xfrm_state.c 55.6 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"

L
Linus Torvalds 已提交
31 32 33
/* Each xfrm_state may be linked to two tables:

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

38
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
39
static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation);
40

41 42 43 44 45
static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
{
	return atomic_inc_not_zero(&x->refcnt);
}

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

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

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

static void xfrm_hash_transfer(struct hlist_head *list,
			       struct hlist_head *ndsttable,
			       struct hlist_head *nsrctable,
			       struct hlist_head *nspitable,
			       unsigned int nhashmask)
{
76
	struct hlist_node *tmp;
77 78
	struct xfrm_state *x;

79
	hlist_for_each_entry_safe(x, tmp, list, bydst) {
80 81
		unsigned int h;

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

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

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

101
static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
102
{
103
	return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
104 105
}

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

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

F
Fan Du 已提交
130
	spin_lock_bh(&net->xfrm.xfrm_state_lock);
131
	write_seqcount_begin(&xfrm_state_hash_generation);
132 133

	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
134 135
	for (i = net->xfrm.state_hmask; i >= 0; i--)
		xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
136 137
				   nhashmask);

138 139 140 141
	odst = net->xfrm.state_bydst;
	osrc = net->xfrm.state_bysrc;
	ospi = net->xfrm.state_byspi;
	ohashmask = net->xfrm.state_hmask;
142

143 144 145 146
	net->xfrm.state_bydst = ndst;
	net->xfrm.state_bysrc = nsrc;
	net->xfrm.state_byspi = nspi;
	net->xfrm.state_hmask = nhashmask;
147

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

	osize = (ohashmask + 1) * sizeof(struct hlist_head);
152 153 154

	synchronize_rcu();

155 156 157
	xfrm_hash_free(odst, osize);
	xfrm_hash_free(osrc, osize);
	xfrm_hash_free(ospi, osize);
158 159
}

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

static DEFINE_SPINLOCK(xfrm_state_gc_lock);

165
int __xfrm_state_delete(struct xfrm_state *x);
L
Linus Torvalds 已提交
166

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

303 304
	spin_unlock_bh(&xfrm_mode_lock);
	xfrm_state_put_afinfo(afinfo);
305 306 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
	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 已提交
342 343
static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
344
	tasklet_hrtimer_cancel(&x->mtimer);
345
	del_timer_sync(&x->rtimer);
J
Jesper Juhl 已提交
346 347 348 349
	kfree(x->aalg);
	kfree(x->ealg);
	kfree(x->calg);
	kfree(x->encap);
350
	kfree(x->coaddr);
351 352
	kfree(x->replay_esn);
	kfree(x->preplay_esn);
353 354
	if (x->inner_mode)
		xfrm_put_mode(x->inner_mode);
355 356
	if (x->inner_mode_iaf)
		xfrm_put_mode(x->inner_mode_iaf);
357 358
	if (x->outer_mode)
		xfrm_put_mode(x->outer_mode);
L
Linus Torvalds 已提交
359 360 361 362
	if (x->type) {
		x->type->destructor(x);
		xfrm_put_type(x->type);
	}
363
	security_xfrm_state_free(x);
L
Linus Torvalds 已提交
364 365 366
	kfree(x);
}

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

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

378 379
	synchronize_rcu();

380
	hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
L
Linus Torvalds 已提交
381 382 383 384 385 386 387 388
		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
389
		return secs*HZ;
L
Linus Torvalds 已提交
390 391
}

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

	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;
409 410 411 412 413 414 415 416 417 418 419
		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 已提交
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
		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;
436
		if (tmo <= 0) {
L
Linus Torvalds 已提交
437
			warn = 1;
438 439
			x->xflags &= ~XFRM_SOFT_EXPIRE;
		} else if (tmo < next) {
L
Linus Torvalds 已提交
440
			next = tmo;
441 442 443
			x->xflags |= XFRM_SOFT_EXPIRE;
			x->saved_tmo = tmo;
		}
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453
	}
	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;
	}

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

L
Linus Torvalds 已提交
462 463 464
	goto out;

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

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

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

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

479 480
static void xfrm_replay_timer_handler(unsigned long data);

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

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

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

void __xfrm_state_destroy(struct xfrm_state *x)
{
516 517
	struct net *net = xs_net(x);

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

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

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

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

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

	return err;
L
Linus Torvalds 已提交
552
}
553
EXPORT_SYMBOL(__xfrm_state_delete);
L
Linus Torvalds 已提交
554

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

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

	return err;
L
Linus Torvalds 已提交
564 565 566
}
EXPORT_SYMBOL(xfrm_state_delete);

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

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

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

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

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

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

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

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

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

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

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

L
Linus Torvalds 已提交
645
static int
646
xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
647
		    const struct xfrm_tmpl *tmpl,
648
		    const xfrm_address_t *daddr, const xfrm_address_t *saddr,
649
		    unsigned short family)
L
Linus Torvalds 已提交
650 651 652 653
{
	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
	if (!afinfo)
		return -1;
654 655 656 657 658 659 660 661 662
	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 已提交
663 664 665 666
	xfrm_state_put_afinfo(afinfo);
	return 0;
}

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

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

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

	return NULL;
}

692 693 694 695
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)
696
{
697
	unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
698 699
	struct xfrm_state *x;

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

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

	return NULL;
}

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

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

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

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

796 797
	to_put = NULL;

798 799
	sequence = read_seqcount_begin(&xfrm_state_hash_generation);

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

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

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

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

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

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

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

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

L
Linus Torvalds 已提交
912 913 914
	return x;
}

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

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


	return rx;
}
EXPORT_SYMBOL(xfrm_stateonly_find);

948 949 950 951 952 953 954 955 956 957 958 959 960 961
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);
962
		spin_unlock_bh(&net->xfrm.xfrm_state_lock);
963 964 965 966 967 968 969
		return x;
	}
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
	return NULL;
}
EXPORT_SYMBOL(xfrm_state_lookup_byspi);

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

975
	list_add(&x->km.all, &net->xfrm.state_all);
976

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

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

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

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

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

995
	net->xfrm.state_num++;
996

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

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

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

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

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

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

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

		xfrm_state_hold(x);
		return x;
	}

	if (!create)
		return NULL;

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

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

1101
		net->xfrm.state_num++;
1102

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

	return x;
}

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

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

	family = x->props.family;

1122 1123
	to_put = NULL;

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

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

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

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

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

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

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

1160 1161 1162
	if (to_put)
		xfrm_state_put(to_put);

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

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

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

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

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

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

1228 1229
	memcpy(&x->mark, &orig->mark, sizeof(x->mark));

1230
	if (xfrm_init_state(x) < 0)
1231 1232 1233
		goto error;

	x->props.flags = orig->props.flags;
1234
	x->props.extra_flags = orig->props.extra_flags;
1235

1236 1237 1238
	x->tfcpad = orig->tfcpad;
	x->replay_maxdiff = orig->replay_maxdiff;
	x->replay_maxage = orig->replay_maxage;
1239 1240 1241 1242 1243 1244 1245
	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 已提交
1246 1247
	xfrm_state_put(x);
out:
1248 1249 1250
	return NULL;
}

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

	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1257 1258

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

1292 1293 1294
	spin_unlock_bh(&net->xfrm.xfrm_state_lock);

	return x;
1295 1296 1297
}
EXPORT_SYMBOL(xfrm_migrate_state_find);

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

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

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

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

1335 1336
	to_put = NULL;

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

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

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

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

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

1359 1360 1361
	if (to_put)
		xfrm_state_put(to_put);

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

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

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

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

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

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

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

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

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

struct xfrm_state *
1450 1451 1452
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 已提交
1453 1454 1455
{
	struct xfrm_state *x;

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

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

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

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

1491 1492 1493
	if (!afinfo)
		return -EAFNOSUPPORT;

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

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

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

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

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

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

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

u32 xfrm_get_acqseq(void)
{
	u32 res;
1539 1540 1541 1542 1543
	static atomic_t acqseq;

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

	return res;
}
EXPORT_SYMBOL(xfrm_get_acqseq);

1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
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);

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

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

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

	err = -ENOENT;
L
Linus Torvalds 已提交
1592 1593

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

		err = 0;
L
Linus Torvalds 已提交
1619
	}
1620 1621 1622 1623 1624

unlock:
	spin_unlock_bh(&x->lock);

	return err;
L
Linus Torvalds 已提交
1625 1626 1627
}
EXPORT_SYMBOL(xfrm_alloc_spi);

1628
static bool __xfrm_state_filter_match(struct xfrm_state *x,
1629
				      struct xfrm_address_filter *filter)
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
{
	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;
}

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

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

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

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

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

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

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

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

	spin_lock(&x->lock);

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

	spin_unlock(&x->lock);
}

1727
static LIST_HEAD(xfrm_km_list);
L
Linus Torvalds 已提交
1728

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

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

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

EXPORT_SYMBOL(km_policy_notify);
EXPORT_SYMBOL(km_state_notify);

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

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

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

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

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

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

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

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

1812
#ifdef CONFIG_XFRM_MIGRATE
1813 1814 1815
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)
1816 1817 1818 1819 1820
{
	int err = -EINVAL;
	int ret;
	struct xfrm_mgr *km;

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

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

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

1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
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 已提交
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
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;
1891 1892
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1893
		pol = km->compile_policy(sk, optname, data,
L
Linus Torvalds 已提交
1894 1895 1896 1897
					 optlen, &err);
		if (err >= 0)
			break;
	}
1898
	rcu_read_unlock();
L
Linus Torvalds 已提交
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911

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

1912 1913
static DEFINE_SPINLOCK(xfrm_km_lock);

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

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

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

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

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

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

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

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

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

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

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

2065 2066
		if (x->props.family == AF_INET)
			iafamily = AF_INET6;
2067

2068 2069 2070 2071 2072 2073
		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);
2074 2075
		}
	}
2076

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

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

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

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

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

error:
	return err;
}

2103 2104 2105 2106 2107 2108 2109
EXPORT_SYMBOL(__xfrm_init_state);

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

H
Herbert Xu 已提交
2110
EXPORT_SYMBOL(xfrm_init_state);
2111

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

2116 2117
	INIT_LIST_HEAD(&net->xfrm.state_all);

2118 2119
	sz = sizeof(struct hlist_head) * 8;

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

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

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

void xfrm_state_fini(struct net *net)
{
2148 2149
	unsigned int sz;

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

2154
	WARN_ON(!list_empty(&net->xfrm.state_all));
2155

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

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

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

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

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

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

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

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

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

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

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

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

2260
void xfrm_audit_state_replay(struct xfrm_state *x,
P
Paul Moore 已提交
2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
			     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);
}
2275
EXPORT_SYMBOL_GPL(xfrm_audit_state_replay);
P
Paul Moore 已提交
2276 2277 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

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 已提交
2325
#endif /* CONFIG_AUDITSYSCALL */