xfrm_state.c 55.8 KB
Newer Older
L
Linus Torvalds 已提交
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
13
 *
L
Linus Torvalds 已提交
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>
21
#include <linux/cache.h>
P
Paul Moore 已提交
22
#include <linux/audit.h>
23
#include <asm/uaccess.h>
24
#include <linux/ktime.h>
25
#include <linux/slab.h>
26 27
#include <linux/interrupt.h>
#include <linux/kernel.h>
L
Linus Torvalds 已提交
28

29 30
#include "xfrm_hash.h"

31 32 33
#define xfrm_state_deref_prot(table, net) \
	rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))

L
Linus Torvalds 已提交
34 35 36
/* Each xfrm_state may be linked to two tables:

   1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
37
   2. Hash table by (daddr,family,reqid) to find what SAs exist for given
L
Linus Torvalds 已提交
38 39 40
      destination/tunnel endpoint. (output)
 */

41
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
42
static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation);
43

44 45 46 47 48
static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
{
	return atomic_inc_not_zero(&x->refcnt);
}

49
static inline unsigned int xfrm_dst_hash(struct net *net,
50 51
					 const xfrm_address_t *daddr,
					 const xfrm_address_t *saddr,
52
					 u32 reqid,
53
					 unsigned short family)
54
{
55
	return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
56 57
}

58
static inline unsigned int xfrm_src_hash(struct net *net,
59 60
					 const xfrm_address_t *daddr,
					 const xfrm_address_t *saddr,
61
					 unsigned short family)
62
{
63
	return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
64 65 66
}

static inline unsigned int
67 68
xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr,
	      __be32 spi, u8 proto, unsigned short family)
69
{
70
	return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
71 72 73 74 75 76 77 78
}

static void xfrm_hash_transfer(struct hlist_head *list,
			       struct hlist_head *ndsttable,
			       struct hlist_head *nsrctable,
			       struct hlist_head *nspitable,
			       unsigned int nhashmask)
{
79
	struct hlist_node *tmp;
80 81
	struct xfrm_state *x;

82
	hlist_for_each_entry_safe(x, tmp, list, bydst) {
83 84
		unsigned int h;

85 86 87
		h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
				    x->props.reqid, x->props.family,
				    nhashmask);
88
		hlist_add_head_rcu(&x->bydst, ndsttable + h);
89

90 91
		h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
				    x->props.family,
92
				    nhashmask);
93
		hlist_add_head_rcu(&x->bysrc, nsrctable + h);
94

95 96 97 98
		if (x->id.spi) {
			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
					    x->id.proto, x->props.family,
					    nhashmask);
99
			hlist_add_head_rcu(&x->byspi, nspitable + h);
100
		}
101 102 103
	}
}

104
static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
105
{
106
	return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
107 108
}

109
static void xfrm_hash_resize(struct work_struct *work)
110
{
111
	struct net *net = container_of(work, struct net, xfrm.state_hash_work);
112 113 114 115 116
	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
	unsigned long nsize, osize;
	unsigned int nhashmask, ohashmask;
	int i;

117
	nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
118
	ndst = xfrm_hash_alloc(nsize);
119
	if (!ndst)
120
		return;
121
	nsrc = xfrm_hash_alloc(nsize);
122
	if (!nsrc) {
123
		xfrm_hash_free(ndst, nsize);
124
		return;
125
	}
126
	nspi = xfrm_hash_alloc(nsize);
127
	if (!nspi) {
128 129
		xfrm_hash_free(ndst, nsize);
		xfrm_hash_free(nsrc, nsize);
130
		return;
131 132
	}

F
Fan Du 已提交
133
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
134
	write_seqcount_begin(&xfrm_state_hash_generation);
135 136

	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
137
	odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net);
138
	for (i = net->xfrm.state_hmask; i >= 0; i--)
139
		xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask);
140

141 142
	osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net);
	ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net);
143
	ohashmask = net->xfrm.state_hmask;
144

145 146 147
	rcu_assign_pointer(net->xfrm.state_bydst, ndst);
	rcu_assign_pointer(net->xfrm.state_bysrc, nsrc);
	rcu_assign_pointer(net->xfrm.state_byspi, nspi);
148
	net->xfrm.state_hmask = nhashmask;
149

150
	write_seqcount_end(&xfrm_state_hash_generation);
F
Fan Du 已提交
151
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
152 153

	osize = (ohashmask + 1) * sizeof(struct hlist_head);
154 155 156

	synchronize_rcu();

157 158 159
	xfrm_hash_free(odst, osize);
	xfrm_hash_free(osrc, osize);
	xfrm_hash_free(ospi, osize);
160 161
}

162 163
static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
L
Linus Torvalds 已提交
164 165 166

static DEFINE_SPINLOCK(xfrm_state_gc_lock);

167
int __xfrm_state_delete(struct xfrm_state *x);
L
Linus Torvalds 已提交
168

169
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
170
bool km_is_alive(const struct km_event *c);
171
void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
L
Linus Torvalds 已提交
172

173
static DEFINE_SPINLOCK(xfrm_type_lock);
174
int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
175
{
176
	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
177
	const struct xfrm_type **typemap;
178 179 180 181 182
	int err = 0;

	if (unlikely(afinfo == NULL))
		return -EAFNOSUPPORT;
	typemap = afinfo->type_map;
183
	spin_lock_bh(&xfrm_type_lock);
184 185 186 187 188

	if (likely(typemap[type->proto] == NULL))
		typemap[type->proto] = type;
	else
		err = -EEXIST;
189 190
	spin_unlock_bh(&xfrm_type_lock);
	xfrm_state_put_afinfo(afinfo);
191 192 193 194
	return err;
}
EXPORT_SYMBOL(xfrm_register_type);

195
int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
196
{
197
	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
198
	const struct xfrm_type **typemap;
199 200 201 202 203
	int err = 0;

	if (unlikely(afinfo == NULL))
		return -EAFNOSUPPORT;
	typemap = afinfo->type_map;
204
	spin_lock_bh(&xfrm_type_lock);
205 206 207 208 209

	if (unlikely(typemap[type->proto] != type))
		err = -ENOENT;
	else
		typemap[type->proto] = NULL;
210 211
	spin_unlock_bh(&xfrm_type_lock);
	xfrm_state_put_afinfo(afinfo);
212 213 214 215
	return err;
}
EXPORT_SYMBOL(xfrm_unregister_type);

216
static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
217 218
{
	struct xfrm_state_afinfo *afinfo;
219 220
	const struct xfrm_type **typemap;
	const struct xfrm_type *type;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	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;
}

243
static void xfrm_put_type(const struct xfrm_type *type)
244 245 246 247
{
	module_put(type->owner);
}

248
static DEFINE_SPINLOCK(xfrm_mode_lock);
249 250 251 252 253 254 255 256 257
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;

258
	afinfo = xfrm_state_get_afinfo(family);
259 260 261 262 263
	if (unlikely(afinfo == NULL))
		return -EAFNOSUPPORT;

	err = -EEXIST;
	modemap = afinfo->mode_map;
264
	spin_lock_bh(&xfrm_mode_lock);
265 266
	if (modemap[mode->encap])
		goto out;
267

268 269 270 271 272 273 274 275 276
	err = -ENOENT;
	if (!try_module_get(afinfo->owner))
		goto out;

	mode->afinfo = afinfo;
	modemap[mode->encap] = mode;
	err = 0;

out:
277 278
	spin_unlock_bh(&xfrm_mode_lock);
	xfrm_state_put_afinfo(afinfo);
279 280 281 282 283 284 285 286 287 288 289 290 291
	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;

292
	afinfo = xfrm_state_get_afinfo(family);
293 294 295 296 297
	if (unlikely(afinfo == NULL))
		return -EAFNOSUPPORT;

	err = -ENOENT;
	modemap = afinfo->mode_map;
298
	spin_lock_bh(&xfrm_mode_lock);
299 300
	if (likely(modemap[mode->encap] == mode)) {
		modemap[mode->encap] = NULL;
301
		module_put(mode->afinfo->owner);
302 303 304
		err = 0;
	}

305 306
	spin_unlock_bh(&xfrm_mode_lock);
	xfrm_state_put_afinfo(afinfo);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
	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);
}

L
Linus Torvalds 已提交
344 345
static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
346
	tasklet_hrtimer_cancel(&x->mtimer);
347
	del_timer_sync(&x->rtimer);
J
Jesper Juhl 已提交
348 349 350 351
	kfree(x->aalg);
	kfree(x->ealg);
	kfree(x->calg);
	kfree(x->encap);
352
	kfree(x->coaddr);
353 354
	kfree(x->replay_esn);
	kfree(x->preplay_esn);
355 356
	if (x->inner_mode)
		xfrm_put_mode(x->inner_mode);
357 358
	if (x->inner_mode_iaf)
		xfrm_put_mode(x->inner_mode_iaf);
359 360
	if (x->outer_mode)
		xfrm_put_mode(x->outer_mode);
L
Linus Torvalds 已提交
361 362 363 364
	if (x->type) {
		x->type->destructor(x);
		xfrm_put_type(x->type);
	}
365
	security_xfrm_state_free(x);
L
Linus Torvalds 已提交
366 367 368
	kfree(x);
}

369
static void xfrm_state_gc_task(struct work_struct *work)
L
Linus Torvalds 已提交
370
{
371
	struct net *net = container_of(work, struct net, xfrm.state_gc_work);
H
Herbert Xu 已提交
372
	struct xfrm_state *x;
373
	struct hlist_node *tmp;
H
Herbert Xu 已提交
374
	struct hlist_head gc_list;
L
Linus Torvalds 已提交
375 376

	spin_lock_bh(&xfrm_state_gc_lock);
377
	hlist_move_list(&net->xfrm.state_gc_list, &gc_list);
L
Linus Torvalds 已提交
378 379
	spin_unlock_bh(&xfrm_state_gc_lock);

380 381
	synchronize_rcu();

382
	hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
L
Linus Torvalds 已提交
383 384 385 386 387 388 389 390
		xfrm_state_gc_destroy(x);
}

static inline unsigned long make_jiffies(long secs)
{
	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
		return MAX_SCHEDULE_TIMEOUT-1;
	else
391
		return secs*HZ;
L
Linus Torvalds 已提交
392 393
}

394
static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
L
Linus Torvalds 已提交
395
{
396 397
	struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
	struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
398
	unsigned long now = get_seconds();
L
Linus Torvalds 已提交
399 400
	long next = LONG_MAX;
	int warn = 0;
J
Joy Latten 已提交
401
	int err = 0;
L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410

	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;
411 412 413 414 415 416 417 418 419 420 421
		if (tmo <= 0) {
			if (x->xflags & XFRM_SOFT_EXPIRE) {
				/* enter hard expire without soft expire first?!
				 * setting a new date could trigger this.
				 * workarbound: fix x->curflt.add_time by below:
				 */
				x->curlft.add_time = now - x->saved_tmo - 1;
				tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
			} else
				goto expired;
		}
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
		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;
438
		if (tmo <= 0) {
L
Linus Torvalds 已提交
439
			warn = 1;
440 441
			x->xflags &= ~XFRM_SOFT_EXPIRE;
		} else if (tmo < next) {
L
Linus Torvalds 已提交
442
			next = tmo;
443 444 445
			x->xflags |= XFRM_SOFT_EXPIRE;
			x->saved_tmo = tmo;
		}
L
Linus Torvalds 已提交
446 447 448 449 450 451 452 453 454 455
	}
	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;
	}

456
	x->km.dying = warn;
L
Linus Torvalds 已提交
457
	if (warn)
458
		km_state_expired(x, 0, 0);
L
Linus Torvalds 已提交
459
resched:
460
	if (next != LONG_MAX) {
461 462
		tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL);
	}
463

L
Linus Torvalds 已提交
464 465 466
	goto out;

expired:
467
	if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0)
L
Linus Torvalds 已提交
468
		x->km.state = XFRM_STATE_EXPIRED;
J
Joy Latten 已提交
469 470

	err = __xfrm_state_delete(x);
471
	if (!err)
472
		km_state_expired(x, 1, 0);
L
Linus Torvalds 已提交
473

474
	xfrm_audit_state_delete(x, err ? 0 : 1, true);
J
Joy Latten 已提交
475

L
Linus Torvalds 已提交
476 477
out:
	spin_unlock(&x->lock);
478
	return HRTIMER_NORESTART;
L
Linus Torvalds 已提交
479 480
}

481 482
static void xfrm_replay_timer_handler(unsigned long data);

483
struct xfrm_state *xfrm_state_alloc(struct net *net)
L
Linus Torvalds 已提交
484 485 486
{
	struct xfrm_state *x;

487
	x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
L
Linus Torvalds 已提交
488 489

	if (x) {
490
		write_pnet(&x->xs_net, net);
L
Linus Torvalds 已提交
491 492
		atomic_set(&x->refcnt, 1);
		atomic_set(&x->tunnel_users, 0);
H
Herbert Xu 已提交
493
		INIT_LIST_HEAD(&x->km.all);
494 495 496
		INIT_HLIST_NODE(&x->bydst);
		INIT_HLIST_NODE(&x->bysrc);
		INIT_HLIST_NODE(&x->byspi);
F
Fan Du 已提交
497 498
		tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler,
					CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
499 500
		setup_timer(&x->rtimer, xfrm_replay_timer_handler,
				(unsigned long)x);
501
		x->curlft.add_time = get_seconds();
L
Linus Torvalds 已提交
502 503 504 505
		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;
506 507
		x->replay_maxage = 0;
		x->replay_maxdiff = 0;
508 509
		x->inner_mode = NULL;
		x->inner_mode_iaf = NULL;
L
Linus Torvalds 已提交
510 511 512 513 514 515 516 517
		spin_lock_init(&x->lock);
	}
	return x;
}
EXPORT_SYMBOL(xfrm_state_alloc);

void __xfrm_state_destroy(struct xfrm_state *x)
{
518 519
	struct net *net = xs_net(x);

520
	WARN_ON(x->km.state != XFRM_STATE_DEAD);
L
Linus Torvalds 已提交
521 522

	spin_lock_bh(&xfrm_state_gc_lock);
523
	hlist_add_head(&x->gclist, &net->xfrm.state_gc_list);
L
Linus Torvalds 已提交
524
	spin_unlock_bh(&xfrm_state_gc_lock);
525
	schedule_work(&net->xfrm.state_gc_work);
L
Linus Torvalds 已提交
526 527 528
}
EXPORT_SYMBOL(__xfrm_state_destroy);

529
int __xfrm_state_delete(struct xfrm_state *x)
L
Linus Torvalds 已提交
530
{
531
	struct net *net = xs_net(x);
532 533
	int err = -ESRCH;

L
Linus Torvalds 已提交
534 535
	if (x->km.state != XFRM_STATE_DEAD) {
		x->km.state = XFRM_STATE_DEAD;
F
Fan Du 已提交
536
		spin_lock(&net->xfrm.xfrm_state_lock);
H
Herbert Xu 已提交
537
		list_del(&x->km.all);
538 539
		hlist_del_rcu(&x->bydst);
		hlist_del_rcu(&x->bysrc);
540
		if (x->id.spi)
541
			hlist_del_rcu(&x->byspi);
542
		net->xfrm.state_num--;
F
Fan Du 已提交
543
		spin_unlock(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
544 545 546 547 548

		/* 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.
		 */
549
		xfrm_state_put(x);
550
		err = 0;
L
Linus Torvalds 已提交
551
	}
552 553

	return err;
L
Linus Torvalds 已提交
554
}
555
EXPORT_SYMBOL(__xfrm_state_delete);
L
Linus Torvalds 已提交
556

557
int xfrm_state_delete(struct xfrm_state *x)
L
Linus Torvalds 已提交
558
{
559 560
	int err;

L
Linus Torvalds 已提交
561
	spin_lock_bh(&x->lock);
562
	err = __xfrm_state_delete(x);
L
Linus Torvalds 已提交
563
	spin_unlock_bh(&x->lock);
564 565

	return err;
L
Linus Torvalds 已提交
566 567 568
}
EXPORT_SYMBOL(xfrm_state_delete);

569 570
#ifdef CONFIG_SECURITY_NETWORK_XFRM
static inline int
571
xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
L
Linus Torvalds 已提交
572
{
573 574
	int i, err = 0;

A
Alexey Dobriyan 已提交
575
	for (i = 0; i <= net->xfrm.state_hmask; i++) {
576 577
		struct xfrm_state *x;

578
		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
579 580
			if (xfrm_id_proto_match(x->id.proto, proto) &&
			   (err = security_xfrm_state_delete(x)) != 0) {
581
				xfrm_audit_state_delete(x, 0, task_valid);
582 583 584 585 586 587 588 589 590
				return err;
			}
		}
	}

	return err;
}
#else
static inline int
591
xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
592 593 594 595 596
{
	return 0;
}
#endif

597
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid)
598
{
599
	int i, err = 0, cnt = 0;
L
Linus Torvalds 已提交
600

F
Fan Du 已提交
601
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
602
	err = xfrm_state_flush_secctx_check(net, proto, task_valid);
603 604 605
	if (err)
		goto out;

606
	err = -ESRCH;
A
Alexey Dobriyan 已提交
607
	for (i = 0; i <= net->xfrm.state_hmask; i++) {
608
		struct xfrm_state *x;
L
Linus Torvalds 已提交
609
restart:
610
		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
L
Linus Torvalds 已提交
611
			if (!xfrm_state_kern(x) &&
612
			    xfrm_id_proto_match(x->id.proto, proto)) {
L
Linus Torvalds 已提交
613
				xfrm_state_hold(x);
F
Fan Du 已提交
614
				spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
615

J
Joy Latten 已提交
616
				err = xfrm_state_delete(x);
J
Joy Latten 已提交
617
				xfrm_audit_state_delete(x, err ? 0 : 1,
618
							task_valid);
L
Linus Torvalds 已提交
619
				xfrm_state_put(x);
620 621
				if (!err)
					cnt++;
L
Linus Torvalds 已提交
622

F
Fan Du 已提交
623
				spin_lock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
624 625 626 627
				goto restart;
			}
		}
	}
628 629
	if (cnt)
		err = 0;
630 631

out:
F
Fan Du 已提交
632
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
633
	return err;
L
Linus Torvalds 已提交
634 635 636
}
EXPORT_SYMBOL(xfrm_state_flush);

637
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
J
Jamal Hadi Salim 已提交
638
{
F
Fan Du 已提交
639
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
640 641
	si->sadcnt = net->xfrm.state_num;
	si->sadhcnt = net->xfrm.state_hmask;
J
Jamal Hadi Salim 已提交
642
	si->sadhmcnt = xfrm_state_hashmax;
F
Fan Du 已提交
643
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
J
Jamal Hadi Salim 已提交
644 645 646
}
EXPORT_SYMBOL(xfrm_sad_getinfo);

L
Linus Torvalds 已提交
647
static int
648
xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
649
		    const struct xfrm_tmpl *tmpl,
650
		    const xfrm_address_t *daddr, const xfrm_address_t *saddr,
651
		    unsigned short family)
L
Linus Torvalds 已提交
652 653 654 655
{
	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
	if (!afinfo)
		return -1;
656 657 658 659 660 661 662 663 664
	afinfo->init_tempsel(&x->sel, fl);

	if (family != tmpl->encap_family) {
		xfrm_state_put_afinfo(afinfo);
		afinfo = xfrm_state_get_afinfo(tmpl->encap_family);
		if (!afinfo)
			return -1;
	}
	afinfo->init_temprop(x, tmpl, daddr, saddr);
L
Linus Torvalds 已提交
665 666 667 668
	xfrm_state_put_afinfo(afinfo);
	return 0;
}

669 670 671 672
static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
					      const xfrm_address_t *daddr,
					      __be32 spi, u8 proto,
					      unsigned short family)
673
{
674
	unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
675 676
	struct xfrm_state *x;

677
	hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
678 679
		if (x->props.family != family ||
		    x->id.spi       != spi ||
680
		    x->id.proto     != proto ||
681
		    !xfrm_addr_equal(&x->id.daddr, daddr, family))
682 683
			continue;

J
Jamal Hadi Salim 已提交
684 685
		if ((mark & x->mark.m) != x->mark.v)
			continue;
686 687
		if (!xfrm_state_hold_rcu(x))
			continue;
688 689 690 691 692 693
		return x;
	}

	return NULL;
}

694 695 696 697
static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
						     const xfrm_address_t *daddr,
						     const xfrm_address_t *saddr,
						     u8 proto, unsigned short family)
698
{
699
	unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
700 701
	struct xfrm_state *x;

702
	hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) {
703
		if (x->props.family != family ||
704
		    x->id.proto     != proto ||
705 706
		    !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
		    !xfrm_addr_equal(&x->props.saddr, saddr, family))
707 708
			continue;

J
Jamal Hadi Salim 已提交
709 710
		if ((mark & x->mark.m) != x->mark.v)
			continue;
711 712
		if (!xfrm_state_hold_rcu(x))
			continue;
713 714 715 716 717 718 719 720 721
		return x;
	}

	return NULL;
}

static inline struct xfrm_state *
__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
{
722
	struct net *net = xs_net(x);
723
	u32 mark = x->mark.v & x->mark.m;
724

725
	if (use_spi)
726 727
		return __xfrm_state_lookup(net, mark, &x->id.daddr,
					   x->id.spi, x->id.proto, family);
728
	else
729 730
		return __xfrm_state_lookup_byaddr(net, mark,
						  &x->id.daddr,
731 732 733 734
						  &x->props.saddr,
						  x->id.proto, family);
}

735
static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
736 737
{
	if (have_hash_collision &&
738 739 740
	    (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
	    net->xfrm.state_num > net->xfrm.state_hmask)
		schedule_work(&net->xfrm.state_hash_work);
741 742
}

743
static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
744
			       const struct flowi *fl, unsigned short family,
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
			       struct xfrm_state **best, int *acq_in_progress,
			       int *error)
{
	/* 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) {
		if ((x->sel.family &&
		     !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
		    !security_xfrm_state_pol_flow_match(x, pol, fl))
			return;

		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) {
		*acq_in_progress = 1;
	} else if (x->km.state == XFRM_STATE_ERROR ||
		   x->km.state == XFRM_STATE_EXPIRED) {
		if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
		    security_xfrm_state_pol_flow_match(x, pol, fl))
			*error = -ESRCH;
	}
}

L
Linus Torvalds 已提交
780
struct xfrm_state *
781
xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
782
		const struct flowi *fl, struct xfrm_tmpl *tmpl,
L
Linus Torvalds 已提交
783 784 785
		struct xfrm_policy *pol, int *err,
		unsigned short family)
{
786
	static xfrm_address_t saddr_wildcard = { };
787
	struct net *net = xp_net(pol);
788
	unsigned int h, h_wildcard;
789
	struct xfrm_state *x, *x0, *to_put;
L
Linus Torvalds 已提交
790 791 792
	int acquire_in_progress = 0;
	int error = 0;
	struct xfrm_state *best = NULL;
793
	u32 mark = pol->mark.v & pol->mark.m;
794
	unsigned short encap_family = tmpl->encap_family;
795
	unsigned int sequence;
796
	struct km_event c;
797

798 799
	to_put = NULL;

800 801
	sequence = read_seqcount_begin(&xfrm_state_hash_generation);

F
Fan Du 已提交
802
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
803
	h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
804
	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
805
		if (x->props.family == encap_family &&
L
Linus Torvalds 已提交
806
		    x->props.reqid == tmpl->reqid &&
J
Jamal Hadi Salim 已提交
807
		    (mark & x->mark.m) == x->mark.v &&
808
		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
809
		    xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
L
Linus Torvalds 已提交
810 811
		    tmpl->mode == x->props.mode &&
		    tmpl->id.proto == x->id.proto &&
812
		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
813
			xfrm_state_look_at(pol, x, fl, encap_family,
814 815
					   &best, &acquire_in_progress, &error);
	}
816
	if (best || acquire_in_progress)
817 818
		goto found;

819
	h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
820
	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
821
		if (x->props.family == encap_family &&
822
		    x->props.reqid == tmpl->reqid &&
J
Jamal Hadi Salim 已提交
823
		    (mark & x->mark.m) == x->mark.v &&
824
		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
825
		    xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
826 827 828
		    tmpl->mode == x->props.mode &&
		    tmpl->id.proto == x->id.proto &&
		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
829
			xfrm_state_look_at(pol, x, fl, encap_family,
830
					   &best, &acquire_in_progress, &error);
L
Linus Torvalds 已提交
831 832
	}

833
found:
L
Linus Torvalds 已提交
834 835
	x = best;
	if (!x && !error && !acquire_in_progress) {
836
		if (tmpl->id.spi &&
837
		    (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
838
					      tmpl->id.proto, encap_family)) != NULL) {
839
			to_put = x0;
L
Linus Torvalds 已提交
840 841 842
			error = -EEXIST;
			goto out;
		}
843 844 845 846 847 848 849 850 851 852 853

		c.net = net;
		/* If the KMs have no listeners (yet...), avoid allocating an SA
		 * for each and every packet - garbage collection might not
		 * handle the flood.
		 */
		if (!km_is_alive(&c)) {
			error = -ESRCH;
			goto out;
		}

854
		x = xfrm_state_alloc(net);
L
Linus Torvalds 已提交
855 856 857 858
		if (x == NULL) {
			error = -ENOMEM;
			goto out;
		}
859
		/* Initialize temporary state matching only
L
Linus Torvalds 已提交
860
		 * to current session. */
861
		xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
862
		memcpy(&x->mark, &pol->mark, sizeof(x->mark));
L
Linus Torvalds 已提交
863

864
		error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid);
865 866
		if (error) {
			x->km.state = XFRM_STATE_DEAD;
867
			to_put = x;
868 869 870 871
			x = NULL;
			goto out;
		}

L
Linus Torvalds 已提交
872 873
		if (km_query(x, tmpl, pol) == 0) {
			x->km.state = XFRM_STATE_ACQ;
874
			list_add(&x->km.all, &net->xfrm.state_all);
875
			hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
876
			h = xfrm_src_hash(net, daddr, saddr, encap_family);
877
			hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
L
Linus Torvalds 已提交
878
			if (x->id.spi) {
879
				h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
880
				hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
L
Linus Torvalds 已提交
881
			}
A
Alexey Dobriyan 已提交
882
			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
883
			tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
884 885
			net->xfrm.state_num++;
			xfrm_hash_grow_check(net, x->bydst.next != NULL);
L
Linus Torvalds 已提交
886 887
		} else {
			x->km.state = XFRM_STATE_DEAD;
888
			to_put = x;
L
Linus Torvalds 已提交
889 890 891 892 893
			x = NULL;
			error = -ESRCH;
		}
	}
out:
894 895 896 897 898 899
	if (x) {
		if (!xfrm_state_hold_rcu(x)) {
			*err = -EAGAIN;
			x = NULL;
		}
	} else {
L
Linus Torvalds 已提交
900
		*err = acquire_in_progress ? -EAGAIN : error;
901
	}
F
Fan Du 已提交
902
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
903 904
	if (to_put)
		xfrm_state_put(to_put);
905 906 907 908 909 910 911 912 913

	if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) {
		*err = -EAGAIN;
		if (x) {
			xfrm_state_put(x);
			x = NULL;
		}
	}

L
Linus Torvalds 已提交
914 915 916
	return x;
}

917
struct xfrm_state *
918
xfrm_stateonly_find(struct net *net, u32 mark,
919
		    xfrm_address_t *daddr, xfrm_address_t *saddr,
920 921
		    unsigned short family, u8 mode, u8 proto, u32 reqid)
{
922
	unsigned int h;
923 924
	struct xfrm_state *rx = NULL, *x = NULL;

925
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
926
	h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
927
	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
928 929
		if (x->props.family == family &&
		    x->props.reqid == reqid &&
J
Jamal Hadi Salim 已提交
930
		    (mark & x->mark.m) == x->mark.v &&
931 932 933 934 935 936 937 938 939 940 941 942
		    !(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);
943
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
944 945 946 947 948 949


	return rx;
}
EXPORT_SYMBOL(xfrm_stateonly_find);

950 951 952 953 954 955 956 957 958 959 960 961 962 963
struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
					      unsigned short family)
{
	struct xfrm_state *x;
	struct xfrm_state_walk *w;

	spin_lock_bh(&net->xfrm.xfrm_state_lock);
	list_for_each_entry(w, &net->xfrm.state_all, all) {
		x = container_of(w, struct xfrm_state, km);
		if (x->props.family != family ||
			x->id.spi != spi)
			continue;

		xfrm_state_hold(x);
964
		spin_unlock_bh(&net->xfrm.xfrm_state_lock);
965 966 967 968 969 970 971
		return x;
	}
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
	return NULL;
}
EXPORT_SYMBOL(xfrm_state_lookup_byspi);

L
Linus Torvalds 已提交
972 973
static void __xfrm_state_insert(struct xfrm_state *x)
{
974
	struct net *net = xs_net(x);
975
	unsigned int h;
L
Linus Torvalds 已提交
976

977
	list_add(&x->km.all, &net->xfrm.state_all);
978

979
	h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
980
			  x->props.reqid, x->props.family);
981
	hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
L
Linus Torvalds 已提交
982

983
	h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
984
	hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
L
Linus Torvalds 已提交
985

986
	if (x->id.spi) {
987
		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
988 989
				  x->props.family);

990
		hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
991 992
	}

993
	tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
994 995
	if (x->replay_maxage)
		mod_timer(&x->rtimer, jiffies + x->replay_maxage);
996

997
	net->xfrm.state_num++;
998

999
	xfrm_hash_grow_check(net, x->bydst.next != NULL);
L
Linus Torvalds 已提交
1000 1001
}

F
Fan Du 已提交
1002
/* net->xfrm.xfrm_state_lock is held */
1003 1004
static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
{
1005
	struct net *net = xs_net(xnew);
1006 1007 1008 1009
	unsigned short family = xnew->props.family;
	u32 reqid = xnew->props.reqid;
	struct xfrm_state *x;
	unsigned int h;
J
Jamal Hadi Salim 已提交
1010
	u32 mark = xnew->mark.v & xnew->mark.m;
1011

1012
	h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
1013
	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1014 1015
		if (x->props.family	== family &&
		    x->props.reqid	== reqid &&
J
Jamal Hadi Salim 已提交
1016
		    (mark & x->mark.m) == x->mark.v &&
1017 1018
		    xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
		    xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family))
H
Herbert Xu 已提交
1019
			x->genid++;
1020 1021 1022
	}
}

L
Linus Torvalds 已提交
1023 1024
void xfrm_state_insert(struct xfrm_state *x)
{
F
Fan Du 已提交
1025 1026 1027
	struct net *net = xs_net(x);

	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1028
	__xfrm_state_bump_genids(x);
L
Linus Torvalds 已提交
1029
	__xfrm_state_insert(x);
F
Fan Du 已提交
1030
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1031 1032 1033
}
EXPORT_SYMBOL(xfrm_state_insert);

F
Fan Du 已提交
1034
/* net->xfrm.xfrm_state_lock is held */
1035 1036
static struct xfrm_state *__find_acq_core(struct net *net,
					  const struct xfrm_mark *m,
1037 1038 1039
					  unsigned short family, u8 mode,
					  u32 reqid, u8 proto,
					  const xfrm_address_t *daddr,
1040 1041
					  const xfrm_address_t *saddr,
					  int create)
1042
{
1043
	unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
1044
	struct xfrm_state *x;
J
Jamal Hadi Salim 已提交
1045
	u32 mark = m->v & m->m;
1046

1047
	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1048 1049 1050 1051
		if (x->props.reqid  != reqid ||
		    x->props.mode   != mode ||
		    x->props.family != family ||
		    x->km.state     != XFRM_STATE_ACQ ||
1052
		    x->id.spi       != 0 ||
1053
		    x->id.proto	    != proto ||
J
Jamal Hadi Salim 已提交
1054
		    (mark & x->mark.m) != x->mark.v ||
1055 1056
		    !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
		    !xfrm_addr_equal(&x->props.saddr, saddr, family))
1057 1058 1059 1060 1061 1062 1063 1064 1065
			continue;

		xfrm_state_hold(x);
		return x;
	}

	if (!create)
		return NULL;

1066
	x = xfrm_state_alloc(net);
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
	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:
J
Jiri Benc 已提交
1079 1080
			x->sel.daddr.in6 = daddr->in6;
			x->sel.saddr.in6 = saddr->in6;
1081 1082
			x->sel.prefixlen_d = 128;
			x->sel.prefixlen_s = 128;
J
Jiri Benc 已提交
1083 1084
			x->props.saddr.in6 = saddr->in6;
			x->id.daddr.in6 = daddr->in6;
1085
			break;
1086
		}
1087 1088 1089 1090 1091 1092

		x->km.state = XFRM_STATE_ACQ;
		x->id.proto = proto;
		x->props.family = family;
		x->props.mode = mode;
		x->props.reqid = reqid;
1093 1094
		x->mark.v = m->v;
		x->mark.m = m->m;
A
Alexey Dobriyan 已提交
1095
		x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
1096
		xfrm_state_hold(x);
1097
		tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
1098
		list_add(&x->km.all, &net->xfrm.state_all);
1099
		hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
1100
		h = xfrm_src_hash(net, daddr, saddr, family);
1101
		hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
1102

1103
		net->xfrm.state_num++;
1104

1105
		xfrm_hash_grow_check(net, x->bydst.next != NULL);
1106 1107 1108 1109 1110
	}

	return x;
}

1111
static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
L
Linus Torvalds 已提交
1112 1113 1114

int xfrm_state_add(struct xfrm_state *x)
{
1115
	struct net *net = xs_net(x);
1116
	struct xfrm_state *x1, *to_put;
L
Linus Torvalds 已提交
1117 1118
	int family;
	int err;
1119
	u32 mark = x->mark.v & x->mark.m;
1120
	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
L
Linus Torvalds 已提交
1121 1122 1123

	family = x->props.family;

1124 1125
	to_put = NULL;

F
Fan Du 已提交
1126
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1127

1128
	x1 = __xfrm_state_locate(x, use_spi, family);
L
Linus Torvalds 已提交
1129
	if (x1) {
1130
		to_put = x1;
L
Linus Torvalds 已提交
1131 1132 1133 1134 1135
		x1 = NULL;
		err = -EEXIST;
		goto out;
	}

1136
	if (use_spi && x->km.seq) {
1137
		x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq);
1138
		if (x1 && ((x1->id.proto != x->id.proto) ||
1139
		    !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) {
1140
			to_put = x1;
L
Linus Torvalds 已提交
1141 1142 1143 1144
			x1 = NULL;
		}
	}

1145
	if (use_spi && !x1)
1146 1147
		x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
				     x->props.reqid, x->id.proto,
1148
				     &x->id.daddr, &x->props.saddr, 0);
L
Linus Torvalds 已提交
1149

1150
	__xfrm_state_bump_genids(x);
L
Linus Torvalds 已提交
1151 1152 1153 1154
	__xfrm_state_insert(x);
	err = 0;

out:
F
Fan Du 已提交
1155
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1156 1157 1158 1159 1160 1161

	if (x1) {
		xfrm_state_delete(x1);
		xfrm_state_put(x1);
	}

1162 1163 1164
	if (to_put)
		xfrm_state_put(to_put);

L
Linus Torvalds 已提交
1165 1166 1167 1168
	return err;
}
EXPORT_SYMBOL(xfrm_state_add);

1169
#ifdef CONFIG_XFRM_MIGRATE
1170
static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig)
1171
{
1172 1173
	struct net *net = xs_net(orig);
	struct xfrm_state *x = xfrm_state_alloc(net);
1174
	if (!x)
H
Herbert Xu 已提交
1175
		goto out;
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186

	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) {
1187
		x->aalg = xfrm_algo_auth_clone(orig->aalg);
1188 1189 1190 1191 1192
		if (!x->aalg)
			goto error;
	}
	x->props.aalgo = orig->props.aalgo;

1193 1194 1195 1196 1197
	if (orig->aead) {
		x->aead = xfrm_algo_aead_clone(orig->aead);
		if (!x->aead)
			goto error;
	}
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
	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;

1212
	if (orig->encap) {
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
		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;
	}

1225
	if (orig->replay_esn) {
1226
		if (xfrm_replay_clone(x, orig))
1227 1228 1229
			goto error;
	}

1230 1231
	memcpy(&x->mark, &orig->mark, sizeof(x->mark));

1232
	if (xfrm_init_state(x) < 0)
1233 1234 1235
		goto error;

	x->props.flags = orig->props.flags;
1236
	x->props.extra_flags = orig->props.extra_flags;
1237

1238 1239 1240
	x->tfcpad = orig->tfcpad;
	x->replay_maxdiff = orig->replay_maxdiff;
	x->replay_maxage = orig->replay_maxage;
1241 1242 1243 1244 1245 1246 1247
	x->curlft.add_time = orig->curlft.add_time;
	x->km.state = orig->km.state;
	x->km.seq = orig->km.seq;

	return x;

 error:
H
Herbert Xu 已提交
1248 1249
	xfrm_state_put(x);
out:
1250 1251 1252
	return NULL;
}

F
Fan Du 已提交
1253
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
1254 1255
{
	unsigned int h;
1256 1257 1258
	struct xfrm_state *x = NULL;

	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1259 1260

	if (m->reqid) {
F
Fan Du 已提交
1261
		h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
1262
				  m->reqid, m->old_family);
F
Fan Du 已提交
1263
		hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1264 1265 1266 1267 1268
			if (x->props.mode != m->mode ||
			    x->id.proto != m->proto)
				continue;
			if (m->reqid && x->props.reqid != m->reqid)
				continue;
1269 1270 1271 1272
			if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
					     m->old_family) ||
			    !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
					     m->old_family))
1273 1274
				continue;
			xfrm_state_hold(x);
1275
			break;
1276 1277
		}
	} else {
F
Fan Du 已提交
1278
		h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
1279
				  m->old_family);
F
Fan Du 已提交
1280
		hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) {
1281 1282 1283
			if (x->props.mode != m->mode ||
			    x->id.proto != m->proto)
				continue;
1284 1285 1286 1287
			if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
					     m->old_family) ||
			    !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
					     m->old_family))
1288 1289
				continue;
			xfrm_state_hold(x);
1290
			break;
1291 1292 1293
		}
	}

1294 1295 1296
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);

	return x;
1297 1298 1299
}
EXPORT_SYMBOL(xfrm_migrate_state_find);

1300 1301
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
				      struct xfrm_migrate *m)
1302 1303 1304
{
	struct xfrm_state *xc;

1305
	xc = xfrm_state_clone(x);
1306 1307 1308 1309 1310 1311 1312
	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 */
1313
	if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) {
1314 1315 1316 1317
		/* 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 {
1318
		if (xfrm_state_add(xc) < 0)
1319 1320 1321 1322 1323
			goto error;
	}

	return xc;
error:
T
Thomas Egerer 已提交
1324
	xfrm_state_put(xc);
1325 1326 1327 1328 1329
	return NULL;
}
EXPORT_SYMBOL(xfrm_state_migrate);
#endif

L
Linus Torvalds 已提交
1330 1331
int xfrm_state_update(struct xfrm_state *x)
{
1332
	struct xfrm_state *x1, *to_put;
L
Linus Torvalds 已提交
1333
	int err;
1334
	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
F
Fan Du 已提交
1335
	struct net *net = xs_net(x);
L
Linus Torvalds 已提交
1336

1337 1338
	to_put = NULL;

F
Fan Du 已提交
1339
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1340
	x1 = __xfrm_state_locate(x, use_spi, x->props.family);
L
Linus Torvalds 已提交
1341 1342 1343 1344 1345 1346

	err = -ESRCH;
	if (!x1)
		goto out;

	if (xfrm_state_kern(x1)) {
1347
		to_put = x1;
L
Linus Torvalds 已提交
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
		err = -EEXIST;
		goto out;
	}

	if (x1->km.state == XFRM_STATE_ACQ) {
		__xfrm_state_insert(x);
		x = NULL;
	}
	err = 0;

out:
F
Fan Du 已提交
1359
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1360

1361 1362 1363
	if (to_put)
		xfrm_state_put(to_put);

L
Linus Torvalds 已提交
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
	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));
1378 1379 1380 1381 1382
		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));
L
Linus Torvalds 已提交
1383 1384 1385
		memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
		x1->km.dying = 0;

1386
		tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
L
Linus Torvalds 已提交
1387 1388 1389 1390
		if (x1->curlft.use_time)
			xfrm_state_check_expire(x1);

		err = 0;
1391 1392
		x->km.state = XFRM_STATE_DEAD;
		__xfrm_state_put(x);
L
Linus Torvalds 已提交
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
	}
	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)
1405
		x->curlft.use_time = get_seconds();
L
Linus Torvalds 已提交
1406 1407 1408

	if (x->curlft.bytes >= x->lft.hard_byte_limit ||
	    x->curlft.packets >= x->lft.hard_packet_limit) {
1409
		x->km.state = XFRM_STATE_EXPIRED;
1410
		tasklet_hrtimer_start(&x->mtimer, ktime_set(0, 0), HRTIMER_MODE_REL);
L
Linus Torvalds 已提交
1411 1412 1413 1414 1415
		return -EINVAL;
	}

	if (!x->km.dying &&
	    (x->curlft.bytes >= x->lft.soft_byte_limit ||
1416 1417
	     x->curlft.packets >= x->lft.soft_packet_limit)) {
		x->km.dying = 1;
1418
		km_state_expired(x, 0, 0);
1419
	}
L
Linus Torvalds 已提交
1420 1421 1422 1423 1424
	return 0;
}
EXPORT_SYMBOL(xfrm_state_check_expire);

struct xfrm_state *
1425
xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi,
1426
		  u8 proto, unsigned short family)
L
Linus Torvalds 已提交
1427 1428 1429
{
	struct xfrm_state *x;

F
Fan Du 已提交
1430
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1431
	x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
F
Fan Du 已提交
1432
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1433 1434 1435 1436 1437
	return x;
}
EXPORT_SYMBOL(xfrm_state_lookup);

struct xfrm_state *
1438
xfrm_state_lookup_byaddr(struct net *net, u32 mark,
1439
			 const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1440 1441 1442 1443
			 u8 proto, unsigned short family)
{
	struct xfrm_state *x;

F
Fan Du 已提交
1444
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1445
	x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
F
Fan Du 已提交
1446
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1447 1448 1449 1450 1451
	return x;
}
EXPORT_SYMBOL(xfrm_state_lookup_byaddr);

struct xfrm_state *
1452 1453 1454
xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
	      u8 proto, const xfrm_address_t *daddr,
	      const xfrm_address_t *saddr, int create, unsigned short family)
L
Linus Torvalds 已提交
1455 1456 1457
{
	struct xfrm_state *x;

F
Fan Du 已提交
1458
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1459
	x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create);
F
Fan Du 已提交
1460
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1461

L
Linus Torvalds 已提交
1462 1463 1464 1465
	return x;
}
EXPORT_SYMBOL(xfrm_find_acq);

1466 1467 1468
#ifdef CONFIG_XFRM_SUB_POLICY
int
xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
F
Fan Du 已提交
1469
	       unsigned short family, struct net *net)
1470 1471 1472 1473 1474 1475
{
	int err = 0;
	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
	if (!afinfo)
		return -EAFNOSUPPORT;

F
Fan Du 已提交
1476
	spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/
1477 1478
	if (afinfo->tmpl_sort)
		err = afinfo->tmpl_sort(dst, src, n);
F
Fan Du 已提交
1479
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
	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);
1491
	struct net *net = xs_net(*src);
F
Fan Du 已提交
1492

1493 1494 1495
	if (!afinfo)
		return -EAFNOSUPPORT;

F
Fan Du 已提交
1496
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1497 1498
	if (afinfo->state_sort)
		err = afinfo->state_sort(dst, src, n);
F
Fan Du 已提交
1499
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1500 1501 1502 1503 1504 1505
	xfrm_state_put_afinfo(afinfo);
	return err;
}
EXPORT_SYMBOL(xfrm_state_sort);
#endif

L
Linus Torvalds 已提交
1506 1507
/* Silly enough, but I'm lazy to build resolution list */

1508
static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
L
Linus Torvalds 已提交
1509 1510 1511
{
	int i;

1512
	for (i = 0; i <= net->xfrm.state_hmask; i++) {
1513 1514
		struct xfrm_state *x;

1515
		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
1516
			if (x->km.seq == seq &&
J
Jamal Hadi Salim 已提交
1517
			    (mark & x->mark.m) == x->mark.v &&
1518
			    x->km.state == XFRM_STATE_ACQ) {
L
Linus Torvalds 已提交
1519 1520 1521 1522 1523 1524 1525 1526
				xfrm_state_hold(x);
				return x;
			}
		}
	}
	return NULL;
}

1527
struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
L
Linus Torvalds 已提交
1528 1529 1530
{
	struct xfrm_state *x;

F
Fan Du 已提交
1531
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1532
	x = __xfrm_find_acq_byseq(net, mark, seq);
F
Fan Du 已提交
1533
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1534 1535 1536 1537 1538 1539 1540
	return x;
}
EXPORT_SYMBOL(xfrm_find_acq_byseq);

u32 xfrm_get_acqseq(void)
{
	u32 res;
1541 1542 1543 1544 1545
	static atomic_t acqseq;

	do {
		res = atomic_inc_return(&acqseq);
	} while (!res);
L
Linus Torvalds 已提交
1546 1547 1548 1549 1550

	return res;
}
EXPORT_SYMBOL(xfrm_get_acqseq);

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
int verify_spi_info(u8 proto, u32 min, u32 max)
{
	switch (proto) {
	case IPPROTO_AH:
	case IPPROTO_ESP:
		break;

	case IPPROTO_COMP:
		/* IPCOMP spi is 16-bits. */
		if (max >= 0x10000)
			return -EINVAL;
		break;

	default:
		return -EINVAL;
	}

	if (min > max)
		return -EINVAL;

	return 0;
}
EXPORT_SYMBOL(verify_spi_info);

1575
int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
L
Linus Torvalds 已提交
1576
{
1577
	struct net *net = xs_net(x);
1578
	unsigned int h;
L
Linus Torvalds 已提交
1579
	struct xfrm_state *x0;
1580 1581 1582
	int err = -ENOENT;
	__be32 minspi = htonl(low);
	__be32 maxspi = htonl(high);
1583
	u32 mark = x->mark.v & x->mark.m;
L
Linus Torvalds 已提交
1584

1585 1586 1587 1588 1589
	spin_lock_bh(&x->lock);
	if (x->km.state == XFRM_STATE_DEAD)
		goto unlock;

	err = 0;
L
Linus Torvalds 已提交
1590
	if (x->id.spi)
1591 1592 1593
		goto unlock;

	err = -ENOENT;
L
Linus Torvalds 已提交
1594 1595

	if (minspi == maxspi) {
1596
		x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family);
L
Linus Torvalds 已提交
1597 1598
		if (x0) {
			xfrm_state_put(x0);
1599
			goto unlock;
L
Linus Torvalds 已提交
1600 1601 1602 1603
		}
		x->id.spi = minspi;
	} else {
		u32 spi = 0;
1604
		for (h = 0; h < high-low+1; h++) {
1605
			spi = low + prandom_u32()%(high-low+1);
1606
			x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
L
Linus Torvalds 已提交
1607 1608 1609 1610 1611 1612 1613 1614
			if (x0 == NULL) {
				x->id.spi = htonl(spi);
				break;
			}
			xfrm_state_put(x0);
		}
	}
	if (x->id.spi) {
F
Fan Du 已提交
1615
		spin_lock_bh(&net->xfrm.xfrm_state_lock);
1616
		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
1617
		hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
F
Fan Du 已提交
1618
		spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1619 1620

		err = 0;
L
Linus Torvalds 已提交
1621
	}
1622 1623 1624 1625 1626

unlock:
	spin_unlock_bh(&x->lock);

	return err;
L
Linus Torvalds 已提交
1627 1628 1629
}
EXPORT_SYMBOL(xfrm_alloc_spi);

1630
static bool __xfrm_state_filter_match(struct xfrm_state *x,
1631
				      struct xfrm_address_filter *filter)
1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
{
	if (filter) {
		if ((filter->family == AF_INET ||
		     filter->family == AF_INET6) &&
		    x->props.family != filter->family)
			return false;

		return addr_match(&x->props.saddr, &filter->saddr,
				  filter->splen) &&
		       addr_match(&x->id.daddr, &filter->daddr,
				  filter->dplen);
	}
	return true;
}

1647
int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
1648
		    int (*func)(struct xfrm_state *, int, void*),
L
Linus Torvalds 已提交
1649 1650
		    void *data)
{
H
Herbert Xu 已提交
1651 1652
	struct xfrm_state *state;
	struct xfrm_state_walk *x;
L
Linus Torvalds 已提交
1653 1654
	int err = 0;

H
Herbert Xu 已提交
1655
	if (walk->seq != 0 && list_empty(&walk->all))
1656 1657
		return 0;

F
Fan Du 已提交
1658
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
H
Herbert Xu 已提交
1659
	if (list_empty(&walk->all))
1660
		x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
H
Herbert Xu 已提交
1661
	else
1662
		x = list_first_entry(&walk->all, struct xfrm_state_walk, all);
1663
	list_for_each_entry_from(x, &net->xfrm.state_all, all) {
H
Herbert Xu 已提交
1664
		if (x->state == XFRM_STATE_DEAD)
1665
			continue;
H
Herbert Xu 已提交
1666 1667
		state = container_of(x, struct xfrm_state, km);
		if (!xfrm_id_proto_match(state->id.proto, walk->proto))
1668
			continue;
1669 1670
		if (!__xfrm_state_filter_match(state, walk->filter))
			continue;
H
Herbert Xu 已提交
1671 1672 1673 1674
		err = func(state, walk->seq, data);
		if (err) {
			list_move_tail(&walk->all, &x->all);
			goto out;
L
Linus Torvalds 已提交
1675
		}
H
Herbert Xu 已提交
1676
		walk->seq++;
L
Linus Torvalds 已提交
1677
	}
H
Herbert Xu 已提交
1678
	if (walk->seq == 0) {
L
Linus Torvalds 已提交
1679 1680 1681
		err = -ENOENT;
		goto out;
	}
H
Herbert Xu 已提交
1682
	list_del_init(&walk->all);
L
Linus Torvalds 已提交
1683
out:
F
Fan Du 已提交
1684
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
L
Linus Torvalds 已提交
1685 1686 1687 1688
	return err;
}
EXPORT_SYMBOL(xfrm_state_walk);

1689
void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
1690
			  struct xfrm_address_filter *filter)
H
Herbert Xu 已提交
1691
{
H
Herbert Xu 已提交
1692
	INIT_LIST_HEAD(&walk->all);
H
Herbert Xu 已提交
1693
	walk->proto = proto;
H
Herbert Xu 已提交
1694 1695
	walk->state = XFRM_STATE_DEAD;
	walk->seq = 0;
1696
	walk->filter = filter;
H
Herbert Xu 已提交
1697 1698 1699
}
EXPORT_SYMBOL(xfrm_state_walk_init);

F
Fan Du 已提交
1700
void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
1701
{
1702 1703
	kfree(walk->filter);

H
Herbert Xu 已提交
1704
	if (list_empty(&walk->all))
H
Herbert Xu 已提交
1705 1706
		return;

F
Fan Du 已提交
1707
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
H
Herbert Xu 已提交
1708
	list_del(&walk->all);
F
Fan Du 已提交
1709
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1710 1711 1712
}
EXPORT_SYMBOL(xfrm_state_walk_done);

1713 1714
static void xfrm_replay_timer_handler(unsigned long data)
{
1715
	struct xfrm_state *x = (struct xfrm_state *)data;
1716 1717 1718

	spin_lock(&x->lock);

J
Jamal Hadi Salim 已提交
1719
	if (x->km.state == XFRM_STATE_VALID) {
1720
		if (xfrm_aevent_is_on(xs_net(x)))
1721
			x->repl->notify(x, XFRM_REPLAY_TIMEOUT);
J
Jamal Hadi Salim 已提交
1722 1723 1724
		else
			x->xflags |= XFRM_TIME_DEFER;
	}
1725 1726 1727 1728

	spin_unlock(&x->lock);
}

1729
static LIST_HEAD(xfrm_km_list);
L
Linus Torvalds 已提交
1730

1731
void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
L
Linus Torvalds 已提交
1732 1733 1734
{
	struct xfrm_mgr *km;

1735 1736
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list)
1737 1738
		if (km->notify_policy)
			km->notify_policy(xp, dir, c);
1739
	rcu_read_unlock();
1740
}
L
Linus Torvalds 已提交
1741

1742
void km_state_notify(struct xfrm_state *x, const struct km_event *c)
1743 1744
{
	struct xfrm_mgr *km;
1745 1746
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list)
1747 1748
		if (km->notify)
			km->notify(x, c);
1749
	rcu_read_unlock();
1750 1751 1752 1753 1754
}

EXPORT_SYMBOL(km_policy_notify);
EXPORT_SYMBOL(km_state_notify);

1755
void km_state_expired(struct xfrm_state *x, int hard, u32 portid)
1756 1757 1758
{
	struct km_event c;

1759
	c.data.hard = hard;
1760
	c.portid = portid;
1761
	c.event = XFRM_MSG_EXPIRE;
1762
	km_state_notify(x, &c);
L
Linus Torvalds 已提交
1763 1764
}

1765
EXPORT_SYMBOL(km_state_expired);
1766 1767 1768 1769
/*
 * We send to all registered managers regardless of failure
 * We are happy with one success
*/
1770
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
L
Linus Torvalds 已提交
1771
{
1772
	int err = -EINVAL, acqret;
L
Linus Torvalds 已提交
1773 1774
	struct xfrm_mgr *km;

1775 1776
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1777
		acqret = km->acquire(x, t, pol);
1778 1779
		if (!acqret)
			err = acqret;
L
Linus Torvalds 已提交
1780
	}
1781
	rcu_read_unlock();
L
Linus Torvalds 已提交
1782 1783
	return err;
}
1784
EXPORT_SYMBOL(km_query);
L
Linus Torvalds 已提交
1785

A
Al Viro 已提交
1786
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
L
Linus Torvalds 已提交
1787 1788 1789 1790
{
	int err = -EINVAL;
	struct xfrm_mgr *km;

1791 1792
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
L
Linus Torvalds 已提交
1793 1794 1795 1796 1797
		if (km->new_mapping)
			err = km->new_mapping(x, ipaddr, sport);
		if (!err)
			break;
	}
1798
	rcu_read_unlock();
L
Linus Torvalds 已提交
1799 1800 1801 1802
	return err;
}
EXPORT_SYMBOL(km_new_mapping);

1803
void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
L
Linus Torvalds 已提交
1804
{
1805
	struct km_event c;
L
Linus Torvalds 已提交
1806

1807
	c.data.hard = hard;
1808
	c.portid = portid;
1809
	c.event = XFRM_MSG_POLEXPIRE;
1810
	km_policy_notify(pol, dir, &c);
L
Linus Torvalds 已提交
1811
}
1812
EXPORT_SYMBOL(km_policy_expired);
L
Linus Torvalds 已提交
1813

1814
#ifdef CONFIG_XFRM_MIGRATE
1815 1816 1817
int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
	       const struct xfrm_migrate *m, int num_migrate,
	       const struct xfrm_kmaddress *k)
1818 1819 1820 1821 1822
{
	int err = -EINVAL;
	int ret;
	struct xfrm_mgr *km;

1823 1824
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1825
		if (km->migrate) {
1826
			ret = km->migrate(sel, dir, type, m, num_migrate, k);
1827 1828 1829 1830
			if (!ret)
				err = ret;
		}
	}
1831
	rcu_read_unlock();
1832 1833 1834
	return err;
}
EXPORT_SYMBOL(km_migrate);
1835
#endif
1836

1837
int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1838 1839 1840 1841 1842
{
	int err = -EINVAL;
	int ret;
	struct xfrm_mgr *km;

1843 1844
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1845
		if (km->report) {
1846
			ret = km->report(net, proto, sel, addr);
1847 1848 1849 1850
			if (!ret)
				err = ret;
		}
	}
1851
	rcu_read_unlock();
1852 1853 1854 1855
	return err;
}
EXPORT_SYMBOL(km_report);

1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
bool km_is_alive(const struct km_event *c)
{
	struct xfrm_mgr *km;
	bool is_alive = false;

	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
		if (km->is_alive && km->is_alive(c)) {
			is_alive = true;
			break;
		}
	}
	rcu_read_unlock();

	return is_alive;
}
EXPORT_SYMBOL(km_is_alive);

L
Linus Torvalds 已提交
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
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;
1893 1894
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1895
		pol = km->compile_policy(sk, optname, data,
L
Linus Torvalds 已提交
1896 1897 1898 1899
					 optlen, &err);
		if (err >= 0)
			break;
	}
1900
	rcu_read_unlock();
L
Linus Torvalds 已提交
1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913

	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);

1914 1915
static DEFINE_SPINLOCK(xfrm_km_lock);

L
Linus Torvalds 已提交
1916 1917
int xfrm_register_km(struct xfrm_mgr *km)
{
1918 1919 1920
	spin_lock_bh(&xfrm_km_lock);
	list_add_tail_rcu(&km->list, &xfrm_km_list);
	spin_unlock_bh(&xfrm_km_lock);
L
Linus Torvalds 已提交
1921 1922 1923 1924 1925 1926
	return 0;
}
EXPORT_SYMBOL(xfrm_register_km);

int xfrm_unregister_km(struct xfrm_mgr *km)
{
1927 1928 1929 1930
	spin_lock_bh(&xfrm_km_lock);
	list_del_rcu(&km->list);
	spin_unlock_bh(&xfrm_km_lock);
	synchronize_rcu();
L
Linus Torvalds 已提交
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
	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;
1942
	spin_lock_bh(&xfrm_state_afinfo_lock);
L
Linus Torvalds 已提交
1943
	if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1944
		err = -EEXIST;
1945
	else
1946 1947
		rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo);
	spin_unlock_bh(&xfrm_state_afinfo_lock);
L
Linus Torvalds 已提交
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
	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;
1959
	spin_lock_bh(&xfrm_state_afinfo_lock);
L
Linus Torvalds 已提交
1960 1961 1962
	if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
		if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
			err = -EINVAL;
1963
		else
1964
			RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL);
L
Linus Torvalds 已提交
1965
	}
1966 1967
	spin_unlock_bh(&xfrm_state_afinfo_lock);
	synchronize_rcu();
L
Linus Torvalds 已提交
1968 1969 1970 1971
	return err;
}
EXPORT_SYMBOL(xfrm_state_unregister_afinfo);

1972
struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
L
Linus Torvalds 已提交
1973 1974 1975 1976
{
	struct xfrm_state_afinfo *afinfo;
	if (unlikely(family >= NPROTO))
		return NULL;
1977 1978
	rcu_read_lock();
	afinfo = rcu_dereference(xfrm_state_afinfo[family]);
1979
	if (unlikely(!afinfo))
1980
		rcu_read_unlock();
L
Linus Torvalds 已提交
1981 1982 1983
	return afinfo;
}

1984
void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
L
Linus Torvalds 已提交
1985
{
1986
	rcu_read_unlock();
L
Linus Torvalds 已提交
1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
}

/* 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)
{
2006
	int res;
L
Linus Torvalds 已提交
2007

2008 2009 2010 2011 2012
	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
2013
		res = mtu - x->props.header_len;
2014
	spin_unlock_bh(&x->lock);
L
Linus Torvalds 已提交
2015 2016 2017
	return res;
}

2018
int __xfrm_init_state(struct xfrm_state *x, bool init_replay)
H
Herbert Xu 已提交
2019
{
2020
	struct xfrm_state_afinfo *afinfo;
2021
	struct xfrm_mode *inner_mode;
2022
	int family = x->props.family;
H
Herbert Xu 已提交
2023 2024
	int err;

2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
	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;
2040

2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054
	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;
2055
		int iafamily = AF_INET;
2056

2057
		inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
2058 2059 2060 2061 2062 2063 2064
		if (inner_mode == NULL)
			goto error;

		if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
			xfrm_put_mode(inner_mode);
			goto error;
		}
2065
		x->inner_mode = inner_mode;
2066

2067 2068
		if (x->props.family == AF_INET)
			iafamily = AF_INET6;
2069

2070 2071 2072 2073 2074 2075
		inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily);
		if (inner_mode_iaf) {
			if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)
				x->inner_mode_iaf = inner_mode_iaf;
			else
				xfrm_put_mode(inner_mode_iaf);
2076 2077
		}
	}
2078

2079
	x->type = xfrm_get_type(x->id.proto, family);
H
Herbert Xu 已提交
2080 2081 2082 2083 2084 2085 2086
	if (x->type == NULL)
		goto error;

	err = x->type->init_state(x);
	if (err)
		goto error;

2087
	x->outer_mode = xfrm_get_mode(x->props.mode, family);
2088 2089
	if (x->outer_mode == NULL) {
		err = -EPROTONOSUPPORT;
2090
		goto error;
2091
	}
2092

2093 2094 2095 2096 2097 2098
	if (init_replay) {
		err = xfrm_init_replay(x);
		if (err)
			goto error;
	}

H
Herbert Xu 已提交
2099 2100 2101 2102 2103 2104
	x->km.state = XFRM_STATE_VALID;

error:
	return err;
}

2105 2106 2107 2108 2109 2110 2111
EXPORT_SYMBOL(__xfrm_init_state);

int xfrm_init_state(struct xfrm_state *x)
{
	return __xfrm_init_state(x, true);
}

H
Herbert Xu 已提交
2112
EXPORT_SYMBOL(xfrm_init_state);
2113

2114
int __net_init xfrm_state_init(struct net *net)
L
Linus Torvalds 已提交
2115
{
2116 2117
	unsigned int sz;

2118 2119
	INIT_LIST_HEAD(&net->xfrm.state_all);

2120 2121
	sz = sizeof(struct hlist_head) * 8;

2122 2123 2124
	net->xfrm.state_bydst = xfrm_hash_alloc(sz);
	if (!net->xfrm.state_bydst)
		goto out_bydst;
2125 2126 2127
	net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
	if (!net->xfrm.state_bysrc)
		goto out_bysrc;
2128 2129 2130
	net->xfrm.state_byspi = xfrm_hash_alloc(sz);
	if (!net->xfrm.state_byspi)
		goto out_byspi;
2131
	net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
L
Linus Torvalds 已提交
2132

2133
	net->xfrm.state_num = 0;
2134
	INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
2135
	INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
2136
	INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
F
Fan Du 已提交
2137
	spin_lock_init(&net->xfrm.xfrm_state_lock);
2138
	return 0;
2139

2140 2141
out_byspi:
	xfrm_hash_free(net->xfrm.state_bysrc, sz);
2142 2143
out_bysrc:
	xfrm_hash_free(net->xfrm.state_bydst, sz);
2144 2145
out_bydst:
	return -ENOMEM;
2146 2147 2148 2149
}

void xfrm_state_fini(struct net *net)
{
2150 2151
	unsigned int sz;

2152
	flush_work(&net->xfrm.state_hash_work);
2153
	xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
2154 2155
	flush_work(&net->xfrm.state_gc_work);

2156
	WARN_ON(!list_empty(&net->xfrm.state_all));
2157

2158
	sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
2159 2160
	WARN_ON(!hlist_empty(net->xfrm.state_byspi));
	xfrm_hash_free(net->xfrm.state_byspi, sz);
2161 2162
	WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
	xfrm_hash_free(net->xfrm.state_bysrc, sz);
2163 2164
	WARN_ON(!hlist_empty(net->xfrm.state_bydst));
	xfrm_hash_free(net->xfrm.state_bydst, sz);
L
Linus Torvalds 已提交
2165 2166
}

J
Joy Latten 已提交
2167
#ifdef CONFIG_AUDITSYSCALL
I
Ilpo Järvinen 已提交
2168 2169
static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
				     struct audit_buffer *audit_buf)
J
Joy Latten 已提交
2170
{
P
Paul Moore 已提交
2171 2172 2173 2174
	struct xfrm_sec_ctx *ctx = x->security;
	u32 spi = ntohl(x->id.spi);

	if (ctx)
J
Joy Latten 已提交
2175
		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
P
Paul Moore 已提交
2176
				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
J
Joy Latten 已提交
2177

2178
	switch (x->props.family) {
J
Joy Latten 已提交
2179
	case AF_INET:
H
Harvey Harrison 已提交
2180 2181
		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
				 &x->props.saddr.a4, &x->id.daddr.a4);
J
Joy Latten 已提交
2182 2183
		break;
	case AF_INET6:
H
Harvey Harrison 已提交
2184
		audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
2185
				 x->props.saddr.a6, x->id.daddr.a6);
J
Joy Latten 已提交
2186 2187
		break;
	}
P
Paul Moore 已提交
2188 2189

	audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
J
Joy Latten 已提交
2190 2191
}

I
Ilpo Järvinen 已提交
2192 2193
static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
				      struct audit_buffer *audit_buf)
P
Paul Moore 已提交
2194
{
2195 2196
	const struct iphdr *iph4;
	const struct ipv6hdr *iph6;
P
Paul Moore 已提交
2197 2198 2199 2200

	switch (family) {
	case AF_INET:
		iph4 = ip_hdr(skb);
H
Harvey Harrison 已提交
2201 2202
		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
				 &iph4->saddr, &iph4->daddr);
P
Paul Moore 已提交
2203 2204 2205 2206
		break;
	case AF_INET6:
		iph6 = ipv6_hdr(skb);
		audit_log_format(audit_buf,
H
Harvey Harrison 已提交
2207
				 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
2208
				 &iph6->saddr, &iph6->daddr,
P
Paul Moore 已提交
2209 2210 2211 2212 2213 2214 2215
				 iph6->flow_lbl[0] & 0x0f,
				 iph6->flow_lbl[1],
				 iph6->flow_lbl[2]);
		break;
	}
}

2216
void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid)
J
Joy Latten 已提交
2217 2218 2219
{
	struct audit_buffer *audit_buf;

P
Paul Moore 已提交
2220
	audit_buf = xfrm_audit_start("SAD-add");
J
Joy Latten 已提交
2221 2222
	if (audit_buf == NULL)
		return;
2223
	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
P
Paul Moore 已提交
2224 2225
	xfrm_audit_helper_sainfo(x, audit_buf);
	audit_log_format(audit_buf, " res=%u", result);
J
Joy Latten 已提交
2226 2227 2228 2229
	audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);

2230
void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid)
J
Joy Latten 已提交
2231 2232 2233
{
	struct audit_buffer *audit_buf;

P
Paul Moore 已提交
2234
	audit_buf = xfrm_audit_start("SAD-delete");
J
Joy Latten 已提交
2235 2236
	if (audit_buf == NULL)
		return;
2237
	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
P
Paul Moore 已提交
2238 2239
	xfrm_audit_helper_sainfo(x, audit_buf);
	audit_log_format(audit_buf, " res=%u", result);
J
Joy Latten 已提交
2240 2241 2242
	audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
P
Paul Moore 已提交
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261

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);

2262
void xfrm_audit_state_replay(struct xfrm_state *x,
P
Paul Moore 已提交
2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
			     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);
}
2277
EXPORT_SYMBOL_GPL(xfrm_audit_state_replay);
P
Paul Moore 已提交
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326

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);
J
Joy Latten 已提交
2327
#endif /* CONFIG_AUDITSYSCALL */