aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/xfrm4_policy.c50
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}