Blame view

net/xfrm/xfrm_state.c 51.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * xfrm_state.c
   *
   * Changes:
   *	Mitsuru KANDA @USAGI
   * 	Kazunori MIYAZAWA @USAGI
   * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   * 		IPv6 support
   * 	YOSHIFUJI Hideaki @USAGI
   * 		Split up af-specific functions
   *	Derek Atkins <derek@ihtfp.com>
   *		Add UDP Encapsulation
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
13
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
   */
  
  #include <linux/workqueue.h>
  #include <net/xfrm.h>
  #include <linux/pfkeyv2.h>
  #include <linux/ipsec.h>
  #include <linux/module.h>
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
21
  #include <linux/cache.h>
68277accb   Paul Moore   [XFRM]: Assorted ...
22
  #include <linux/audit.h>
b5890d8ba   Jesper Juhl   [XFRM]: Clean up ...
23
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

44e36b42a   David S. Miller   [XFRM]: Extract c...
25
  #include "xfrm_hash.h"
ee857a7d6   David S. Miller   [XFRM]: Move xfrm...
26
27
  struct sock *xfrm_nl;
  EXPORT_SYMBOL(xfrm_nl);
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
28
  u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
29
  EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
30
  u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
31
  EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
32
  u32 sysctl_xfrm_acq_expires __read_mostly = 30;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  /* Each xfrm_state may be linked to two tables:
  
     1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
a624c108e   David S. Miller   [XFRM]: Put more ...
36
     2. Hash table by (daddr,family,reqid) to find what SAs exist for given
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
44
45
46
47
        destination/tunnel endpoint. (output)
   */
  
  static DEFINE_SPINLOCK(xfrm_state_lock);
  
  /* Hash table to find appropriate SA towards given target (endpoint
   * of tunnel or destination of transport mode) allowed by selector.
   *
   * Main use is finding SA after policy selected tunnel or transport mode.
   * Also, it can be used by ah/esp icmp error handler to find offending SA.
   */
4c563f766   Timo Teras   [XFRM]: Speed up ...
48
  static LIST_HEAD(xfrm_state_all);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
49
50
51
52
53
54
  static struct hlist_head *xfrm_state_bydst __read_mostly;
  static struct hlist_head *xfrm_state_bysrc __read_mostly;
  static struct hlist_head *xfrm_state_byspi __read_mostly;
  static unsigned int xfrm_state_hmask __read_mostly;
  static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
  static unsigned int xfrm_state_num;
9d4a706d8   David S. Miller   [XFRM]: Add gener...
55
  static unsigned int xfrm_state_genid;
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
56

17c2a42a2   Herbert Xu   [IPSEC]: Store af...
57
58
  static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
  static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
59
60
61
62
63
64
  #ifdef CONFIG_AUDITSYSCALL
  static void xfrm_audit_state_replay(struct xfrm_state *x,
  				    struct sk_buff *skb, __be32 net_seq);
  #else
  #define xfrm_audit_state_replay(x, s, sq)	do { ; } while (0)
  #endif /* CONFIG_AUDITSYSCALL */
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
65
66
67
  static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
  					 xfrm_address_t *saddr,
  					 u32 reqid,
a624c108e   David S. Miller   [XFRM]: Put more ...
68
  					 unsigned short family)
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
69
  {
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
70
  	return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
71
  }
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
72
73
  static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
  					 xfrm_address_t *saddr,
44e36b42a   David S. Miller   [XFRM]: Extract c...
74
  					 unsigned short family)
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
75
  {
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
76
  	return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
77
  }
2575b6543   David S. Miller   [XFRM]: Simplify ...
78
  static inline unsigned int
8122adf06   Al Viro   [XFRM]: xfrm_spi_...
79
  xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
80
  {
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
81
  	return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
82
  }
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
83
84
85
86
87
88
89
90
91
92
93
  static void xfrm_hash_transfer(struct hlist_head *list,
  			       struct hlist_head *ndsttable,
  			       struct hlist_head *nsrctable,
  			       struct hlist_head *nspitable,
  			       unsigned int nhashmask)
  {
  	struct hlist_node *entry, *tmp;
  	struct xfrm_state *x;
  
  	hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
  		unsigned int h;
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
94
95
96
  		h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
  				    x->props.reqid, x->props.family,
  				    nhashmask);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
97
  		hlist_add_head(&x->bydst, ndsttable+h);
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
98
99
  		h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
  				    x->props.family,
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
100
101
  				    nhashmask);
  		hlist_add_head(&x->bysrc, nsrctable+h);
7b4dc3600   Masahide NAKAMURA   [XFRM]: Do not ad...
102
103
104
105
106
107
  		if (x->id.spi) {
  			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
  					    x->id.proto, x->props.family,
  					    nhashmask);
  			hlist_add_head(&x->byspi, nspitable+h);
  		}
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
108
109
110
111
112
113
114
115
116
117
  	}
  }
  
  static unsigned long xfrm_hash_new_size(void)
  {
  	return ((xfrm_state_hmask + 1) << 1) *
  		sizeof(struct hlist_head);
  }
  
  static DEFINE_MUTEX(hash_resize_mutex);
c4028958b   David Howells   WorkStruct: make ...
118
  static void xfrm_hash_resize(struct work_struct *__unused)
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
119
120
121
122
123
124
125
126
127
  {
  	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
  	unsigned long nsize, osize;
  	unsigned int nhashmask, ohashmask;
  	int i;
  
  	mutex_lock(&hash_resize_mutex);
  
  	nsize = xfrm_hash_new_size();
44e36b42a   David S. Miller   [XFRM]: Extract c...
128
  	ndst = xfrm_hash_alloc(nsize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
129
130
  	if (!ndst)
  		goto out_unlock;
44e36b42a   David S. Miller   [XFRM]: Extract c...
131
  	nsrc = xfrm_hash_alloc(nsize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
132
  	if (!nsrc) {
44e36b42a   David S. Miller   [XFRM]: Extract c...
133
  		xfrm_hash_free(ndst, nsize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
134
135
  		goto out_unlock;
  	}
44e36b42a   David S. Miller   [XFRM]: Extract c...
136
  	nspi = xfrm_hash_alloc(nsize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
137
  	if (!nspi) {
44e36b42a   David S. Miller   [XFRM]: Extract c...
138
139
  		xfrm_hash_free(ndst, nsize);
  		xfrm_hash_free(nsrc, nsize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  		goto out_unlock;
  	}
  
  	spin_lock_bh(&xfrm_state_lock);
  
  	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
  	for (i = xfrm_state_hmask; i >= 0; i--)
  		xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
  				   nhashmask);
  
  	odst = xfrm_state_bydst;
  	osrc = xfrm_state_bysrc;
  	ospi = xfrm_state_byspi;
  	ohashmask = xfrm_state_hmask;
  
  	xfrm_state_bydst = ndst;
  	xfrm_state_bysrc = nsrc;
  	xfrm_state_byspi = nspi;
  	xfrm_state_hmask = nhashmask;
  
  	spin_unlock_bh(&xfrm_state_lock);
  
  	osize = (ohashmask + 1) * sizeof(struct hlist_head);
44e36b42a   David S. Miller   [XFRM]: Extract c...
163
164
165
  	xfrm_hash_free(odst, osize);
  	xfrm_hash_free(osrc, osize);
  	xfrm_hash_free(ospi, osize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
166
167
168
169
  
  out_unlock:
  	mutex_unlock(&hash_resize_mutex);
  }
c4028958b   David Howells   WorkStruct: make ...
170
  static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
171

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
177
178
  DECLARE_WAIT_QUEUE_HEAD(km_waitq);
  EXPORT_SYMBOL(km_waitq);
  
  static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
  static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
  
  static struct work_struct xfrm_state_gc_work;
8f126e37c   David S. Miller   [XFRM]: Convert x...
179
  static HLIST_HEAD(xfrm_state_gc_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  static DEFINE_SPINLOCK(xfrm_state_gc_lock);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
181
  int __xfrm_state_delete(struct xfrm_state *x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
183
  int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
184
  void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
186
187
188
189
190
191
192
193
194
195
196
197
198
  static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
  {
  	struct xfrm_state_afinfo *afinfo;
  	if (unlikely(family >= NPROTO))
  		return NULL;
  	write_lock_bh(&xfrm_state_afinfo_lock);
  	afinfo = xfrm_state_afinfo[family];
  	if (unlikely(!afinfo))
  		write_unlock_bh(&xfrm_state_afinfo_lock);
  	return afinfo;
  }
  
  static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
9a429c498   Eric Dumazet   [NET]: Add some a...
199
  	__releases(xfrm_state_afinfo_lock)
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
200
201
202
  {
  	write_unlock_bh(&xfrm_state_afinfo_lock);
  }
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
203
  int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
204
205
  {
  	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
206
  	const struct xfrm_type **typemap;
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  	int err = 0;
  
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
  	typemap = afinfo->type_map;
  
  	if (likely(typemap[type->proto] == NULL))
  		typemap[type->proto] = type;
  	else
  		err = -EEXIST;
  	xfrm_state_unlock_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_register_type);
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
221
  int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
222
223
  {
  	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
224
  	const struct xfrm_type **typemap;
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  	int err = 0;
  
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
  	typemap = afinfo->type_map;
  
  	if (unlikely(typemap[type->proto] != type))
  		err = -ENOENT;
  	else
  		typemap[type->proto] = NULL;
  	xfrm_state_unlock_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_unregister_type);
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
239
  static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
240
241
  {
  	struct xfrm_state_afinfo *afinfo;
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
242
243
  	const struct xfrm_type **typemap;
  	const struct xfrm_type *type;
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	int modload_attempted = 0;
  
  retry:
  	afinfo = xfrm_state_get_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return NULL;
  	typemap = afinfo->type_map;
  
  	type = typemap[proto];
  	if (unlikely(type && !try_module_get(type->owner)))
  		type = NULL;
  	if (!type && !modload_attempted) {
  		xfrm_state_put_afinfo(afinfo);
  		request_module("xfrm-type-%d-%d", family, proto);
  		modload_attempted = 1;
  		goto retry;
  	}
  
  	xfrm_state_put_afinfo(afinfo);
  	return type;
  }
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
265
  static void xfrm_put_type(const struct xfrm_type *type)
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  {
  	module_put(type->owner);
  }
  
  int xfrm_register_mode(struct xfrm_mode *mode, int family)
  {
  	struct xfrm_state_afinfo *afinfo;
  	struct xfrm_mode **modemap;
  	int err;
  
  	if (unlikely(mode->encap >= XFRM_MODE_MAX))
  		return -EINVAL;
  
  	afinfo = xfrm_state_lock_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
  
  	err = -EEXIST;
  	modemap = afinfo->mode_map;
17c2a42a2   Herbert Xu   [IPSEC]: Store af...
285
286
  	if (modemap[mode->encap])
  		goto out;
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
287

17c2a42a2   Herbert Xu   [IPSEC]: Store af...
288
289
290
291
292
293
294
295
296
  	err = -ENOENT;
  	if (!try_module_get(afinfo->owner))
  		goto out;
  
  	mode->afinfo = afinfo;
  	modemap[mode->encap] = mode;
  	err = 0;
  
  out:
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  	xfrm_state_unlock_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_register_mode);
  
  int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
  {
  	struct xfrm_state_afinfo *afinfo;
  	struct xfrm_mode **modemap;
  	int err;
  
  	if (unlikely(mode->encap >= XFRM_MODE_MAX))
  		return -EINVAL;
  
  	afinfo = xfrm_state_lock_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
  
  	err = -ENOENT;
  	modemap = afinfo->mode_map;
  	if (likely(modemap[mode->encap] == mode)) {
  		modemap[mode->encap] = NULL;
17c2a42a2   Herbert Xu   [IPSEC]: Store af...
319
  		module_put(mode->afinfo->owner);
aa5d62cc8   Herbert Xu   [IPSEC]: Move typ...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  		err = 0;
  	}
  
  	xfrm_state_unlock_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_unregister_mode);
  
  static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
  {
  	struct xfrm_state_afinfo *afinfo;
  	struct xfrm_mode *mode;
  	int modload_attempted = 0;
  
  	if (unlikely(encap >= XFRM_MODE_MAX))
  		return NULL;
  
  retry:
  	afinfo = xfrm_state_get_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return NULL;
  
  	mode = afinfo->mode_map[encap];
  	if (unlikely(mode && !try_module_get(mode->owner)))
  		mode = NULL;
  	if (!mode && !modload_attempted) {
  		xfrm_state_put_afinfo(afinfo);
  		request_module("xfrm-mode-%d-%d", family, encap);
  		modload_attempted = 1;
  		goto retry;
  	}
  
  	xfrm_state_put_afinfo(afinfo);
  	return mode;
  }
  
  static void xfrm_put_mode(struct xfrm_mode *mode)
  {
  	module_put(mode->owner);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  static void xfrm_state_gc_destroy(struct xfrm_state *x)
  {
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
362
363
  	del_timer_sync(&x->timer);
  	del_timer_sync(&x->rtimer);
a51482bde   Jesper Juhl   [NET]: kfree cleanup
364
365
366
367
  	kfree(x->aalg);
  	kfree(x->ealg);
  	kfree(x->calg);
  	kfree(x->encap);
060f02a3b   Noriaki TAKAMIYA   [XFRM] STATE: Int...
368
  	kfree(x->coaddr);
13996378e   Herbert Xu   [IPSEC]: Rename m...
369
370
  	if (x->inner_mode)
  		xfrm_put_mode(x->inner_mode);
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
371
372
  	if (x->inner_mode_iaf)
  		xfrm_put_mode(x->inner_mode_iaf);
13996378e   Herbert Xu   [IPSEC]: Rename m...
373
374
  	if (x->outer_mode)
  		xfrm_put_mode(x->outer_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
  	if (x->type) {
  		x->type->destructor(x);
  		xfrm_put_type(x->type);
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
379
  	security_xfrm_state_free(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  	kfree(x);
  }
c4028958b   David Howells   WorkStruct: make ...
382
  static void xfrm_state_gc_task(struct work_struct *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  {
  	struct xfrm_state *x;
8f126e37c   David S. Miller   [XFRM]: Convert x...
385
386
  	struct hlist_node *entry, *tmp;
  	struct hlist_head gc_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	spin_lock_bh(&xfrm_state_gc_lock);
8f126e37c   David S. Miller   [XFRM]: Convert x...
389
390
  	gc_list.first = xfrm_state_gc_list.first;
  	INIT_HLIST_HEAD(&xfrm_state_gc_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	spin_unlock_bh(&xfrm_state_gc_lock);
8f126e37c   David S. Miller   [XFRM]: Convert x...
392
  	hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  		xfrm_state_gc_destroy(x);
8f126e37c   David S. Miller   [XFRM]: Convert x...
394

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
  	wake_up(&km_waitq);
  }
  
  static inline unsigned long make_jiffies(long secs)
  {
  	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
  		return MAX_SCHEDULE_TIMEOUT-1;
  	else
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
403
  		return secs*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
408
  }
  
  static void xfrm_timer_handler(unsigned long data)
  {
  	struct xfrm_state *x = (struct xfrm_state*)data;
9d729f72d   James Morris   [NET]: Convert xt...
409
  	unsigned long now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  	long next = LONG_MAX;
  	int warn = 0;
161a09e73   Joy Latten   audit: Add auditi...
412
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  
  	spin_lock(&x->lock);
  	if (x->km.state == XFRM_STATE_DEAD)
  		goto out;
  	if (x->km.state == XFRM_STATE_EXPIRED)
  		goto expired;
  	if (x->lft.hard_add_expires_seconds) {
  		long tmo = x->lft.hard_add_expires_seconds +
  			x->curlft.add_time - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (x->lft.hard_use_expires_seconds) {
  		long tmo = x->lft.hard_use_expires_seconds +
  			(x->curlft.use_time ? : now) - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (x->km.dying)
  		goto resched;
  	if (x->lft.soft_add_expires_seconds) {
  		long tmo = x->lft.soft_add_expires_seconds +
  			x->curlft.add_time - now;
  		if (tmo <= 0)
  			warn = 1;
  		else if (tmo < next)
  			next = tmo;
  	}
  	if (x->lft.soft_use_expires_seconds) {
  		long tmo = x->lft.soft_use_expires_seconds +
  			(x->curlft.use_time ? : now) - now;
  		if (tmo <= 0)
  			warn = 1;
  		else if (tmo < next)
  			next = tmo;
  	}
4666faab0   Herbert Xu   [IPSEC] Kill spur...
453
  	x->km.dying = warn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  	if (warn)
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
455
  		km_state_expired(x, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  resched:
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
457
458
  	if (next != LONG_MAX)
  		mod_timer(&x->timer, jiffies + make_jiffies(next));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
  	goto out;
  
  expired:
  	if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
  		x->km.state = XFRM_STATE_EXPIRED;
  		wake_up(&km_waitq);
  		next = 2;
  		goto resched;
  	}
161a09e73   Joy Latten   audit: Add auditi...
468
469
470
  
  	err = __xfrm_state_delete(x);
  	if (!err && x->id.spi)
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
471
  		km_state_expired(x, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
473
  	xfrm_audit_state_delete(x, err ? 0 : 1,
2532386f4   Eric Paris   Audit: collect se...
474
475
  				audit_get_loginuid(current),
  				audit_get_sessionid(current), 0);
161a09e73   Joy Latten   audit: Add auditi...
476

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  out:
  	spin_unlock(&x->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  }
0ac847524   David S. Miller   [XFRM]: Make sure...
480
  static void xfrm_replay_timer_handler(unsigned long data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
  struct xfrm_state *xfrm_state_alloc(void)
  {
  	struct xfrm_state *x;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
484
  	x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
  
  	if (x) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  		atomic_set(&x->refcnt, 1);
  		atomic_set(&x->tunnel_users, 0);
4c563f766   Timo Teras   [XFRM]: Speed up ...
489
  		INIT_LIST_HEAD(&x->all);
8f126e37c   David S. Miller   [XFRM]: Convert x...
490
491
492
  		INIT_HLIST_NODE(&x->bydst);
  		INIT_HLIST_NODE(&x->bysrc);
  		INIT_HLIST_NODE(&x->byspi);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
493
494
495
  		setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
  		setup_timer(&x->rtimer, xfrm_replay_timer_handler,
  				(unsigned long)x);
9d729f72d   James Morris   [NET]: Convert xt...
496
  		x->curlft.add_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
  		x->lft.soft_byte_limit = XFRM_INF;
  		x->lft.soft_packet_limit = XFRM_INF;
  		x->lft.hard_byte_limit = XFRM_INF;
  		x->lft.hard_packet_limit = XFRM_INF;
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
501
502
  		x->replay_maxage = 0;
  		x->replay_maxdiff = 0;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
503
504
  		x->inner_mode = NULL;
  		x->inner_mode_iaf = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
512
513
  		spin_lock_init(&x->lock);
  	}
  	return x;
  }
  EXPORT_SYMBOL(xfrm_state_alloc);
  
  void __xfrm_state_destroy(struct xfrm_state *x)
  {
  	BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
4c563f766   Timo Teras   [XFRM]: Speed up ...
514
515
516
  	spin_lock_bh(&xfrm_state_lock);
  	list_del(&x->all);
  	spin_unlock_bh(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  	spin_lock_bh(&xfrm_state_gc_lock);
8f126e37c   David S. Miller   [XFRM]: Convert x...
518
  	hlist_add_head(&x->bydst, &xfrm_state_gc_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
  	spin_unlock_bh(&xfrm_state_gc_lock);
  	schedule_work(&xfrm_state_gc_work);
  }
  EXPORT_SYMBOL(__xfrm_state_destroy);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
523
  int __xfrm_state_delete(struct xfrm_state *x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  {
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
525
  	int err = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
  	if (x->km.state != XFRM_STATE_DEAD) {
  		x->km.state = XFRM_STATE_DEAD;
  		spin_lock(&xfrm_state_lock);
8f126e37c   David S. Miller   [XFRM]: Convert x...
529
  		hlist_del(&x->bydst);
8f126e37c   David S. Miller   [XFRM]: Convert x...
530
  		hlist_del(&x->bysrc);
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
531
  		if (x->id.spi)
8f126e37c   David S. Miller   [XFRM]: Convert x...
532
  			hlist_del(&x->byspi);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
533
  		xfrm_state_num--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  		spin_unlock(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
  		/* All xfrm_state objects are created by xfrm_state_alloc.
  		 * The xfrm_state_alloc call gives a reference, and that
  		 * is what we are dropping here.
  		 */
5dba47971   Patrick McHardy   [XFRM]: Fix leak ...
540
  		xfrm_state_put(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
541
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
543
544
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  }
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
546
  EXPORT_SYMBOL(__xfrm_state_delete);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
548
  int xfrm_state_delete(struct xfrm_state *x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  {
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
550
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  	spin_lock_bh(&x->lock);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
552
  	err = __xfrm_state_delete(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	spin_unlock_bh(&x->lock);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
554
555
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  }
  EXPORT_SYMBOL(xfrm_state_delete);
4aa2e62c4   Joy Latten   xfrm: Add securit...
558
559
560
  #ifdef CONFIG_SECURITY_NETWORK_XFRM
  static inline int
  xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  {
4aa2e62c4   Joy Latten   xfrm: Add securit...
562
563
564
565
566
567
568
569
570
  	int i, err = 0;
  
  	for (i = 0; i <= xfrm_state_hmask; i++) {
  		struct hlist_node *entry;
  		struct xfrm_state *x;
  
  		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
  			if (xfrm_id_proto_match(x->id.proto, proto) &&
  			   (err = security_xfrm_state_delete(x)) != 0) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
571
572
  				xfrm_audit_state_delete(x, 0,
  							audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
573
  							audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
574
  							audit_info->secid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  				return err;
  			}
  		}
  	}
  
  	return err;
  }
  #else
  static inline int
  xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
  {
  	return 0;
  }
  #endif
  
  int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
  {
  	int i, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
  
  	spin_lock_bh(&xfrm_state_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
595
596
597
  	err = xfrm_state_flush_secctx_check(proto, audit_info);
  	if (err)
  		goto out;
a9917c066   Masahide NAKAMURA   [XFRM] STATE: Fix...
598
  	for (i = 0; i <= xfrm_state_hmask; i++) {
8f126e37c   David S. Miller   [XFRM]: Convert x...
599
600
  		struct hlist_node *entry;
  		struct xfrm_state *x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  restart:
8f126e37c   David S. Miller   [XFRM]: Convert x...
602
  		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  			if (!xfrm_state_kern(x) &&
5794708f1   Masahide NAKAMURA   [XFRM]: Introduce...
604
  			    xfrm_id_proto_match(x->id.proto, proto)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  				xfrm_state_hold(x);
  				spin_unlock_bh(&xfrm_state_lock);
161a09e73   Joy Latten   audit: Add auditi...
607
  				err = xfrm_state_delete(x);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
608
609
  				xfrm_audit_state_delete(x, err ? 0 : 1,
  							audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
610
  							audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
611
  							audit_info->secid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
617
618
  				xfrm_state_put(x);
  
  				spin_lock_bh(&xfrm_state_lock);
  				goto restart;
  			}
  		}
  	}
4aa2e62c4   Joy Latten   xfrm: Add securit...
619
620
621
  	err = 0;
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
  	spin_unlock_bh(&xfrm_state_lock);
  	wake_up(&km_waitq);
4aa2e62c4   Joy Latten   xfrm: Add securit...
624
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
  }
  EXPORT_SYMBOL(xfrm_state_flush);
af11e3160   Jamal Hadi Salim   [XFRM] SAD info T...
627
  void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
628
629
630
631
632
633
634
635
  {
  	spin_lock_bh(&xfrm_state_lock);
  	si->sadcnt = xfrm_state_num;
  	si->sadhcnt = xfrm_state_hmask;
  	si->sadhmcnt = xfrm_state_hashmax;
  	spin_unlock_bh(&xfrm_state_lock);
  }
  EXPORT_SYMBOL(xfrm_sad_getinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
640
641
642
643
644
645
646
647
648
  static int
  xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
  		  struct xfrm_tmpl *tmpl,
  		  xfrm_address_t *daddr, xfrm_address_t *saddr,
  		  unsigned short family)
  {
  	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
  	if (!afinfo)
  		return -1;
  	afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
  	xfrm_state_put_afinfo(afinfo);
  	return 0;
  }
a94cfd197   Al Viro   [XFRM]: xfrm_stat...
649
  static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
650
651
652
  {
  	unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
  	struct xfrm_state *x;
8f126e37c   David S. Miller   [XFRM]: Convert x...
653
  	struct hlist_node *entry;
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
654

8f126e37c   David S. Miller   [XFRM]: Convert x...
655
  	hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  		if (x->props.family != family ||
  		    x->id.spi       != spi ||
  		    x->id.proto     != proto)
  			continue;
  
  		switch (family) {
  		case AF_INET:
  			if (x->id.daddr.a4 != daddr->a4)
  				continue;
  			break;
  		case AF_INET6:
  			if (!ipv6_addr_equal((struct in6_addr *)daddr,
  					     (struct in6_addr *)
  					     x->id.daddr.a6))
  				continue;
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
672
  		}
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
673
674
675
676
677
678
679
680
681
682
  
  		xfrm_state_hold(x);
  		return x;
  	}
  
  	return NULL;
  }
  
  static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
  {
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
683
  	unsigned int h = xfrm_src_hash(daddr, saddr, family);
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
684
  	struct xfrm_state *x;
8f126e37c   David S. Miller   [XFRM]: Convert x...
685
  	struct hlist_node *entry;
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
686

8f126e37c   David S. Miller   [XFRM]: Convert x...
687
  	hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
  		if (x->props.family != family ||
  		    x->id.proto     != proto)
  			continue;
  
  		switch (family) {
  		case AF_INET:
  			if (x->id.daddr.a4 != daddr->a4 ||
  			    x->props.saddr.a4 != saddr->a4)
  				continue;
  			break;
  		case AF_INET6:
  			if (!ipv6_addr_equal((struct in6_addr *)daddr,
  					     (struct in6_addr *)
  					     x->id.daddr.a6) ||
  			    !ipv6_addr_equal((struct in6_addr *)saddr,
  					     (struct in6_addr *)
  					     x->props.saddr.a6))
  				continue;
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
707
  		}
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  
  		xfrm_state_hold(x);
  		return x;
  	}
  
  	return NULL;
  }
  
  static inline struct xfrm_state *
  __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
  {
  	if (use_spi)
  		return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
  					   x->id.proto, family);
  	else
  		return __xfrm_state_lookup_byaddr(&x->id.daddr,
  						  &x->props.saddr,
  						  x->id.proto, family);
  }
2fab22f2d   Patrick McHardy   [XFRM]: Fix xfrm_...
727
728
729
730
731
732
733
  static void xfrm_hash_grow_check(int have_hash_collision)
  {
  	if (have_hash_collision &&
  	    (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
  	    xfrm_state_num > xfrm_state_hmask)
  		schedule_work(&xfrm_hash_work);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  struct xfrm_state *
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
735
  xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
  		struct flowi *fl, struct xfrm_tmpl *tmpl,
  		struct xfrm_policy *pol, int *err,
  		unsigned short family)
  {
4bda4f250   Pavel Emelyanov   [XFRM]: Fix poten...
740
  	unsigned int h;
8f126e37c   David S. Miller   [XFRM]: Convert x...
741
  	struct hlist_node *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
  	struct xfrm_state *x, *x0;
  	int acquire_in_progress = 0;
  	int error = 0;
  	struct xfrm_state *best = NULL;
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
746

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	spin_lock_bh(&xfrm_state_lock);
4bda4f250   Pavel Emelyanov   [XFRM]: Fix poten...
748
  	h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
749
  	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  		if (x->props.family == family &&
  		    x->props.reqid == tmpl->reqid &&
fbd9a5b47   Masahide NAKAMURA   [XFRM] STATE: Com...
752
  		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  		    xfrm_state_addr_check(x, daddr, saddr, family) &&
  		    tmpl->mode == x->props.mode &&
  		    tmpl->id.proto == x->id.proto &&
  		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
  			/* Resolution logic:
  			   1. There is a valid state with matching selector.
  			      Done.
  			   2. Valid state with inappropriate selector. Skip.
  
  			   Entering area of "sysdeps".
  
  			   3. If state is not valid, selector is temporary,
  			      it selects only session which triggered
  			      previous resolution. Key manager will do
  			      something to install a state with proper
  			      selector.
  			 */
  			if (x->km.state == XFRM_STATE_VALID) {
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
771
  				if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
772
  				    !security_xfrm_state_pol_flow_match(x, pol, fl))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
778
779
780
781
782
  					continue;
  				if (!best ||
  				    best->km.dying > x->km.dying ||
  				    (best->km.dying == x->km.dying &&
  				     best->curlft.add_time < x->curlft.add_time))
  					best = x;
  			} else if (x->km.state == XFRM_STATE_ACQ) {
  				acquire_in_progress = 1;
  			} else if (x->km.state == XFRM_STATE_ERROR ||
  				   x->km.state == XFRM_STATE_EXPIRED) {
48b8d7831   Joakim Koskela   [XFRM]: State sel...
783
  				if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
784
  				    security_xfrm_state_pol_flow_match(x, pol, fl))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
791
  					error = -ESRCH;
  			}
  		}
  	}
  
  	x = best;
  	if (!x && !error && !acquire_in_progress) {
5c5d281a9   Patrick McHardy   [XFRM]: Fix exist...
792
  		if (tmpl->id.spi &&
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
793
794
  		    (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
  					      tmpl->id.proto, family)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
802
803
804
805
806
  			xfrm_state_put(x0);
  			error = -EEXIST;
  			goto out;
  		}
  		x = xfrm_state_alloc();
  		if (x == NULL) {
  			error = -ENOMEM;
  			goto out;
  		}
  		/* Initialize temporary selector matching only
  		 * to current session. */
  		xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
807
808
809
810
811
812
813
  		error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
  		if (error) {
  			x->km.state = XFRM_STATE_DEAD;
  			xfrm_state_put(x);
  			x = NULL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  		if (km_query(x, tmpl, pol) == 0) {
  			x->km.state = XFRM_STATE_ACQ;
8f126e37c   David S. Miller   [XFRM]: Convert x...
816
  			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
817
  			h = xfrm_src_hash(daddr, saddr, family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
818
  			hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  			if (x->id.spi) {
  				h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
821
  				hlist_add_head(&x->byspi, xfrm_state_byspi+h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  			}
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
823
824
  			x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
  			x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  			add_timer(&x->timer);
2fab22f2d   Patrick McHardy   [XFRM]: Fix xfrm_...
826
827
  			xfrm_state_num++;
  			xfrm_hash_grow_check(x->bydst.next != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
831
832
833
834
835
836
837
838
839
840
  		} else {
  			x->km.state = XFRM_STATE_DEAD;
  			xfrm_state_put(x);
  			x = NULL;
  			error = -ESRCH;
  		}
  	}
  out:
  	if (x)
  		xfrm_state_hold(x);
  	else
  		*err = acquire_in_progress ? -EAGAIN : error;
  	spin_unlock_bh(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  	return x;
  }
628529b6e   Jamal Hadi Salim   [XFRM] Introduce ...
843
844
845
846
  struct xfrm_state *
  xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
  		    unsigned short family, u8 mode, u8 proto, u32 reqid)
  {
4bda4f250   Pavel Emelyanov   [XFRM]: Fix poten...
847
  	unsigned int h;
628529b6e   Jamal Hadi Salim   [XFRM] Introduce ...
848
849
850
851
  	struct xfrm_state *rx = NULL, *x = NULL;
  	struct hlist_node *entry;
  
  	spin_lock(&xfrm_state_lock);
4bda4f250   Pavel Emelyanov   [XFRM]: Fix poten...
852
  	h = xfrm_dst_hash(daddr, saddr, reqid, family);
628529b6e   Jamal Hadi Salim   [XFRM] Introduce ...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
  		if (x->props.family == family &&
  		    x->props.reqid == reqid &&
  		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
  		    xfrm_state_addr_check(x, daddr, saddr, family) &&
  		    mode == x->props.mode &&
  		    proto == x->id.proto &&
  		    x->km.state == XFRM_STATE_VALID) {
  			rx = x;
  			break;
  		}
  	}
  
  	if (rx)
  		xfrm_state_hold(rx);
  	spin_unlock(&xfrm_state_lock);
  
  
  	return rx;
  }
  EXPORT_SYMBOL(xfrm_stateonly_find);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  static void __xfrm_state_insert(struct xfrm_state *x)
  {
a624c108e   David S. Miller   [XFRM]: Put more ...
876
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877

9d4a706d8   David S. Miller   [XFRM]: Add gener...
878
  	x->genid = ++xfrm_state_genid;
4c563f766   Timo Teras   [XFRM]: Speed up ...
879
  	list_add_tail(&x->all, &xfrm_state_all);
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
880
881
  	h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
  			  x->props.reqid, x->props.family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
882
  	hlist_add_head(&x->bydst, xfrm_state_bydst+h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883

667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
884
  	h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
885
  	hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886

7b4dc3600   Masahide NAKAMURA   [XFRM]: Do not ad...
887
  	if (x->id.spi) {
6c44e6b7a   Masahide NAKAMURA   [XFRM] STATE: Add...
888
889
  		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
  				  x->props.family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
890
  		hlist_add_head(&x->byspi, xfrm_state_byspi+h);
6c44e6b7a   Masahide NAKAMURA   [XFRM] STATE: Add...
891
  	}
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
892
893
894
  	mod_timer(&x->timer, jiffies + HZ);
  	if (x->replay_maxage)
  		mod_timer(&x->rtimer, jiffies + x->replay_maxage);
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
895

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  	wake_up(&km_waitq);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
897
898
  
  	xfrm_state_num++;
918049f01   David S. Miller   [XFRM]: Fix xfrm_...
899
  	xfrm_hash_grow_check(x->bydst.next != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
  }
c7f5ea3a4   David S. Miller   [XFRM]: Do not fl...
901
902
903
904
905
906
907
908
  /* xfrm_state_lock is held */
  static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
  {
  	unsigned short family = xnew->props.family;
  	u32 reqid = xnew->props.reqid;
  	struct xfrm_state *x;
  	struct hlist_node *entry;
  	unsigned int h;
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
909
  	h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
c7f5ea3a4   David S. Miller   [XFRM]: Do not fl...
910
911
912
  	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
  		if (x->props.family	== family &&
  		    x->props.reqid	== reqid &&
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
913
914
  		    !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
  		    !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
c7f5ea3a4   David S. Miller   [XFRM]: Do not fl...
915
916
917
  			x->genid = xfrm_state_genid;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
  void xfrm_state_insert(struct xfrm_state *x)
  {
  	spin_lock_bh(&xfrm_state_lock);
c7f5ea3a4   David S. Miller   [XFRM]: Do not fl...
921
  	__xfrm_state_bump_genids(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
925
  	__xfrm_state_insert(x);
  	spin_unlock_bh(&xfrm_state_lock);
  }
  EXPORT_SYMBOL(xfrm_state_insert);
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
926
927
928
  /* xfrm_state_lock is held */
  static 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)
  {
c1969f294   David S. Miller   [XFRM]: Hash xfrm...
929
  	unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
930
  	struct hlist_node *entry;
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
931
  	struct xfrm_state *x;
8f126e37c   David S. Miller   [XFRM]: Convert x...
932
  	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
933
934
935
936
  		if (x->props.reqid  != reqid ||
  		    x->props.mode   != mode ||
  		    x->props.family != family ||
  		    x->km.state     != XFRM_STATE_ACQ ||
75e252d98   Joy Latten   [XFRM]: Fix missi...
937
938
  		    x->id.spi       != 0 ||
  		    x->id.proto	    != proto)
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
  			continue;
  
  		switch (family) {
  		case AF_INET:
  			if (x->id.daddr.a4    != daddr->a4 ||
  			    x->props.saddr.a4 != saddr->a4)
  				continue;
  			break;
  		case AF_INET6:
  			if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
  					     (struct in6_addr *)daddr) ||
  			    !ipv6_addr_equal((struct in6_addr *)
  					     x->props.saddr.a6,
  					     (struct in6_addr *)saddr))
  				continue;
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
955
  		}
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
  
  		xfrm_state_hold(x);
  		return x;
  	}
  
  	if (!create)
  		return NULL;
  
  	x = xfrm_state_alloc();
  	if (likely(x)) {
  		switch (family) {
  		case AF_INET:
  			x->sel.daddr.a4 = daddr->a4;
  			x->sel.saddr.a4 = saddr->a4;
  			x->sel.prefixlen_d = 32;
  			x->sel.prefixlen_s = 32;
  			x->props.saddr.a4 = saddr->a4;
  			x->id.daddr.a4 = daddr->a4;
  			break;
  
  		case AF_INET6:
  			ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
  				       (struct in6_addr *)daddr);
  			ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
  				       (struct in6_addr *)saddr);
  			x->sel.prefixlen_d = 128;
  			x->sel.prefixlen_s = 128;
  			ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
  				       (struct in6_addr *)saddr);
  			ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
  				       (struct in6_addr *)daddr);
  			break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
988
  		}
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
989
990
991
992
993
994
  
  		x->km.state = XFRM_STATE_ACQ;
  		x->id.proto = proto;
  		x->props.family = family;
  		x->props.mode = mode;
  		x->props.reqid = reqid;
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
995
  		x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
996
  		xfrm_state_hold(x);
01e67d08f   David S. Miller   [XFRM]: Allow XFR...
997
  		x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
998
  		add_timer(&x->timer);
8f126e37c   David S. Miller   [XFRM]: Convert x...
999
  		hlist_add_head(&x->bydst, xfrm_state_bydst+h);
667bbcb6c   Masahide NAKAMURA   [XFRM] STATE: Use...
1000
  		h = xfrm_src_hash(daddr, saddr, family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
1001
  		hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
918049f01   David S. Miller   [XFRM]: Fix xfrm_...
1002
1003
1004
1005
  
  		xfrm_state_num++;
  
  		xfrm_hash_grow_check(x->bydst.next != NULL);
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
1006
1007
1008
1009
  	}
  
  	return x;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
  static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
  
  int xfrm_state_add(struct xfrm_state *x)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
  	struct xfrm_state *x1;
  	int family;
  	int err;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1017
  	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
  
  	family = x->props.family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  
  	spin_lock_bh(&xfrm_state_lock);
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1022
  	x1 = __xfrm_state_locate(x, use_spi, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
1027
1028
  	if (x1) {
  		xfrm_state_put(x1);
  		x1 = NULL;
  		err = -EEXIST;
  		goto out;
  	}
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1029
  	if (use_spi && x->km.seq) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  		x1 = __xfrm_find_acq_byseq(x->km.seq);
75e252d98   Joy Latten   [XFRM]: Fix missi...
1031
1032
  		if (x1 && ((x1->id.proto != x->id.proto) ||
  		    xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  			xfrm_state_put(x1);
  			x1 = NULL;
  		}
  	}
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1037
  	if (use_spi && !x1)
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
1038
1039
1040
  		x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
  				     x->id.proto,
  				     &x->id.daddr, &x->props.saddr, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041

c7f5ea3a4   David S. Miller   [XFRM]: Do not fl...
1042
  	__xfrm_state_bump_genids(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
1046
1047
  	__xfrm_state_insert(x);
  	err = 0;
  
  out:
  	spin_unlock_bh(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
1052
1053
1054
1055
1056
  
  	if (x1) {
  		xfrm_state_delete(x1);
  		xfrm_state_put(x1);
  	}
  
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_add);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1057
  #ifdef CONFIG_XFRM_MIGRATE
6666351df   Eric Dumazet   [XFRM]: xfrm_stat...
1058
  static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
  {
  	int err = -ENOMEM;
  	struct xfrm_state *x = xfrm_state_alloc();
  	if (!x)
  		goto error;
  
  	memcpy(&x->id, &orig->id, sizeof(x->id));
  	memcpy(&x->sel, &orig->sel, sizeof(x->sel));
  	memcpy(&x->lft, &orig->lft, sizeof(x->lft));
  	x->props.mode = orig->props.mode;
  	x->props.replay_window = orig->props.replay_window;
  	x->props.reqid = orig->props.reqid;
  	x->props.family = orig->props.family;
  	x->props.saddr = orig->props.saddr;
  
  	if (orig->aalg) {
  		x->aalg = xfrm_algo_clone(orig->aalg);
  		if (!x->aalg)
  			goto error;
  	}
  	x->props.aalgo = orig->props.aalgo;
  
  	if (orig->ealg) {
  		x->ealg = xfrm_algo_clone(orig->ealg);
  		if (!x->ealg)
  			goto error;
  	}
  	x->props.ealgo = orig->props.ealgo;
  
  	if (orig->calg) {
  		x->calg = xfrm_algo_clone(orig->calg);
  		if (!x->calg)
  			goto error;
  	}
  	x->props.calgo = orig->props.calgo;
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1094
  	if (orig->encap) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  		x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
  		if (!x->encap)
  			goto error;
  	}
  
  	if (orig->coaddr) {
  		x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
  				    GFP_KERNEL);
  		if (!x->coaddr)
  			goto error;
  	}
  
  	err = xfrm_init_state(x);
  	if (err)
  		goto error;
  
  	x->props.flags = orig->props.flags;
  
  	x->curlft.add_time = orig->curlft.add_time;
  	x->km.state = orig->km.state;
  	x->km.seq = orig->km.seq;
  
  	return x;
  
   error:
  	if (errp)
  		*errp = err;
  	if (x) {
  		kfree(x->aalg);
  		kfree(x->ealg);
  		kfree(x->calg);
  		kfree(x->encap);
  		kfree(x->coaddr);
  	}
  	kfree(x);
  	return NULL;
  }
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  
  /* xfrm_state_lock is held */
  struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
  {
  	unsigned int h;
  	struct xfrm_state *x;
  	struct hlist_node *entry;
  
  	if (m->reqid) {
  		h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
  				  m->reqid, m->old_family);
  		hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
  			if (x->props.mode != m->mode ||
  			    x->id.proto != m->proto)
  				continue;
  			if (m->reqid && x->props.reqid != m->reqid)
  				continue;
  			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
  					  m->old_family) ||
  			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
  					  m->old_family))
  				continue;
  			xfrm_state_hold(x);
  			return x;
  		}
  	} else {
  		h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
  				  m->old_family);
  		hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
  			if (x->props.mode != m->mode ||
  			    x->id.proto != m->proto)
  				continue;
  			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
  					  m->old_family) ||
  			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
  					  m->old_family))
  				continue;
  			xfrm_state_hold(x);
  			return x;
  		}
  	}
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1173
  	return NULL;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  }
  EXPORT_SYMBOL(xfrm_migrate_state_find);
  
  struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
  				       struct xfrm_migrate *m)
  {
  	struct xfrm_state *xc;
  	int err;
  
  	xc = xfrm_state_clone(x, &err);
  	if (!xc)
  		return NULL;
  
  	memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
  	memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
  
  	/* add state */
  	if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
  		/* a care is needed when the destination address of the
  		   state is to be updated as it is a part of triplet */
  		xfrm_state_insert(xc);
  	} else {
  		if ((err = xfrm_state_add(xc)) < 0)
  			goto error;
  	}
  
  	return xc;
  error:
  	kfree(xc);
  	return NULL;
  }
  EXPORT_SYMBOL(xfrm_state_migrate);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
  int xfrm_state_update(struct xfrm_state *x)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
  	struct xfrm_state *x1;
  	int err;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1211
  	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  	spin_lock_bh(&xfrm_state_lock);
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1214
  	x1 = __xfrm_state_locate(x, use_spi, x->props.family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
  
  	err = -ESRCH;
  	if (!x1)
  		goto out;
  
  	if (xfrm_state_kern(x1)) {
  		xfrm_state_put(x1);
  		err = -EEXIST;
  		goto out;
  	}
  
  	if (x1->km.state == XFRM_STATE_ACQ) {
  		__xfrm_state_insert(x);
  		x = NULL;
  	}
  	err = 0;
  
  out:
  	spin_unlock_bh(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
  
  	if (err)
  		return err;
  
  	if (!x) {
  		xfrm_state_delete(x1);
  		xfrm_state_put(x1);
  		return 0;
  	}
  
  	err = -EINVAL;
  	spin_lock_bh(&x1->lock);
  	if (likely(x1->km.state == XFRM_STATE_VALID)) {
  		if (x->encap && x1->encap)
  			memcpy(x1->encap, x->encap, sizeof(*x1->encap));
060f02a3b   Noriaki TAKAMIYA   [XFRM] STATE: Int...
1249
1250
1251
1252
1253
  		if (x->coaddr && x1->coaddr) {
  			memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
  		}
  		if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
  			memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
  		memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
  		x1->km.dying = 0;
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
1256
  		mod_timer(&x1->timer, jiffies + HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
  		if (x1->curlft.use_time)
  			xfrm_state_check_expire(x1);
  
  		err = 0;
  	}
  	spin_unlock_bh(&x1->lock);
  
  	xfrm_state_put(x1);
  
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_update);
  
  int xfrm_state_check_expire(struct xfrm_state *x)
  {
  	if (!x->curlft.use_time)
9d729f72d   James Morris   [NET]: Convert xt...
1273
  		x->curlft.use_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
1276
1277
1278
1279
  
  	if (x->km.state != XFRM_STATE_VALID)
  		return -EINVAL;
  
  	if (x->curlft.bytes >= x->lft.hard_byte_limit ||
  	    x->curlft.packets >= x->lft.hard_packet_limit) {
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1280
  		x->km.state = XFRM_STATE_EXPIRED;
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
1281
  		mod_timer(&x->timer, jiffies);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
1284
1285
1286
  		return -EINVAL;
  	}
  
  	if (!x->km.dying &&
  	    (x->curlft.bytes >= x->lft.soft_byte_limit ||
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1287
1288
  	     x->curlft.packets >= x->lft.soft_packet_limit)) {
  		x->km.dying = 1;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1289
  		km_state_expired(x, 0, 0);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1290
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
1293
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_state_check_expire);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  struct xfrm_state *
a94cfd197   Al Viro   [XFRM]: xfrm_stat...
1295
  xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
1297
1298
  		  unsigned short family)
  {
  	struct xfrm_state *x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
  
  	spin_lock_bh(&xfrm_state_lock);
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1301
  	x = __xfrm_state_lookup(daddr, spi, proto, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
  	spin_unlock_bh(&xfrm_state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
1307
  	return x;
  }
  EXPORT_SYMBOL(xfrm_state_lookup);
  
  struct xfrm_state *
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1308
1309
1310
1311
  xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
  			 u8 proto, unsigned short family)
  {
  	struct xfrm_state *x;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1312
1313
  
  	spin_lock_bh(&xfrm_state_lock);
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1314
  	x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1315
  	spin_unlock_bh(&xfrm_state_lock);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
1316
1317
1318
1319
1320
  	return x;
  }
  EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
  
  struct xfrm_state *
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1321
1322
  xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
  	      xfrm_address_t *daddr, xfrm_address_t *saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
  	      int create, unsigned short family)
  {
  	struct xfrm_state *x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
  
  	spin_lock_bh(&xfrm_state_lock);
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
1328
  	x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
  	spin_unlock_bh(&xfrm_state_lock);
2770834c9   David S. Miller   [XFRM]: Pull xfrm...
1330

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
1332
1333
  	return x;
  }
  EXPORT_SYMBOL(xfrm_find_acq);
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
  #ifdef CONFIG_XFRM_SUB_POLICY
  int
  xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
  	       unsigned short family)
  {
  	int err = 0;
  	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
  	if (!afinfo)
  		return -EAFNOSUPPORT;
  
  	spin_lock_bh(&xfrm_state_lock);
  	if (afinfo->tmpl_sort)
  		err = afinfo->tmpl_sort(dst, src, n);
  	spin_unlock_bh(&xfrm_state_lock);
  	xfrm_state_put_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_tmpl_sort);
  
  int
  xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
  		unsigned short family)
  {
  	int err = 0;
  	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
  	if (!afinfo)
  		return -EAFNOSUPPORT;
  
  	spin_lock_bh(&xfrm_state_lock);
  	if (afinfo->state_sort)
  		err = afinfo->state_sort(dst, src, n);
  	spin_unlock_bh(&xfrm_state_lock);
  	xfrm_state_put_afinfo(afinfo);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_sort);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
  /* Silly enough, but I'm lazy to build resolution list */
  
  static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
  {
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376

f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
1377
  	for (i = 0; i <= xfrm_state_hmask; i++) {
8f126e37c   David S. Miller   [XFRM]: Convert x...
1378
1379
1380
1381
1382
1383
  		struct hlist_node *entry;
  		struct xfrm_state *x;
  
  		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
  			if (x->km.seq == seq &&
  			    x->km.state == XFRM_STATE_ACQ) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
  				xfrm_state_hold(x);
  				return x;
  			}
  		}
  	}
  	return NULL;
  }
  
  struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
  {
  	struct xfrm_state *x;
  
  	spin_lock_bh(&xfrm_state_lock);
  	x = __xfrm_find_acq_byseq(seq);
  	spin_unlock_bh(&xfrm_state_lock);
  	return x;
  }
  EXPORT_SYMBOL(xfrm_find_acq_byseq);
  
  u32 xfrm_get_acqseq(void)
  {
  	u32 res;
  	static u32 acqseq;
  	static DEFINE_SPINLOCK(acqseq_lock);
  
  	spin_lock_bh(&acqseq_lock);
  	res = (++acqseq ? : ++acqseq);
  	spin_unlock_bh(&acqseq_lock);
  	return res;
  }
  EXPORT_SYMBOL(xfrm_get_acqseq);
658b219e9   Herbert Xu   [IPSEC]: Move com...
1415
  int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
  {
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
1417
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
  	struct xfrm_state *x0;
658b219e9   Herbert Xu   [IPSEC]: Move com...
1419
1420
1421
  	int err = -ENOENT;
  	__be32 minspi = htonl(low);
  	__be32 maxspi = htonl(high);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422

658b219e9   Herbert Xu   [IPSEC]: Move com...
1423
1424
1425
1426
1427
  	spin_lock_bh(&x->lock);
  	if (x->km.state == XFRM_STATE_DEAD)
  		goto unlock;
  
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
  	if (x->id.spi)
658b219e9   Herbert Xu   [IPSEC]: Move com...
1429
1430
1431
  		goto unlock;
  
  	err = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
1434
1435
1436
  
  	if (minspi == maxspi) {
  		x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
  		if (x0) {
  			xfrm_state_put(x0);
658b219e9   Herbert Xu   [IPSEC]: Move com...
1437
  			goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
1439
1440
1441
  		}
  		x->id.spi = minspi;
  	} else {
  		u32 spi = 0;
26977b4ed   Al Viro   [XFRM]: xfrm_allo...
1442
1443
  		for (h=0; h<high-low+1; h++) {
  			spi = low + net_random()%(high-low+1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
  			x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
  			if (x0 == NULL) {
  				x->id.spi = htonl(spi);
  				break;
  			}
  			xfrm_state_put(x0);
  		}
  	}
  	if (x->id.spi) {
  		spin_lock_bh(&xfrm_state_lock);
  		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
8f126e37c   David S. Miller   [XFRM]: Convert x...
1455
  		hlist_add_head(&x->byspi, xfrm_state_byspi+h);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
  		spin_unlock_bh(&xfrm_state_lock);
658b219e9   Herbert Xu   [IPSEC]: Move com...
1457
1458
  
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459
  	}
658b219e9   Herbert Xu   [IPSEC]: Move com...
1460
1461
1462
1463
1464
  
  unlock:
  	spin_unlock_bh(&x->lock);
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
  }
  EXPORT_SYMBOL(xfrm_alloc_spi);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1467
1468
  int xfrm_state_walk(struct xfrm_state_walk *walk,
  		    int (*func)(struct xfrm_state *, int, void*),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
  		    void *data)
  {
4c563f766   Timo Teras   [XFRM]: Speed up ...
1471
  	struct xfrm_state *old, *x, *last = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
  	int err = 0;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1473
1474
1475
1476
1477
  	if (walk->state == NULL && walk->count != 0)
  		return 0;
  
  	old = x = walk->state;
  	walk->state = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
  	spin_lock_bh(&xfrm_state_lock);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
  	if (x == NULL)
  		x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
  	list_for_each_entry_from(x, &xfrm_state_all, all) {
  		if (x->km.state == XFRM_STATE_DEAD)
  			continue;
  		if (!xfrm_id_proto_match(x->id.proto, walk->proto))
  			continue;
  		if (last) {
  			err = func(last, walk->count, data);
  			if (err) {
  				xfrm_state_hold(last);
  				walk->state = last;
  				goto out;
94b9bb548   Jamal Hadi Salim   [XFRM] Optimize S...
1492
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
  		}
4c563f766   Timo Teras   [XFRM]: Speed up ...
1494
1495
  		last = x;
  		walk->count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
  	}
4c563f766   Timo Teras   [XFRM]: Speed up ...
1497
  	if (walk->count == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
1499
1500
  		err = -ENOENT;
  		goto out;
  	}
4c563f766   Timo Teras   [XFRM]: Speed up ...
1501
1502
  	if (last)
  		err = func(last, 0, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
  out:
  	spin_unlock_bh(&xfrm_state_lock);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1505
1506
  	if (old != NULL)
  		xfrm_state_put(old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
1508
1509
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_walk);
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  
  void xfrm_replay_notify(struct xfrm_state *x, int event)
  {
  	struct km_event c;
  	/* we send notify messages in case
  	 *  1. we updated on of the sequence numbers, and the seqno difference
  	 *     is at least x->replay_maxdiff, in this case we also update the
  	 *     timeout of our timer function
  	 *  2. if x->replay_maxage has elapsed since last update,
  	 *     and there were changes
  	 *
  	 *  The state structure must be locked!
  	 */
  
  	switch (event) {
  	case XFRM_REPLAY_UPDATE:
  		if (x->replay_maxdiff &&
  		    (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
2717096ab   Jamal Hadi Salim   [XFRM]: Fix aeven...
1528
1529
1530
1531
1532
1533
  		    (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
  			if (x->xflags & XFRM_TIME_DEFER)
  				event = XFRM_REPLAY_TIMEOUT;
  			else
  				return;
  		}
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1534
1535
1536
1537
1538
1539
  
  		break;
  
  	case XFRM_REPLAY_TIMEOUT:
  		if ((x->replay.seq == x->preplay.seq) &&
  		    (x->replay.bitmap == x->preplay.bitmap) &&
2717096ab   Jamal Hadi Salim   [XFRM]: Fix aeven...
1540
1541
  		    (x->replay.oseq == x->preplay.oseq)) {
  			x->xflags |= XFRM_TIME_DEFER;
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1542
  			return;
2717096ab   Jamal Hadi Salim   [XFRM]: Fix aeven...
1543
  		}
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1544
1545
1546
1547
1548
1549
1550
1551
  
  		break;
  	}
  
  	memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
  	c.event = XFRM_MSG_NEWAE;
  	c.data.aevent = event;
  	km_state_notify(x, &c);
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1552
  	if (x->replay_maxage &&
a47f0ce05   David S. Miller   [XFRM]: Kill exce...
1553
  	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
2717096ab   Jamal Hadi Salim   [XFRM]: Fix aeven...
1554
  		x->xflags &= ~XFRM_TIME_DEFER;
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1555
1556
1557
1558
1559
1560
1561
  }
  
  static void xfrm_replay_timer_handler(unsigned long data)
  {
  	struct xfrm_state *x = (struct xfrm_state*)data;
  
  	spin_lock(&x->lock);
2717096ab   Jamal Hadi Salim   [XFRM]: Fix aeven...
1562
1563
1564
1565
1566
1567
  	if (x->km.state == XFRM_STATE_VALID) {
  		if (xfrm_aevent_is_on())
  			xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
  		else
  			x->xflags |= XFRM_TIME_DEFER;
  	}
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1568
1569
1570
  
  	spin_unlock(&x->lock);
  }
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
1571
1572
  int xfrm_replay_check(struct xfrm_state *x,
  		      struct sk_buff *skb, __be32 net_seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
1574
  {
  	u32 diff;
a252cc237   Al Viro   [XFRM]: xrfm_repl...
1575
  	u32 seq = ntohl(net_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
  
  	if (unlikely(seq == 0))
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
1578
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
1580
1581
1582
1583
  
  	if (likely(seq > x->replay.seq))
  		return 0;
  
  	diff = x->replay.seq - seq;
4c4d51a73   Herbert Xu   [IPSEC]: Reject p...
1584
1585
  	if (diff >= min_t(unsigned int, x->props.replay_window,
  			  sizeof(x->replay.bitmap) * 8)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  		x->stats.replay_window++;
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
1587
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
1589
1590
1591
  	}
  
  	if (x->replay.bitmap & (1U << diff)) {
  		x->stats.replay++;
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
1592
  		goto err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
1594
  	}
  	return 0;
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
1595
1596
1597
1598
  
  err:
  	xfrm_audit_state_replay(x, skb, net_seq);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600

61f4627b2   Al Viro   [XFRM]: xfrm_repl...
1601
  void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
1603
  {
  	u32 diff;
61f4627b2   Al Viro   [XFRM]: xfrm_repl...
1604
  	u32 seq = ntohl(net_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
  
  	if (seq > x->replay.seq) {
  		diff = seq - x->replay.seq;
  		if (diff < x->props.replay_window)
  			x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
  		else
  			x->replay.bitmap = 1;
  		x->replay.seq = seq;
  	} else {
  		diff = x->replay.seq - seq;
  		x->replay.bitmap |= (1U << diff);
  	}
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
1617
1618
1619
  
  	if (xfrm_aevent_is_on())
  		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621

df01812eb   Denis Cheng   [XFRM] net/xfrm/x...
1622
  static LIST_HEAD(xfrm_km_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
  static DEFINE_RWLOCK(xfrm_km_lock);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1624
  void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625
1626
  {
  	struct xfrm_mgr *km;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1627
1628
1629
1630
1631
1632
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list)
  		if (km->notify_policy)
  			km->notify_policy(xp, dir, c);
  	read_unlock(&xfrm_km_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1634
1635
1636
  void km_state_notify(struct xfrm_state *x, struct km_event *c)
  {
  	struct xfrm_mgr *km;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1639
1640
  		if (km->notify)
  			km->notify(x, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1641
  	read_unlock(&xfrm_km_lock);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1642
1643
1644
1645
  }
  
  EXPORT_SYMBOL(km_policy_notify);
  EXPORT_SYMBOL(km_state_notify);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1646
  void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1647
1648
  {
  	struct km_event c;
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
1649
  	c.data.hard = hard;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1650
  	c.pid = pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1651
  	c.event = XFRM_MSG_EXPIRE;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1652
  	km_state_notify(x, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
1654
1655
1656
  
  	if (hard)
  		wake_up(&km_waitq);
  }
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1657
  EXPORT_SYMBOL(km_state_expired);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1658
1659
1660
1661
  /*
   * We send to all registered managers regardless of failure
   * We are happy with one success
  */
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1662
  int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
  {
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1664
  	int err = -EINVAL, acqret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
1666
1667
1668
  	struct xfrm_mgr *km;
  
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list) {
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1669
1670
1671
  		acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
  		if (!acqret)
  			err = acqret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
1673
1674
1675
  	}
  	read_unlock(&xfrm_km_lock);
  	return err;
  }
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1676
  EXPORT_SYMBOL(km_query);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677

5d36b1803   Al Viro   [XFRM]: annotate ...
1678
  int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
  {
  	int err = -EINVAL;
  	struct xfrm_mgr *km;
  
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list) {
  		if (km->new_mapping)
  			err = km->new_mapping(x, ipaddr, sport);
  		if (!err)
  			break;
  	}
  	read_unlock(&xfrm_km_lock);
  	return err;
  }
  EXPORT_SYMBOL(km_new_mapping);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1694
  void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
  {
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1696
  	struct km_event c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697

bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
1698
  	c.data.hard = hard;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1699
  	c.pid = pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1700
  	c.event = XFRM_MSG_POLEXPIRE;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1701
  	km_policy_notify(pol, dir, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
1703
1704
1705
  
  	if (hard)
  		wake_up(&km_waitq);
  }
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
1706
  EXPORT_SYMBOL(km_policy_expired);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707

2d60abc2a   Eric Dumazet   [XFRM]: Do not de...
1708
  #ifdef CONFIG_XFRM_MIGRATE
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
  int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
  	       struct xfrm_migrate *m, int num_migrate)
  {
  	int err = -EINVAL;
  	int ret;
  	struct xfrm_mgr *km;
  
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list) {
  		if (km->migrate) {
  			ret = km->migrate(sel, dir, type, m, num_migrate);
  			if (!ret)
  				err = ret;
  		}
  	}
  	read_unlock(&xfrm_km_lock);
  	return err;
  }
  EXPORT_SYMBOL(km_migrate);
2d60abc2a   Eric Dumazet   [XFRM]: Do not de...
1728
  #endif
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
1729

97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
  int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
  {
  	int err = -EINVAL;
  	int ret;
  	struct xfrm_mgr *km;
  
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list) {
  		if (km->report) {
  			ret = km->report(proto, sel, addr);
  			if (!ret)
  				err = ret;
  		}
  	}
  	read_unlock(&xfrm_km_lock);
  	return err;
  }
  EXPORT_SYMBOL(km_report);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
  int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
  {
  	int err;
  	u8 *data;
  	struct xfrm_mgr *km;
  	struct xfrm_policy *pol = NULL;
  
  	if (optlen <= 0 || optlen > PAGE_SIZE)
  		return -EMSGSIZE;
  
  	data = kmalloc(optlen, GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	err = -EFAULT;
  	if (copy_from_user(data, optval, optlen))
  		goto out;
  
  	err = -EINVAL;
  	read_lock(&xfrm_km_lock);
  	list_for_each_entry(km, &xfrm_km_list, list) {
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
1769
  		pol = km->compile_policy(sk, optname, data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
  					 optlen, &err);
  		if (err >= 0)
  			break;
  	}
  	read_unlock(&xfrm_km_lock);
  
  	if (err >= 0) {
  		xfrm_sk_policy_insert(sk, err, pol);
  		xfrm_pol_put(pol);
  		err = 0;
  	}
  
  out:
  	kfree(data);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_user_policy);
  
  int xfrm_register_km(struct xfrm_mgr *km)
  {
  	write_lock_bh(&xfrm_km_lock);
  	list_add_tail(&km->list, &xfrm_km_list);
  	write_unlock_bh(&xfrm_km_lock);
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_register_km);
  
  int xfrm_unregister_km(struct xfrm_mgr *km)
  {
  	write_lock_bh(&xfrm_km_lock);
  	list_del(&km->list);
  	write_unlock_bh(&xfrm_km_lock);
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_unregister_km);
  
  int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
  {
  	int err = 0;
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
  	if (unlikely(afinfo->family >= NPROTO))
  		return -EAFNOSUPPORT;
f3111502c   Ingo Molnar   [XFRM]: fix incor...
1813
  	write_lock_bh(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
  	if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
  		err = -ENOBUFS;
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1816
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
  		xfrm_state_afinfo[afinfo->family] = afinfo;
f3111502c   Ingo Molnar   [XFRM]: fix incor...
1818
  	write_unlock_bh(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_register_afinfo);
  
  int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
  {
  	int err = 0;
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
  	if (unlikely(afinfo->family >= NPROTO))
  		return -EAFNOSUPPORT;
f3111502c   Ingo Molnar   [XFRM]: fix incor...
1830
  	write_lock_bh(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
1833
  	if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
  		if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
  			err = -EINVAL;
edcd58215   David S. Miller   [XFRM]: Pull xfrm...
1834
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
  			xfrm_state_afinfo[afinfo->family] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
  	}
f3111502c   Ingo Molnar   [XFRM]: fix incor...
1837
  	write_unlock_bh(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
1840
  	return err;
  }
  EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
17c2a42a2   Herbert Xu   [IPSEC]: Store af...
1841
  static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842
1843
1844
1845
1846
1847
  {
  	struct xfrm_state_afinfo *afinfo;
  	if (unlikely(family >= NPROTO))
  		return NULL;
  	read_lock(&xfrm_state_afinfo_lock);
  	afinfo = xfrm_state_afinfo[family];
546be2405   Herbert Xu   [IPSEC] xfrm: Und...
1848
1849
  	if (unlikely(!afinfo))
  		read_unlock(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
  	return afinfo;
  }
17c2a42a2   Herbert Xu   [IPSEC]: Store af...
1852
  static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
9a429c498   Eric Dumazet   [NET]: Add some a...
1853
  	__releases(xfrm_state_afinfo_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1854
  {
546be2405   Herbert Xu   [IPSEC] xfrm: Und...
1855
  	read_unlock(&xfrm_state_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
  }
  
  /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
  void xfrm_state_delete_tunnel(struct xfrm_state *x)
  {
  	if (x->tunnel) {
  		struct xfrm_state *t = x->tunnel;
  
  		if (atomic_read(&t->tunnel_users) == 2)
  			xfrm_state_delete(t);
  		atomic_dec(&t->tunnel_users);
  		xfrm_state_put(t);
  		x->tunnel = NULL;
  	}
  }
  EXPORT_SYMBOL(xfrm_state_delete_tunnel);
  
  int xfrm_state_mtu(struct xfrm_state *x, int mtu)
  {
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
1875
  	int res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1876

c5c252389   Patrick McHardy   [XFRM]: Optimize ...
1877
1878
1879
1880
1881
  	spin_lock_bh(&x->lock);
  	if (x->km.state == XFRM_STATE_VALID &&
  	    x->type && x->type->get_mtu)
  		res = x->type->get_mtu(x, mtu);
  	else
281216177   Patrick McHardy   [XFRM]: Fix MTU c...
1882
  		res = mtu - x->props.header_len;
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
1883
  	spin_unlock_bh(&x->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
1885
  	return res;
  }
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1886
1887
  int xfrm_init_state(struct xfrm_state *x)
  {
d094cd83c   Herbert Xu   [IPSEC]: Add xfrm...
1888
  	struct xfrm_state_afinfo *afinfo;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
1889
  	struct xfrm_mode *inner_mode;
d094cd83c   Herbert Xu   [IPSEC]: Add xfrm...
1890
  	int family = x->props.family;
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1891
  	int err;
d094cd83c   Herbert Xu   [IPSEC]: Add xfrm...
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
  	err = -EAFNOSUPPORT;
  	afinfo = xfrm_state_get_afinfo(family);
  	if (!afinfo)
  		goto error;
  
  	err = 0;
  	if (afinfo->init_flags)
  		err = afinfo->init_flags(x);
  
  	xfrm_state_put_afinfo(afinfo);
  
  	if (err)
  		goto error;
  
  	err = -EPROTONOSUPPORT;
13996378e   Herbert Xu   [IPSEC]: Rename m...
1907

df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
  	if (x->sel.family != AF_UNSPEC) {
  		inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
  		if (inner_mode == NULL)
  			goto error;
  
  		if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
  		    family != x->sel.family) {
  			xfrm_put_mode(inner_mode);
  			goto error;
  		}
  
  		x->inner_mode = inner_mode;
  	} else {
  		struct xfrm_mode *inner_mode_iaf;
  
  		inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
  		if (inner_mode == NULL)
  			goto error;
  
  		if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
  			xfrm_put_mode(inner_mode);
  			goto error;
  		}
  
  		inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
  		if (inner_mode_iaf == NULL)
  			goto error;
  
  		if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
  			xfrm_put_mode(inner_mode_iaf);
  			goto error;
  		}
  
  		if (x->props.family == AF_INET) {
  			x->inner_mode = inner_mode;
  			x->inner_mode_iaf = inner_mode_iaf;
  		} else {
  			x->inner_mode = inner_mode_iaf;
  			x->inner_mode_iaf = inner_mode;
  		}
  	}
13996378e   Herbert Xu   [IPSEC]: Rename m...
1949

d094cd83c   Herbert Xu   [IPSEC]: Add xfrm...
1950
  	x->type = xfrm_get_type(x->id.proto, family);
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1951
1952
1953
1954
1955
1956
  	if (x->type == NULL)
  		goto error;
  
  	err = x->type->init_state(x);
  	if (err)
  		goto error;
13996378e   Herbert Xu   [IPSEC]: Rename m...
1957
1958
  	x->outer_mode = xfrm_get_mode(x->props.mode, family);
  	if (x->outer_mode == NULL)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
1959
  		goto error;
72cb6962a   Herbert Xu   [IPSEC]: Add xfrm...
1960
1961
1962
1963
1964
1965
1966
  	x->km.state = XFRM_STATE_VALID;
  
  error:
  	return err;
  }
  
  EXPORT_SYMBOL(xfrm_init_state);
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1967

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
1969
  void __init xfrm_state_init(void)
  {
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
1970
1971
1972
  	unsigned int sz;
  
  	sz = sizeof(struct hlist_head) * 8;
44e36b42a   David S. Miller   [XFRM]: Extract c...
1973
1974
1975
  	xfrm_state_bydst = xfrm_hash_alloc(sz);
  	xfrm_state_bysrc = xfrm_hash_alloc(sz);
  	xfrm_state_byspi = xfrm_hash_alloc(sz);
f034b5d4e   David S. Miller   [XFRM]: Dynamic x...
1976
1977
1978
  	if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
  		panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
  	xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1979

c4028958b   David Howells   WorkStruct: make ...
1980
  	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
  }
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1982
  #ifdef CONFIG_AUDITSYSCALL
cf35f43e6   Ilpo Järvinen   [XFRM]: Kill some...
1983
1984
  static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
  				     struct audit_buffer *audit_buf)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1985
  {
68277accb   Paul Moore   [XFRM]: Assorted ...
1986
1987
1988
1989
  	struct xfrm_sec_ctx *ctx = x->security;
  	u32 spi = ntohl(x->id.spi);
  
  	if (ctx)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1990
  		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
68277accb   Paul Moore   [XFRM]: Assorted ...
1991
  				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1992
1993
1994
  
  	switch(x->props.family) {
  	case AF_INET:
68277accb   Paul Moore   [XFRM]: Assorted ...
1995
1996
  		audit_log_format(audit_buf,
  				 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
1997
1998
1999
2000
  				 NIPQUAD(x->props.saddr.a4),
  				 NIPQUAD(x->id.daddr.a4));
  		break;
  	case AF_INET6:
68277accb   Paul Moore   [XFRM]: Assorted ...
2001
2002
2003
2004
  		audit_log_format(audit_buf,
  				 " src=" NIP6_FMT " dst=" NIP6_FMT,
  				 NIP6(*(struct in6_addr *)x->props.saddr.a6),
  				 NIP6(*(struct in6_addr *)x->id.daddr.a6));
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2005
2006
  		break;
  	}
68277accb   Paul Moore   [XFRM]: Assorted ...
2007
2008
  
  	audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2009
  }
cf35f43e6   Ilpo Järvinen   [XFRM]: Kill some...
2010
2011
  static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
  				      struct audit_buffer *audit_buf)
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
  {
  	struct iphdr *iph4;
  	struct ipv6hdr *iph6;
  
  	switch (family) {
  	case AF_INET:
  		iph4 = ip_hdr(skb);
  		audit_log_format(audit_buf,
  				 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
  				 NIPQUAD(iph4->saddr),
  				 NIPQUAD(iph4->daddr));
  		break;
  	case AF_INET6:
  		iph6 = ipv6_hdr(skb);
  		audit_log_format(audit_buf,
  				 " src=" NIP6_FMT " dst=" NIP6_FMT
5e2c433d9   YOSHIFUJI Hideaki   [XFRM] AUDIT: Fix...
2028
  				 " flowlbl=0x%x%02x%02x",
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2029
2030
2031
2032
2033
2034
2035
2036
  				 NIP6(iph6->saddr),
  				 NIP6(iph6->daddr),
  				 iph6->flow_lbl[0] & 0x0f,
  				 iph6->flow_lbl[1],
  				 iph6->flow_lbl[2]);
  		break;
  	}
  }
68277accb   Paul Moore   [XFRM]: Assorted ...
2037
  void xfrm_audit_state_add(struct xfrm_state *x, int result,
2532386f4   Eric Paris   Audit: collect se...
2038
  			  uid_t auid, u32 sessionid, u32 secid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2039
2040
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2041

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2042
  	audit_buf = xfrm_audit_start("SAD-add");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2043
2044
  	if (audit_buf == NULL)
  		return;
2532386f4   Eric Paris   Audit: collect se...
2045
  	xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2046
2047
  	xfrm_audit_helper_sainfo(x, audit_buf);
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2048
2049
2050
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
68277accb   Paul Moore   [XFRM]: Assorted ...
2051
  void xfrm_audit_state_delete(struct xfrm_state *x, int result,
2532386f4   Eric Paris   Audit: collect se...
2052
  			     uid_t auid, u32 sessionid, u32 secid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2053
2054
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2055

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2056
  	audit_buf = xfrm_audit_start("SAD-delete");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2057
2058
  	if (audit_buf == NULL)
  		return;
2532386f4   Eric Paris   Audit: collect se...
2059
  	xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2060
2061
  	xfrm_audit_helper_sainfo(x, audit_buf);
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2062
2063
2064
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
  
  void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
  				      struct sk_buff *skb)
  {
  	struct audit_buffer *audit_buf;
  	u32 spi;
  
  	audit_buf = xfrm_audit_start("SA-replay-overflow");
  	if (audit_buf == NULL)
  		return;
  	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
  	/* don't record the sequence number because it's inherent in this kind
  	 * of audit message */
  	spi = ntohl(x->id.spi);
  	audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
  
  static void xfrm_audit_state_replay(struct xfrm_state *x,
  			     struct sk_buff *skb, __be32 net_seq)
  {
  	struct audit_buffer *audit_buf;
  	u32 spi;
  
  	audit_buf = xfrm_audit_start("SA-replayed-pkt");
  	if (audit_buf == NULL)
  		return;
  	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
  	spi = ntohl(x->id.spi);
  	audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
  			 spi, spi, ntohl(net_seq));
  	audit_log_end(audit_buf);
  }
  
  void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
  {
  	struct audit_buffer *audit_buf;
  
  	audit_buf = xfrm_audit_start("SA-notfound");
  	if (audit_buf == NULL)
  		return;
  	xfrm_audit_helper_pktinfo(skb, family, audit_buf);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
  
  void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
  			       __be32 net_spi, __be32 net_seq)
  {
  	struct audit_buffer *audit_buf;
  	u32 spi;
  
  	audit_buf = xfrm_audit_start("SA-notfound");
  	if (audit_buf == NULL)
  		return;
  	xfrm_audit_helper_pktinfo(skb, family, audit_buf);
  	spi = ntohl(net_spi);
  	audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
  			 spi, spi, ntohl(net_seq));
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
  
  void xfrm_audit_state_icvfail(struct xfrm_state *x,
  			      struct sk_buff *skb, u8 proto)
  {
  	struct audit_buffer *audit_buf;
  	__be32 net_spi;
  	__be32 net_seq;
  
  	audit_buf = xfrm_audit_start("SA-icv-failure");
  	if (audit_buf == NULL)
  		return;
  	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
  	if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
  		u32 spi = ntohl(net_spi);
  		audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
  				 spi, spi, ntohl(net_seq));
  	}
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2148
  #endif /* CONFIG_AUDITSYSCALL */