Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c44e6b7 authored by Masahide NAKAMURA's avatar Masahide NAKAMURA Committed by David S. Miller
Browse files

[XFRM] STATE: Add source address list.



Support source address based searching.
Mobile IPv6 will use it.
Based on MIPL2 kernel patch.

Signed-off-by: default avatarMasahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 622dc828
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ struct xfrm_state
{
	/* Note: bydst is re-used during gc */
	struct list_head	bydst;
	struct list_head	bysrc;
	struct list_head	byspi;

	atomic_t		refcnt;
@@ -236,6 +237,7 @@ extern int __xfrm_state_delete(struct xfrm_state *x);
struct xfrm_state_afinfo {
	unsigned short		family;
	struct list_head	*state_bydst;
	struct list_head	*state_bysrc;
	struct list_head	*state_byspi;
	int			(*init_flags)(struct xfrm_state *x);
	void			(*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
@@ -420,6 +422,30 @@ unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
	return 0;
}

static __inline__
unsigned __xfrm4_src_hash(xfrm_address_t *addr)
{
	return __xfrm4_dst_hash(addr);
}

static __inline__
unsigned __xfrm6_src_hash(xfrm_address_t *addr)
{
	return __xfrm6_dst_hash(addr);
}

static __inline__
unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family)
{
	switch (family) {
	case AF_INET:
		return __xfrm4_src_hash(addr);
	case AF_INET6:
		return __xfrm6_src_hash(addr);
	}
	return 0;
}

static __inline__
unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
{
+3 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
		add_timer(&x0->timer);
		xfrm_state_hold(x0);
		list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h);
		h = __xfrm4_src_hash(saddr);
		xfrm_state_hold(x0);
		list_add_tail(&x0->bysrc, xfrm4_state_afinfo.state_bysrc+h);
		wake_up(&km_waitq);
	}
	if (x0)
+3 −0
Original line number Diff line number Diff line
@@ -126,6 +126,9 @@ __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
		add_timer(&x0->timer);
		xfrm_state_hold(x0);
		list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
		h = __xfrm6_src_hash(saddr);
		xfrm_state_hold(x0);
		list_add_tail(&x0->bysrc, xfrm6_state_afinfo.state_bysrc+h);
		wake_up(&km_waitq);
	}
	if (x0)
+19 −2
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
 * Also, it can be used by ah/esp icmp error handler to find offending SA.
 */
static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE];
static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];

DECLARE_WAIT_QUEUE_HEAD(km_waitq);
@@ -200,6 +201,7 @@ struct xfrm_state *xfrm_state_alloc(void)
		atomic_set(&x->refcnt, 1);
		atomic_set(&x->tunnel_users, 0);
		INIT_LIST_HEAD(&x->bydst);
		INIT_LIST_HEAD(&x->bysrc);
		INIT_LIST_HEAD(&x->byspi);
		init_timer(&x->timer);
		x->timer.function = xfrm_timer_handler;
@@ -240,6 +242,8 @@ int __xfrm_state_delete(struct xfrm_state *x)
		spin_lock(&xfrm_state_lock);
		list_del(&x->bydst);
		__xfrm_state_put(x);
		list_del(&x->bysrc);
		__xfrm_state_put(x);
		if (x->id.spi) {
			list_del(&x->byspi);
			__xfrm_state_put(x);
@@ -415,6 +419,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
			x->km.state = XFRM_STATE_ACQ;
			list_add_tail(&x->bydst, xfrm_state_bydst+h);
			xfrm_state_hold(x);
			list_add_tail(&x->bysrc, xfrm_state_bysrc+h);
			xfrm_state_hold(x);
			if (x->id.spi) {
				h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
				list_add(&x->byspi, xfrm_state_byspi+h);
@@ -448,10 +454,18 @@ static void __xfrm_state_insert(struct xfrm_state *x)
	list_add(&x->bydst, xfrm_state_bydst+h);
	xfrm_state_hold(x);

	h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
	h = xfrm_src_hash(&x->props.saddr, x->props.family);

	list_add(&x->bysrc, xfrm_state_bysrc+h);
	xfrm_state_hold(x);

	if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) {
		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
				  x->props.family);

		list_add(&x->byspi, xfrm_state_byspi+h);
		xfrm_state_hold(x);
	}

	if (!mod_timer(&x->timer, jiffies + HZ))
		xfrm_state_hold(x);
@@ -1075,6 +1089,7 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
		err = -ENOBUFS;
	else {
		afinfo->state_bydst = xfrm_state_bydst;
		afinfo->state_bysrc = xfrm_state_bysrc;
		afinfo->state_byspi = xfrm_state_byspi;
		xfrm_state_afinfo[afinfo->family] = afinfo;
	}
@@ -1097,6 +1112,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
		else {
			xfrm_state_afinfo[afinfo->family] = NULL;
			afinfo->state_byspi = NULL;
			afinfo->state_bysrc = NULL;
			afinfo->state_bydst = NULL;
		}
	}
@@ -1218,6 +1234,7 @@ void __init xfrm_state_init(void)

	for (i=0; i<XFRM_DST_HSIZE; i++) {
		INIT_LIST_HEAD(&xfrm_state_bydst[i]);
		INIT_LIST_HEAD(&xfrm_state_bysrc[i]);
		INIT_LIST_HEAD(&xfrm_state_byspi[i]);
	}
	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);