[IPSEC]: Move flow construction into xfrm_dst_lookup
authorHerbert Xu <herbert@gondor.apana.org.au>
Wed, 14 Nov 2007 05:37:28 +0000 (21:37 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 22:53:42 +0000 (14:53 -0800)
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>
include/net/xfrm.h
net/ipv4/xfrm4_policy.c
net/ipv6/xfrm6_policy.c
net/xfrm/xfrm_policy.c

index 3434fdc7de37db524c065b0a21ca1f2bcae953ab..d427343f527b5d14ef2e7f6348ffa86fc6649efc 100644 (file)
@@ -233,7 +233,8 @@ struct xfrm_policy_afinfo {
        unsigned short          family;
        struct dst_ops          *dst_ops;
        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);
        struct dst_entry        *(*find_bundle)(struct flowi *fl, 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
 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_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
 #else
 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);
        return 0;
 }
-
-static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family)
-{
-       return -EINVAL;
-} 
 #endif
 
+extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
 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 *);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
index d903c8bdffcd15a2832d95b73a77a5ad201662bb..cebc847319692ac9f5f486de074516ffaf8459c1 100644 (file)
@@ -8,7 +8,8 @@
  *
  */
 
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
 #include <linux/inetdevice.h>
 #include <net/dst.h>
 #include <net/xfrm.h>
 static struct dst_ops xfrm4_dst_ops;
 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);
-}
-
-static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
-{
-       struct rtable *rt;
-       struct flowi fl_tunnel = {
+       struct flowi fl = {
                .nl_u = {
                        .ip4_u = {
+                               .tos = tos,
                                .daddr = daddr->a4,
                        },
                },
        };
+       struct dst_entry *dst;
+       struct rtable *rt;
+       int err;
 
-       if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
-               saddr->a4 = rt->rt_src;
-               dst_release(&rt->u.dst);
-               return 0;
-       }
-       return -EHOSTUNREACH;
+       if (saddr)
+               fl.fl4_src = saddr->a4;
+
+       err = __ip_route_output_key(&rt, &fl);
+       dst = &rt->u.dst;
+       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 *
@@ -73,15 +90,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
        struct dst_entry *dst, *dst_prev;
        struct rtable *rt0 = (struct rtable*)(*dst_p);
        struct rtable *rt = rt0;
-       struct flowi fl_tunnel = {
-               .nl_u = {
-                       .ip4_u = {
-                               .saddr = fl->fl4_src,
-                               .daddr = fl->fl4_dst,
-                               .tos = fl->fl4_tos
-                       }
-               }
-       };
+       int tos = fl->fl4_tos;
        int i;
        int err;
        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;
 
                if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-                       unsigned short encap_family = xfrm[i]->props.family;
-                       switch (encap_family) {
-                       case AF_INET:
-                               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)
+                       dst1 = xfrm_dst_lookup(xfrm[i], tos);
+                       err = PTR_ERR(dst1);
+                       if (IS_ERR(dst1))
                                goto error;
+
+                       rt = (struct rtable *)dst1;
                } else
                        dst_hold(&rt->u.dst);
        }
index 3b38e493d151c7048e21c29858deebf2dc1cba89..8e78530865a62b1d04f0d0632150204e612f50ad 100644 (file)
@@ -11,7 +11,8 @@
  *
  */
 
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <net/addrconf.h>
 #include <net/dst.h>
 static struct dst_ops xfrm6_dst_ops;
 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);
-       int err = dst->error;
-       if (!err)
-               *xdst = (struct xfrm_dst *) dst;
-       else
+       struct flowi fl = {};
+       struct dst_entry *dst;
+       int err;
+
+       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);
-       return err;
+               dst = ERR_PTR(err);
+       }
+
+       return dst;
 }
 
 static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
 {
-       struct rt6_info *rt;
-       struct flowi fl_tunnel = {
-               .nl_u = {
-                       .ip6_u = {
-                               .daddr = *(struct in6_addr *)&daddr->a6,
-                       },
-               },
-       };
-
-       if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
-               ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
-                              (struct in6_addr *)&saddr->a6);
-               dst_release(&rt->u.dst);
-               return 0;
-       }
-       return -EHOSTUNREACH;
+       struct dst_entry *dst;
+
+       dst = xfrm6_dst_lookup(0, NULL, daddr);
+       if (IS_ERR(dst))
+               return -EHOSTUNREACH;
+
+       ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
+                      (struct in6_addr *)&saddr->a6);
+       dst_release(dst);
+       return 0;
 }
 
 static struct dst_entry *
@@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
        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
  * 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 rt6_info *rt0 = (struct rt6_info*)(*dst_p);
        struct rt6_info *rt  = rt0;
-       struct flowi fl_tunnel = {
-               .nl_u = {
-                       .ip6_u = {
-                               .saddr = fl->fl6_src,
-                               .daddr = fl->fl6_dst,
-                       }
-               }
-       };
        int i;
        int err;
        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;
 
                if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-                       unsigned short encap_family = xfrm[i]->props.family;
-                       switch(encap_family) {
-                       case AF_INET:
-                               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)
+                       dst1 = xfrm_dst_lookup(xfrm[i], 0);
+                       err = PTR_ERR(dst1);
+                       if (IS_ERR(dst1))
                                goto error;
+
+                       rt = (struct rt6_info *)dst1;
                } else
                        dst_hold(&rt->u.dst);
        }
index df5bfa837eb363d2a4caac212d9ea1543cb74bd7..085c19d4d1b7bb6c0b32ab7a26d9e5a4b3533468 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/list.h>
@@ -84,21 +85,25 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
        return 0;
 }
 
-int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
-                   unsigned short family)
+struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
 {
-       struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
-       int err = 0;
+       xfrm_address_t *saddr = &x->props.saddr;
+       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))
-               return -EAFNOSUPPORT;
+               return ERR_PTR(-EAFNOSUPPORT);
 
-       if (likely(afinfo->dst_lookup != NULL))
-               err = afinfo->dst_lookup(dst, fl);
-       else
-               err = -EINVAL;
+       dst = afinfo->dst_lookup(tos, saddr, daddr);
        xfrm_policy_put_afinfo(afinfo);
-       return err;
+       return dst;
 }
 EXPORT_SYMBOL(xfrm_dst_lookup);