diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-12-11 12:32:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:43 -0500 |
commit | 25ee3286dcbc830a833354bb1d15567956844813 (patch) | |
tree | bb5597d9e148f363bf0bbcd1a7269b5f677f0103 /net/ipv6 | |
parent | 66cdb3ca27323a92712d289fc5edc7841d74a139 (diff) |
[IPSEC]: Merge common code into xfrm_bundle_create
Half of the code in xfrm4_bundle_create and xfrm6_bundle_create are
common. This patch extracts that logic and puts it into
xfrm_bundle_create. The rest of it are then accessed through afinfo.
As a result this fixes the problem with inter-family transforms where
we treat every xfrm dst in the bundle as if it belongs to the top
family.
This patch also fixes a long-standing error-path bug where we may free
the xfrm states twice.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 136 |
1 files changed, 22 insertions, 114 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8e78530865a6..63932c5fd3c7 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -93,126 +93,33 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
93 | return dst; | 93 | return dst; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 96 | static int xfrm6_get_tos(struct flowi *fl) |
97 | * all the metrics... Shortly, bundle a bundle. | ||
98 | */ | ||
99 | |||
100 | static int | ||
101 | __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | ||
102 | struct flowi *fl, struct dst_entry **dst_p) | ||
103 | { | 97 | { |
104 | struct dst_entry *dst, *dst_prev; | 98 | return 0; |
105 | struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); | 99 | } |
106 | struct rt6_info *rt = rt0; | ||
107 | int i; | ||
108 | int err; | ||
109 | int header_len = 0; | ||
110 | int trailer_len = 0; | ||
111 | |||
112 | dst = dst_prev = NULL; | ||
113 | dst_hold(&rt->u.dst); | ||
114 | |||
115 | for (i = 0; i < nx; i++) { | ||
116 | struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops); | ||
117 | struct xfrm_dst *xdst; | ||
118 | 100 | ||
119 | if (unlikely(dst1 == NULL)) { | 101 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) |
120 | err = -ENOBUFS; | 102 | { |
121 | dst_release(&rt->u.dst); | 103 | struct rt6_info *rt = (struct rt6_info*)xdst->route; |
122 | goto error; | ||
123 | } | ||
124 | 104 | ||
125 | if (!dst) | 105 | xdst->u.dst.dev = dev; |
126 | dst = dst1; | 106 | dev_hold(dev); |
127 | else { | ||
128 | dst_prev->child = dst1; | ||
129 | dst1->flags |= DST_NOHASH; | ||
130 | dst_clone(dst1); | ||
131 | } | ||
132 | 107 | ||
133 | xdst = (struct xfrm_dst *)dst1; | 108 | xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev); |
134 | xdst->route = &rt->u.dst; | 109 | if (!xdst->u.rt6.rt6i_idev) |
135 | xdst->genid = xfrm[i]->genid; | 110 | return -ENODEV; |
136 | if (rt->rt6i_node) | ||
137 | xdst->route_cookie = rt->rt6i_node->fn_sernum; | ||
138 | |||
139 | dst1->next = dst_prev; | ||
140 | dst_prev = dst1; | ||
141 | |||
142 | if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
143 | ((struct rt6_info *)dst)->nfheader_len += | ||
144 | xfrm[i]->props.header_len; | ||
145 | header_len += xfrm[i]->props.header_len; | ||
146 | trailer_len += xfrm[i]->props.trailer_len; | ||
147 | |||
148 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | ||
149 | dst1 = xfrm_dst_lookup(xfrm[i], 0); | ||
150 | err = PTR_ERR(dst1); | ||
151 | if (IS_ERR(dst1)) | ||
152 | goto error; | ||
153 | |||
154 | rt = (struct rt6_info *)dst1; | ||
155 | } else | ||
156 | dst_hold(&rt->u.dst); | ||
157 | } | ||
158 | 111 | ||
159 | dst_prev->child = &rt->u.dst; | 112 | /* Sheit... I remember I did this right. Apparently, |
160 | dst->path = &rt->u.dst; | 113 | * it was magically lost, so this code needs audit */ |
161 | 114 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | | |
162 | /* Copy neighbour for reachability confirmation */ | 115 | RTF_LOCAL); |
163 | dst->neighbour = neigh_clone(rt->u.dst.neighbour); | 116 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; |
164 | 117 | xdst->u.rt6.rt6i_node = rt->rt6i_node; | |
165 | if (rt->rt6i_node) | 118 | xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; |
166 | ((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum; | 119 | xdst->u.rt6.rt6i_dst = rt->rt6i_dst; |
167 | 120 | xdst->u.rt6.rt6i_src = rt->rt6i_src; | |
168 | *dst_p = dst; | ||
169 | dst = dst_prev; | ||
170 | |||
171 | dst_prev = *dst_p; | ||
172 | i = 0; | ||
173 | err = -ENODEV; | ||
174 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | ||
175 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | ||
176 | |||
177 | dst_prev->xfrm = xfrm[i++]; | ||
178 | dst_prev->dev = rt->u.dst.dev; | ||
179 | if (!rt->u.dst.dev) | ||
180 | goto error; | ||
181 | dev_hold(rt->u.dst.dev); | ||
182 | |||
183 | x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev); | ||
184 | if (!x->u.rt6.rt6i_idev) | ||
185 | goto error; | ||
186 | |||
187 | dst_prev->obsolete = -1; | ||
188 | dst_prev->flags |= DST_HOST; | ||
189 | dst_prev->lastuse = jiffies; | ||
190 | dst_prev->header_len = header_len; | ||
191 | dst_prev->trailer_len = trailer_len; | ||
192 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | ||
193 | |||
194 | dst_prev->input = dst_discard; | ||
195 | dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output; | ||
196 | /* Sheit... I remember I did this right. Apparently, | ||
197 | * it was magically lost, so this code needs audit */ | ||
198 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTF_ANYCAST|RTF_LOCAL); | ||
199 | x->u.rt6.rt6i_metric = rt0->rt6i_metric; | ||
200 | x->u.rt6.rt6i_node = rt0->rt6i_node; | ||
201 | x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; | ||
202 | memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); | ||
203 | x->u.rt6.rt6i_dst = rt0->rt6i_dst; | ||
204 | x->u.rt6.rt6i_src = rt0->rt6i_src; | ||
205 | header_len -= x->u.dst.xfrm->props.header_len; | ||
206 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | ||
207 | } | ||
208 | 121 | ||
209 | xfrm_init_pmtu(dst); | ||
210 | return 0; | 122 | return 0; |
211 | |||
212 | error: | ||
213 | if (dst) | ||
214 | dst_free(dst); | ||
215 | return err; | ||
216 | } | 123 | } |
217 | 124 | ||
218 | static inline void | 125 | static inline void |
@@ -355,8 +262,9 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
355 | .dst_lookup = xfrm6_dst_lookup, | 262 | .dst_lookup = xfrm6_dst_lookup, |
356 | .get_saddr = xfrm6_get_saddr, | 263 | .get_saddr = xfrm6_get_saddr, |
357 | .find_bundle = __xfrm6_find_bundle, | 264 | .find_bundle = __xfrm6_find_bundle, |
358 | .bundle_create = __xfrm6_bundle_create, | ||
359 | .decode_session = _decode_session6, | 265 | .decode_session = _decode_session6, |
266 | .get_tos = xfrm6_get_tos, | ||
267 | .fill_dst = xfrm6_fill_dst, | ||
360 | }; | 268 | }; |
361 | 269 | ||
362 | static void __init xfrm6_policy_init(void) | 270 | static void __init xfrm6_policy_init(void) |