This is a support to search transformation states by its addresses
by using source address list.
For Mobile IPv6 usage.
Based on MIPL2 kernel patch.
---
include/net/xfrm.h | 11 +++++++++++
net/ipv4/xfrm4_state.c | 13 +++++++++++++
net/ipv6/xfrm6_state.c | 25 ++++++++++++++++++++++++
net/xfrm/xfrm_state.c | 49 +++++++++++++++++++++++++++++++++++++++++++-----
net/xfrm/xfrm_user.c | 13 +++++++++++--
5 files changed, 104 insertions(+), 7 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 75649da..aaef1c4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -247,6 +247,9 @@ #endif
struct xfrm_tmpl *tmpl,
xfrm_address_t *daddr,
xfrm_address_t *saddr);
struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32
spi, u8 proto);
+#ifdef CONFIG_XFRM_ADVANCED
+ struct xfrm_state *(*state_lookup_byaddr)(xfrm_address_t *daddr,
xfrm_address_t *saddr, u8 proto);
+#endif
struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr,
xfrm_address_t *saddr,
int create);
@@ -930,6 +933,14 @@ extern void xfrm_state_insert(struct xfr
extern int xfrm_state_add(struct xfrm_state *x);
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8
proto, unsigned short family);
+#ifdef CONFIG_XFRM_ADVANCED
+extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr,
xfrm_address_t *saddr, u8 proto, unsigned short family);
+#else
+static inline struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t
*daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
+{
+ return NULL;
+}
+#endif
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
extern int xfrm_state_delete(struct xfrm_state *x);
extern void xfrm_state_flush(u8 proto);
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 6de2ce0..8b44a75 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -80,6 +80,16 @@ __xfrm4_state_lookup(xfrm_address_t *dad
return NULL;
}
+#ifdef CONFIG_XFRM_ADVANCED
+/* placeholder until ipv4's code is written */
+static struct xfrm_state *
+__xfrm4_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ u8 proto)
+{
+ return NULL;
+}
+#endif
+
static struct xfrm_state *
__xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr, xfrm_address_t *saddr,
@@ -140,6 +150,9 @@ static struct xfrm_state_afinfo xfrm4_st
.init_flags = xfrm4_init_flags,
.init_tempsel = __xfrm4_init_tempsel,
.state_lookup = __xfrm4_state_lookup,
+#ifdef CONFIG_XFRM_ADVANCED
+ .state_lookup_byaddr = __xfrm4_state_lookup_byaddr,
+#endif
.find_acq = __xfrm4_find_acq,
};
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 00b6c17..d141030 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -63,6 +63,28 @@ __xfrm6_init_tempsel(struct xfrm_state *
x->props.family = AF_INET6;
}
+#ifdef CONFIG_XFRM_ADVANCED
+static struct xfrm_state *
+__xfrm6_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ u8 proto)
+{
+ struct xfrm_state *x = NULL;
+ unsigned h;
+
+ h = __xfrm6_src_hash(saddr);
+ list_for_each_entry(x, xfrm6_state_afinfo.state_bysrc+h, bysrc) {
+ if (x->props.family == AF_INET6 &&
+ ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr
*)x->id.daddr.a6) &&
+ ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr
*)x->props.saddr.a6) &&
+ proto == x->id.proto) {
+ xfrm_state_hold(x);
+ return x;
+ }
+ }
+ return NULL;
+}
+#endif
+
static struct xfrm_state *
__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
{
@@ -143,6 +165,9 @@ static struct xfrm_state_afinfo xfrm6_st
.lock = RW_LOCK_UNLOCKED,
.init_tempsel = __xfrm6_init_tempsel,
.state_lookup = __xfrm6_state_lookup,
+#ifdef CONFIG_XFRM_ADVANCED
+ .state_lookup_byaddr = __xfrm6_state_lookup_byaddr,
+#endif
.find_acq = __xfrm6_find_acq,
};
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 1942bb1..1eedb85 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -501,6 +501,11 @@ int xfrm_state_add(struct xfrm_state *x)
struct xfrm_state *x1;
int family;
int err;
+#ifdef CONFIG_XFRM_ADVANCED
+ int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+#else
+ int use_spi = 1;
+#endif
family = x->props.family;
afinfo = xfrm_state_get_afinfo(family);
@@ -509,7 +514,12 @@ int xfrm_state_add(struct xfrm_state *x)
spin_lock_bh(&xfrm_state_lock);
- x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
+ if (use_spi)
+ x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
+#ifdef CONFIG_XFRM_ADVANCED
+ else
+ x1 = afinfo->state_lookup_byaddr(&x->id.daddr, &x->props.saddr,
x->id.proto);
+#endif
if (x1) {
xfrm_state_put(x1);
x1 = NULL;
@@ -517,7 +527,7 @@ int xfrm_state_add(struct xfrm_state *x)
goto out;
}
- if (x->km.seq) {
+ if (use_spi && x->km.seq) {
x1 = __xfrm_find_acq_byseq(x->km.seq);
if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) {
xfrm_state_put(x1);
@@ -525,7 +535,7 @@ int xfrm_state_add(struct xfrm_state *x)
}
}
- if (!x1)
+ if (use_spi && !x1)
x1 = afinfo->find_acq(
x->props.mode, x->props.reqid, x->id.proto,
&x->id.daddr, &x->props.saddr, 0);
@@ -552,15 +562,25 @@ EXPORT_SYMBOL(xfrm_state_add);
int xfrm_state_update(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
- struct xfrm_state *x1;
+ struct xfrm_state *x1 = NULL;
int err;
+#ifdef CONFIG_XFRM_ADVANCED
+ int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+#else
+ int use_spi = 1;
+#endif
afinfo = xfrm_state_get_afinfo(x->props.family);
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_state_lock);
- x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
+ if (use_spi)
+ x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
+#ifdef CONFIG_XFRM_ADVANCED
+ else
+ x1 = afinfo->state_lookup_byaddr(&x->id.daddr, &x->props.saddr,
x->id.proto);
+#endif
err = -ESRCH;
if (!x1)
@@ -680,6 +700,25 @@ xfrm_state_lookup(xfrm_address_t *daddr,
}
EXPORT_SYMBOL(xfrm_state_lookup);
+#ifdef CONFIG_XFRM_ADVANCED
+struct xfrm_state *
+xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ u8 proto, unsigned short family)
+{
+ struct xfrm_state *x;
+ struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
+ if (!afinfo)
+ return NULL;
+
+ spin_lock_bh(&xfrm_state_lock);
+ x = afinfo->state_lookup_byaddr(daddr, saddr, proto);
+ spin_unlock_bh(&xfrm_state_lock);
+ xfrm_state_put_afinfo(afinfo);
+ return x;
+}
+EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
+#endif
+
struct xfrm_state *
xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr, xfrm_address_t *saddr,
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index f92d163..85051a2 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -416,6 +416,15 @@ out:
return err;
}
+static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p)
+{
+ if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY))
+ return xfrm_state_lookup(&p->daddr, p->spi, p->proto,
p->family);
+ else
+ return xfrm_state_lookup_byaddr(&p->daddr, &p->saddr, p->proto,
+ p->family);
+}
+
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
@@ -423,7 +432,7 @@ static int xfrm_del_sa(struct sk_buff *s
struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
- x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+ x = xfrm_user_state_lookup(p);
if (x == NULL)
return -ESRCH;
@@ -576,7 +585,7 @@ static int xfrm_get_sa(struct sk_buff *s
struct sk_buff *resp_skb;
int err;
- x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+ x = xfrm_user_state_lookup(p);
err = -ESRCH;
if (x == NULL)
goto out_noput;
--
1.4.1
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html