forked from Minki/linux
[IPSEC]: Move flow construction into xfrm_dst_lookup
This patch moves the flow construction from the callers of xfrm_dst_lookup into that function. It also changes xfrm_dst_lookup so that it takes an xfrm state as its argument instead of explicit addresses. This removes any address-specific logic from the callers of xfrm_dst_lookup which is needed to correctly support inter-family transforms. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f04e7e8d7f
commit
66cdb3ca27
@ -233,7 +233,8 @@ struct xfrm_policy_afinfo {
|
|||||||
unsigned short family;
|
unsigned short family;
|
||||||
struct dst_ops *dst_ops;
|
struct dst_ops *dst_ops;
|
||||||
void (*garbage_collect)(void);
|
void (*garbage_collect)(void);
|
||||||
int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
|
struct dst_entry *(*dst_lookup)(int tos, xfrm_address_t *saddr,
|
||||||
|
xfrm_address_t *daddr);
|
||||||
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
|
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
|
||||||
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
|
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
|
||||||
int (*bundle_create)(struct xfrm_policy *policy,
|
int (*bundle_create)(struct xfrm_policy *policy,
|
||||||
@ -1079,7 +1080,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
|
|||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
|
extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
|
||||||
extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
|
extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
|
||||||
extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
|
|
||||||
#else
|
#else
|
||||||
static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
|
static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
|
||||||
{
|
{
|
||||||
@ -1092,13 +1092,9 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
|
|||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family)
|
|
||||||
{
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
|
||||||
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
|
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
|
||||||
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
|
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
|
||||||
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
|
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
#include <net/dst.h>
|
#include <net/dst.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
@ -17,28 +18,44 @@
|
|||||||
static struct dst_ops xfrm4_dst_ops;
|
static struct dst_ops xfrm4_dst_ops;
|
||||||
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
|
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
|
||||||
|
|
||||||
static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
|
static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr,
|
||||||
|
xfrm_address_t *daddr)
|
||||||
{
|
{
|
||||||
return __ip_route_output_key((struct rtable**)dst, fl);
|
struct flowi fl = {
|
||||||
}
|
|
||||||
|
|
||||||
static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
|
||||||
{
|
|
||||||
struct rtable *rt;
|
|
||||||
struct flowi fl_tunnel = {
|
|
||||||
.nl_u = {
|
.nl_u = {
|
||||||
.ip4_u = {
|
.ip4_u = {
|
||||||
|
.tos = tos,
|
||||||
.daddr = daddr->a4,
|
.daddr = daddr->a4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
struct dst_entry *dst;
|
||||||
|
struct rtable *rt;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
|
if (saddr)
|
||||||
saddr->a4 = rt->rt_src;
|
fl.fl4_src = saddr->a4;
|
||||||
dst_release(&rt->u.dst);
|
|
||||||
return 0;
|
err = __ip_route_output_key(&rt, &fl);
|
||||||
}
|
dst = &rt->u.dst;
|
||||||
return -EHOSTUNREACH;
|
if (err)
|
||||||
|
dst = ERR_PTR(err);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
||||||
|
{
|
||||||
|
struct dst_entry *dst;
|
||||||
|
struct rtable *rt;
|
||||||
|
|
||||||
|
dst = xfrm4_dst_lookup(0, NULL, daddr);
|
||||||
|
if (IS_ERR(dst))
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
|
||||||
|
rt = (struct rtable *)dst;
|
||||||
|
saddr->a4 = rt->rt_src;
|
||||||
|
dst_release(dst);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dst_entry *
|
static struct dst_entry *
|
||||||
@ -73,15 +90,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
|
|||||||
struct dst_entry *dst, *dst_prev;
|
struct dst_entry *dst, *dst_prev;
|
||||||
struct rtable *rt0 = (struct rtable*)(*dst_p);
|
struct rtable *rt0 = (struct rtable*)(*dst_p);
|
||||||
struct rtable *rt = rt0;
|
struct rtable *rt = rt0;
|
||||||
struct flowi fl_tunnel = {
|
int tos = fl->fl4_tos;
|
||||||
.nl_u = {
|
|
||||||
.ip4_u = {
|
|
||||||
.saddr = fl->fl4_src,
|
|
||||||
.daddr = fl->fl4_dst,
|
|
||||||
.tos = fl->fl4_tos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int i;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
int header_len = 0;
|
int header_len = 0;
|
||||||
@ -119,25 +128,12 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
|
|||||||
trailer_len += xfrm[i]->props.trailer_len;
|
trailer_len += xfrm[i]->props.trailer_len;
|
||||||
|
|
||||||
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
|
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
|
||||||
unsigned short encap_family = xfrm[i]->props.family;
|
dst1 = xfrm_dst_lookup(xfrm[i], tos);
|
||||||
switch (encap_family) {
|
err = PTR_ERR(dst1);
|
||||||
case AF_INET:
|
if (IS_ERR(dst1))
|
||||||
fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
|
|
||||||
fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
|
|
||||||
break;
|
|
||||||
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
|
|
||||||
case AF_INET6:
|
|
||||||
ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
|
|
||||||
ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
BUG_ON(1);
|
|
||||||
}
|
|
||||||
err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
|
|
||||||
&fl_tunnel, encap_family);
|
|
||||||
if (err)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
rt = (struct rtable *)dst1;
|
||||||
} else
|
} else
|
||||||
dst_hold(&rt->u.dst);
|
dst_hold(&rt->u.dst);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
#include <net/dst.h>
|
#include <net/dst.h>
|
||||||
@ -26,35 +27,40 @@
|
|||||||
static struct dst_ops xfrm6_dst_ops;
|
static struct dst_ops xfrm6_dst_ops;
|
||||||
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
|
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
|
||||||
|
|
||||||
static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
|
static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
|
||||||
|
xfrm_address_t *daddr)
|
||||||
{
|
{
|
||||||
struct dst_entry *dst = ip6_route_output(NULL, fl);
|
struct flowi fl = {};
|
||||||
int err = dst->error;
|
struct dst_entry *dst;
|
||||||
if (!err)
|
int err;
|
||||||
*xdst = (struct xfrm_dst *) dst;
|
|
||||||
else
|
memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst));
|
||||||
|
if (saddr)
|
||||||
|
memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
|
||||||
|
|
||||||
|
dst = ip6_route_output(NULL, &fl);
|
||||||
|
|
||||||
|
err = dst->error;
|
||||||
|
if (dst->error) {
|
||||||
dst_release(dst);
|
dst_release(dst);
|
||||||
return err;
|
dst = ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
||||||
{
|
{
|
||||||
struct rt6_info *rt;
|
struct dst_entry *dst;
|
||||||
struct flowi fl_tunnel = {
|
|
||||||
.nl_u = {
|
|
||||||
.ip6_u = {
|
|
||||||
.daddr = *(struct in6_addr *)&daddr->a6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
|
dst = xfrm6_dst_lookup(0, NULL, daddr);
|
||||||
ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
|
if (IS_ERR(dst))
|
||||||
(struct in6_addr *)&saddr->a6);
|
return -EHOSTUNREACH;
|
||||||
dst_release(&rt->u.dst);
|
|
||||||
return 0;
|
ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
|
||||||
}
|
(struct in6_addr *)&saddr->a6);
|
||||||
return -EHOSTUNREACH;
|
dst_release(dst);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dst_entry *
|
static struct dst_entry *
|
||||||
@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
|
|
||||||
{
|
|
||||||
return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
|
|
||||||
&x->id.daddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
|
|
||||||
{
|
|
||||||
return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
|
|
||||||
&x->props.saddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
|
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
|
||||||
* all the metrics... Shortly, bundle a bundle.
|
* all the metrics... Shortly, bundle a bundle.
|
||||||
*/
|
*/
|
||||||
@ -110,14 +104,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
|
|||||||
struct dst_entry *dst, *dst_prev;
|
struct dst_entry *dst, *dst_prev;
|
||||||
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
|
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
|
||||||
struct rt6_info *rt = rt0;
|
struct rt6_info *rt = rt0;
|
||||||
struct flowi fl_tunnel = {
|
|
||||||
.nl_u = {
|
|
||||||
.ip6_u = {
|
|
||||||
.saddr = fl->fl6_src,
|
|
||||||
.daddr = fl->fl6_dst,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int i;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
int header_len = 0;
|
int header_len = 0;
|
||||||
@ -160,25 +146,12 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
|
|||||||
trailer_len += xfrm[i]->props.trailer_len;
|
trailer_len += xfrm[i]->props.trailer_len;
|
||||||
|
|
||||||
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
|
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
|
||||||
unsigned short encap_family = xfrm[i]->props.family;
|
dst1 = xfrm_dst_lookup(xfrm[i], 0);
|
||||||
switch(encap_family) {
|
err = PTR_ERR(dst1);
|
||||||
case AF_INET:
|
if (IS_ERR(dst1))
|
||||||
fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
|
|
||||||
fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
|
|
||||||
|
|
||||||
ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG_ON(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
|
|
||||||
&fl_tunnel, encap_family);
|
|
||||||
if (err)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
rt = (struct rt6_info *)dst1;
|
||||||
} else
|
} else
|
||||||
dst_hold(&rt->u.dst);
|
dst_hold(&rt->u.dst);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
@ -84,21 +85,25 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
|
struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
|
||||||
unsigned short family)
|
|
||||||
{
|
{
|
||||||
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
xfrm_address_t *saddr = &x->props.saddr;
|
||||||
int err = 0;
|
xfrm_address_t *daddr = &x->id.daddr;
|
||||||
|
struct xfrm_policy_afinfo *afinfo;
|
||||||
|
struct dst_entry *dst;
|
||||||
|
|
||||||
|
if (x->type->flags & XFRM_TYPE_LOCAL_COADDR)
|
||||||
|
saddr = x->coaddr;
|
||||||
|
if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
|
||||||
|
daddr = x->coaddr;
|
||||||
|
|
||||||
|
afinfo = xfrm_policy_get_afinfo(x->props.family);
|
||||||
if (unlikely(afinfo == NULL))
|
if (unlikely(afinfo == NULL))
|
||||||
return -EAFNOSUPPORT;
|
return ERR_PTR(-EAFNOSUPPORT);
|
||||||
|
|
||||||
if (likely(afinfo->dst_lookup != NULL))
|
dst = afinfo->dst_lookup(tos, saddr, daddr);
|
||||||
err = afinfo->dst_lookup(dst, fl);
|
|
||||||
else
|
|
||||||
err = -EINVAL;
|
|
||||||
xfrm_policy_put_afinfo(afinfo);
|
xfrm_policy_put_afinfo(afinfo);
|
||||||
return err;
|
return dst;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xfrm_dst_lookup);
|
EXPORT_SYMBOL(xfrm_dst_lookup);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user