diff options
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8dffd4daae9c..59480e92177d 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -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,27 @@ __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 | unsigned short encap_family = xfrm[i]->props.family; |
190 | ipv6_addr_copy(&fl_tunnel.fl6_src, local); | 183 | switch(encap_family) { |
184 | case AF_INET: | ||
185 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
186 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
187 | break; | ||
188 | case AF_INET6: | ||
189 | ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6); | ||
190 | ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6); | ||
191 | break; | ||
192 | default: | ||
193 | BUG_ON(1); | ||
194 | } | ||
195 | |||
191 | err = xfrm_dst_lookup((struct xfrm_dst **) &rt, | 196 | err = xfrm_dst_lookup((struct xfrm_dst **) &rt, |
192 | &fl_tunnel, AF_INET6); | 197 | &fl_tunnel, encap_family); |
193 | if (err) | 198 | if (err) |
194 | goto error; | 199 | goto error; |
195 | } else | 200 | } else |
@@ -208,6 +213,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
208 | i = 0; | 213 | i = 0; |
209 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 214 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
210 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 215 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
216 | struct xfrm_state_afinfo *afinfo; | ||
211 | 217 | ||
212 | dst_prev->xfrm = xfrm[i++]; | 218 | dst_prev->xfrm = xfrm[i++]; |
213 | dst_prev->dev = rt->u.dst.dev; | 219 | dst_prev->dev = rt->u.dst.dev; |
@@ -224,7 +230,17 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
224 | /* Copy neighbour for reachability confirmation */ | 230 | /* Copy neighbour for reachability confirmation */ |
225 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 231 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
226 | dst_prev->input = rt->u.dst.input; | 232 | dst_prev->input = rt->u.dst.input; |
227 | dst_prev->output = xfrm6_output; | 233 | /* XXX: When IPv4 is implemented as module and can be unloaded, |
234 | * we should manage reference to xfrm4_output in afinfo->output. | ||
235 | * Miyazawa | ||
236 | */ | ||
237 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | ||
238 | if (!afinfo) { | ||
239 | dst = *dst_p; | ||
240 | goto error; | ||
241 | }; | ||
242 | dst_prev->output = afinfo->output; | ||
243 | xfrm_state_put_afinfo(afinfo); | ||
228 | /* Sheit... I remember I did this right. Apparently, | 244 | /* Sheit... I remember I did this right. Apparently, |
229 | * it was magically lost, so this code needs audit */ | 245 | * it was magically lost, so this code needs audit */ |
230 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); | 246 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); |