diff options
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8dffd4daae9c..b1133f27c8ae 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * IPv6 support | 8 | * IPv6 support |
9 | * YOSHIFUJI Hideaki | 9 | * YOSHIFUJI Hideaki |
10 | * Split up af-specific portion | 10 | * Split up af-specific portion |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/compiler.h> | 14 | #include <linux/compiler.h> |
@@ -131,13 +131,11 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
131 | struct dst_entry *dst, *dst_prev; | 131 | struct dst_entry *dst, *dst_prev; |
132 | struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); | 132 | struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); |
133 | struct rt6_info *rt = rt0; | 133 | struct rt6_info *rt = rt0; |
134 | struct in6_addr *remote = &fl->fl6_dst; | ||
135 | struct in6_addr *local = &fl->fl6_src; | ||
136 | struct flowi fl_tunnel = { | 134 | struct flowi fl_tunnel = { |
137 | .nl_u = { | 135 | .nl_u = { |
138 | .ip6_u = { | 136 | .ip6_u = { |
139 | .saddr = *local, | 137 | .saddr = fl->fl6_src, |
140 | .daddr = *remote | 138 | .daddr = fl->fl6_dst, |
141 | } | 139 | } |
142 | } | 140 | } |
143 | }; | 141 | }; |
@@ -153,7 +151,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
153 | for (i = 0; i < nx; i++) { | 151 | for (i = 0; i < nx; i++) { |
154 | struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops); | 152 | struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops); |
155 | struct xfrm_dst *xdst; | 153 | struct xfrm_dst *xdst; |
156 | int tunnel = 0; | ||
157 | 154 | ||
158 | if (unlikely(dst1 == NULL)) { | 155 | if (unlikely(dst1 == NULL)) { |
159 | err = -ENOBUFS; | 156 | err = -ENOBUFS; |
@@ -177,19 +174,29 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
177 | 174 | ||
178 | dst1->next = dst_prev; | 175 | dst1->next = dst_prev; |
179 | dst_prev = dst1; | 176 | dst_prev = dst1; |
180 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 177 | |
181 | remote = __xfrm6_bundle_addr_remote(xfrm[i], remote); | ||
182 | local = __xfrm6_bundle_addr_local(xfrm[i], local); | ||
183 | tunnel = 1; | ||
184 | } | ||
185 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); | 178 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); |
186 | trailer_len += xfrm[i]->props.trailer_len; | 179 | trailer_len += xfrm[i]->props.trailer_len; |
187 | 180 | ||
188 | if (tunnel) { | 181 | if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL || |
189 | ipv6_addr_copy(&fl_tunnel.fl6_dst, remote); | 182 | xfrm[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) { |
190 | ipv6_addr_copy(&fl_tunnel.fl6_src, local); | 183 | unsigned short encap_family = xfrm[i]->props.family; |
184 | switch(encap_family) { | ||
185 | case AF_INET: | ||
186 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
187 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
188 | break; | ||
189 | case AF_INET6: | ||
190 | ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst)); | ||
191 | |||
192 | ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_src)); | ||
193 | break; | ||
194 | default: | ||
195 | BUG_ON(1); | ||
196 | } | ||
197 | |||
191 | err = xfrm_dst_lookup((struct xfrm_dst **) &rt, | 198 | err = xfrm_dst_lookup((struct xfrm_dst **) &rt, |
192 | &fl_tunnel, AF_INET6); | 199 | &fl_tunnel, encap_family); |
193 | if (err) | 200 | if (err) |
194 | goto error; | 201 | goto error; |
195 | } else | 202 | } else |
@@ -208,6 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
208 | i = 0; | 215 | i = 0; |
209 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 216 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
210 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 217 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
218 | struct xfrm_state_afinfo *afinfo; | ||
211 | 219 | ||
212 | dst_prev->xfrm = xfrm[i++]; | 220 | dst_prev->xfrm = xfrm[i++]; |
213 | dst_prev->dev = rt->u.dst.dev; | 221 | dst_prev->dev = rt->u.dst.dev; |
@@ -224,16 +232,26 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
224 | /* Copy neighbour for reachability confirmation */ | 232 | /* Copy neighbour for reachability confirmation */ |
225 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 233 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
226 | dst_prev->input = rt->u.dst.input; | 234 | dst_prev->input = rt->u.dst.input; |
227 | dst_prev->output = xfrm6_output; | 235 | /* XXX: When IPv4 is implemented as module and can be unloaded, |
236 | * we should manage reference to xfrm4_output in afinfo->output. | ||
237 | * Miyazawa | ||
238 | */ | ||
239 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | ||
240 | if (!afinfo) { | ||
241 | dst = *dst_p; | ||
242 | goto error; | ||
243 | }; | ||
244 | dst_prev->output = afinfo->output; | ||
245 | xfrm_state_put_afinfo(afinfo); | ||
228 | /* Sheit... I remember I did this right. Apparently, | 246 | /* Sheit... I remember I did this right. Apparently, |
229 | * it was magically lost, so this code needs audit */ | 247 | * it was magically lost, so this code needs audit */ |
230 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); | 248 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); |
231 | x->u.rt6.rt6i_metric = rt0->rt6i_metric; | 249 | x->u.rt6.rt6i_metric = rt0->rt6i_metric; |
232 | x->u.rt6.rt6i_node = rt0->rt6i_node; | 250 | x->u.rt6.rt6i_node = rt0->rt6i_node; |
233 | x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; | 251 | x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; |
234 | memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); | 252 | memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); |
235 | x->u.rt6.rt6i_dst = rt0->rt6i_dst; | 253 | x->u.rt6.rt6i_dst = rt0->rt6i_dst; |
236 | x->u.rt6.rt6i_src = rt0->rt6i_src; | 254 | x->u.rt6.rt6i_src = rt0->rt6i_src; |
237 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; | 255 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; |
238 | in6_dev_hold(rt0->rt6i_idev); | 256 | in6_dev_hold(rt0->rt6i_idev); |
239 | __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm); | 257 | __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm); |