diff options
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 97 |
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 @@ | |||
26 | static struct dst_ops xfrm6_dst_ops; | 27 | static struct dst_ops xfrm6_dst_ops; |
27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 28 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
28 | 29 | ||
29 | static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl) | 30 | static 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 | ||
40 | static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | 52 | static 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 | ||
60 | static struct dst_entry * | 66 | static 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 | ||
90 | static 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 | |||
96 | static 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 | } |