diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index fb9f69c616f5..011136a95809 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -72,13 +72,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
72 | struct dst_entry *dst, *dst_prev; | 72 | struct dst_entry *dst, *dst_prev; |
73 | struct rtable *rt0 = (struct rtable*)(*dst_p); | 73 | struct rtable *rt0 = (struct rtable*)(*dst_p); |
74 | struct rtable *rt = rt0; | 74 | struct rtable *rt = rt0; |
75 | __be32 remote = fl->fl4_dst; | ||
76 | __be32 local = fl->fl4_src; | ||
77 | struct flowi fl_tunnel = { | 75 | struct flowi fl_tunnel = { |
78 | .nl_u = { | 76 | .nl_u = { |
79 | .ip4_u = { | 77 | .ip4_u = { |
80 | .saddr = local, | 78 | .saddr = fl->fl4_src, |
81 | .daddr = remote, | 79 | .daddr = fl->fl4_dst, |
82 | .tos = fl->fl4_tos | 80 | .tos = fl->fl4_tos |
83 | } | 81 | } |
84 | } | 82 | } |
@@ -94,7 +92,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
94 | for (i = 0; i < nx; i++) { | 92 | for (i = 0; i < nx; i++) { |
95 | struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); | 93 | struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); |
96 | struct xfrm_dst *xdst; | 94 | struct xfrm_dst *xdst; |
97 | int tunnel = 0; | ||
98 | 95 | ||
99 | if (unlikely(dst1 == NULL)) { | 96 | if (unlikely(dst1 == NULL)) { |
100 | err = -ENOBUFS; | 97 | err = -ENOBUFS; |
@@ -116,19 +113,28 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
116 | 113 | ||
117 | dst1->next = dst_prev; | 114 | dst1->next = dst_prev; |
118 | dst_prev = dst1; | 115 | dst_prev = dst1; |
119 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 116 | |
120 | remote = xfrm[i]->id.daddr.a4; | ||
121 | local = xfrm[i]->props.saddr.a4; | ||
122 | tunnel = 1; | ||
123 | } | ||
124 | header_len += xfrm[i]->props.header_len; | 117 | header_len += xfrm[i]->props.header_len; |
125 | trailer_len += xfrm[i]->props.trailer_len; | 118 | trailer_len += xfrm[i]->props.trailer_len; |
126 | 119 | ||
127 | if (tunnel) { | 120 | if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) { |
128 | fl_tunnel.fl4_src = local; | 121 | unsigned short encap_family = xfrm[i]->props.family; |
129 | fl_tunnel.fl4_dst = remote; | 122 | switch(encap_family) { |
123 | case AF_INET: | ||
124 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
125 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
126 | break; | ||
127 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
128 | case AF_INET6: | ||
129 | ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6); | ||
130 | ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6); | ||
131 | break; | ||
132 | #endif | ||
133 | default: | ||
134 | BUG_ON(1); | ||
135 | } | ||
130 | err = xfrm_dst_lookup((struct xfrm_dst **)&rt, | 136 | err = xfrm_dst_lookup((struct xfrm_dst **)&rt, |
131 | &fl_tunnel, AF_INET); | 137 | &fl_tunnel, encap_family); |
132 | if (err) | 138 | if (err) |
133 | goto error; | 139 | goto error; |
134 | } else | 140 | } else |
@@ -145,6 +151,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
145 | i = 0; | 151 | i = 0; |
146 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 152 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
147 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 153 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
154 | struct xfrm_state_afinfo *afinfo; | ||
148 | x->u.rt.fl = *fl; | 155 | x->u.rt.fl = *fl; |
149 | 156 | ||
150 | dst_prev->xfrm = xfrm[i++]; | 157 | dst_prev->xfrm = xfrm[i++]; |
@@ -162,8 +169,17 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
162 | /* Copy neighbout for reachability confirmation */ | 169 | /* Copy neighbout for reachability confirmation */ |
163 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 170 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
164 | dst_prev->input = rt->u.dst.input; | 171 | dst_prev->input = rt->u.dst.input; |
165 | dst_prev->output = xfrm4_output; | 172 | /* XXX: When IPv6 module can be unloaded, we should manage reference |
166 | if (rt->peer) | 173 | * to xfrm6_output in afinfo->output. Miyazawa |
174 | * */ | ||
175 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | ||
176 | if (!afinfo) { | ||
177 | dst = *dst_p; | ||
178 | goto error; | ||
179 | } | ||
180 | dst_prev->output = afinfo->output; | ||
181 | xfrm_state_put_afinfo(afinfo); | ||
182 | if (dst_prev->xfrm->props.family == AF_INET && rt->peer) | ||
167 | atomic_inc(&rt->peer->refcnt); | 183 | atomic_inc(&rt->peer->refcnt); |
168 | x->u.rt.peer = rt->peer; | 184 | x->u.rt.peer = rt->peer; |
169 | /* Sheit... I remember I did this right. Apparently, | 185 | /* Sheit... I remember I did this right. Apparently, |
@@ -274,7 +290,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
274 | 290 | ||
275 | if (likely(xdst->u.rt.idev)) | 291 | if (likely(xdst->u.rt.idev)) |
276 | in_dev_put(xdst->u.rt.idev); | 292 | in_dev_put(xdst->u.rt.idev); |
277 | if (likely(xdst->u.rt.peer)) | 293 | if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) |
278 | inet_putpeer(xdst->u.rt.peer); | 294 | inet_putpeer(xdst->u.rt.peer); |
279 | xfrm_dst_destroy(xdst); | 295 | xfrm_dst_destroy(xdst); |
280 | } | 296 | } |