aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r--net/ipv6/xfrm6_policy.c97
1 files changed, 35 insertions, 62 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 3b38e493d151..8e78530865a6 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -11,7 +11,8 @@
11 * 11 *
12 */ 12 */
13 13
14#include <linux/compiler.h> 14#include <linux/err.h>
15#include <linux/kernel.h>
15#include <linux/netdevice.h> 16#include <linux/netdevice.h>
16#include <net/addrconf.h> 17#include <net/addrconf.h>
17#include <net/dst.h> 18#include <net/dst.h>
@@ -26,35 +27,40 @@
26static struct dst_ops xfrm6_dst_ops; 27static struct dst_ops xfrm6_dst_ops;
27static struct xfrm_policy_afinfo xfrm6_policy_afinfo; 28static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
28 29
29static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl) 30static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
31 xfrm_address_t *daddr)
30{ 32{
31 struct dst_entry *dst = ip6_route_output(NULL, fl); 33 struct flowi fl = {};
32 int err = dst->error; 34 struct dst_entry *dst;
33 if (!err) 35 int err;
34 *xdst = (struct xfrm_dst *) dst; 36
35 else 37 memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst));
38 if (saddr)
39 memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
40
41 dst = ip6_route_output(NULL, &fl);
42
43 err = dst->error;
44 if (dst->error) {
36 dst_release(dst); 45 dst_release(dst);
37 return err; 46 dst = ERR_PTR(err);
47 }
48
49 return dst;
38} 50}
39 51
40static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) 52static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
41{ 53{
42 struct rt6_info *rt; 54 struct dst_entry *dst;
43 struct flowi fl_tunnel = { 55
44 .nl_u = { 56 dst = xfrm6_dst_lookup(0, NULL, daddr);
45 .ip6_u = { 57 if (IS_ERR(dst))
46 .daddr = *(struct in6_addr *)&daddr->a6, 58 return -EHOSTUNREACH;
47 }, 59
48 }, 60 ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
49 }; 61 (struct in6_addr *)&saddr->a6);
50 62 dst_release(dst);
51 if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { 63 return 0;
52 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
53 (struct in6_addr *)&saddr->a6);
54 dst_release(&rt->u.dst);
55 return 0;
56 }
57 return -EHOSTUNREACH;
58} 64}
59 65
60static struct dst_entry * 66static struct dst_entry *
@@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
87 return dst; 93 return dst;
88} 94}
89 95
90static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
91{
92 return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
93 &x->id.daddr;
94}
95
96static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
97{
98 return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
99 &x->props.saddr;
100}
101
102/* Allocate chain of dst_entry's, attach known xfrm's, calculate 96/* Allocate chain of dst_entry's, attach known xfrm's, calculate
103 * all the metrics... Shortly, bundle a bundle. 97 * all the metrics... Shortly, bundle a bundle.
104 */ 98 */
@@ -110,14 +104,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
110 struct dst_entry *dst, *dst_prev; 104 struct dst_entry *dst, *dst_prev;
111 struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); 105 struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
112 struct rt6_info *rt = rt0; 106 struct rt6_info *rt = rt0;
113 struct flowi fl_tunnel = {
114 .nl_u = {
115 .ip6_u = {
116 .saddr = fl->fl6_src,
117 .daddr = fl->fl6_dst,
118 }
119 }
120 };
121 int i; 107 int i;
122 int err; 108 int err;
123 int header_len = 0; 109 int header_len = 0;
@@ -160,25 +146,12 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
160 trailer_len += xfrm[i]->props.trailer_len; 146 trailer_len += xfrm[i]->props.trailer_len;
161 147
162 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { 148 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
163 unsigned short encap_family = xfrm[i]->props.family; 149 dst1 = xfrm_dst_lookup(xfrm[i], 0);
164 switch(encap_family) { 150 err = PTR_ERR(dst1);
165 case AF_INET: 151 if (IS_ERR(dst1))
166 fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
167 fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
168 break;
169 case AF_INET6:
170 ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
171
172 ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
173 break;
174 default:
175 BUG_ON(1);
176 }
177
178 err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
179 &fl_tunnel, encap_family);
180 if (err)
181 goto error; 152 goto error;
153
154 rt = (struct rt6_info *)dst1;
182 } else 155 } else
183 dst_hold(&rt->u.dst); 156 dst_hold(&rt->u.dst);
184 } 157 }