diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 206 |
1 files changed, 197 insertions, 9 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 344f0a6abec5..224b44e31a07 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -57,6 +57,9 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | |||
57 | static unsigned int xfrm_state_num; | 57 | static unsigned int xfrm_state_num; |
58 | static unsigned int xfrm_state_genid; | 58 | static unsigned int xfrm_state_genid; |
59 | 59 | ||
60 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | ||
61 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
62 | |||
60 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | 63 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, |
61 | xfrm_address_t *saddr, | 64 | xfrm_address_t *saddr, |
62 | u32 reqid, | 65 | u32 reqid, |
@@ -187,6 +190,184 @@ int __xfrm_state_delete(struct xfrm_state *x); | |||
187 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 190 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
188 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | 191 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
189 | 192 | ||
193 | static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) | ||
194 | { | ||
195 | struct xfrm_state_afinfo *afinfo; | ||
196 | if (unlikely(family >= NPROTO)) | ||
197 | return NULL; | ||
198 | write_lock_bh(&xfrm_state_afinfo_lock); | ||
199 | afinfo = xfrm_state_afinfo[family]; | ||
200 | if (unlikely(!afinfo)) | ||
201 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
202 | return afinfo; | ||
203 | } | ||
204 | |||
205 | static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) | ||
206 | { | ||
207 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
208 | } | ||
209 | |||
210 | int xfrm_register_type(struct xfrm_type *type, unsigned short family) | ||
211 | { | ||
212 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | ||
213 | struct xfrm_type **typemap; | ||
214 | int err = 0; | ||
215 | |||
216 | if (unlikely(afinfo == NULL)) | ||
217 | return -EAFNOSUPPORT; | ||
218 | typemap = afinfo->type_map; | ||
219 | |||
220 | if (likely(typemap[type->proto] == NULL)) | ||
221 | typemap[type->proto] = type; | ||
222 | else | ||
223 | err = -EEXIST; | ||
224 | xfrm_state_unlock_afinfo(afinfo); | ||
225 | return err; | ||
226 | } | ||
227 | EXPORT_SYMBOL(xfrm_register_type); | ||
228 | |||
229 | int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) | ||
230 | { | ||
231 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | ||
232 | struct xfrm_type **typemap; | ||
233 | int err = 0; | ||
234 | |||
235 | if (unlikely(afinfo == NULL)) | ||
236 | return -EAFNOSUPPORT; | ||
237 | typemap = afinfo->type_map; | ||
238 | |||
239 | if (unlikely(typemap[type->proto] != type)) | ||
240 | err = -ENOENT; | ||
241 | else | ||
242 | typemap[type->proto] = NULL; | ||
243 | xfrm_state_unlock_afinfo(afinfo); | ||
244 | return err; | ||
245 | } | ||
246 | EXPORT_SYMBOL(xfrm_unregister_type); | ||
247 | |||
248 | static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) | ||
249 | { | ||
250 | struct xfrm_state_afinfo *afinfo; | ||
251 | struct xfrm_type **typemap; | ||
252 | struct xfrm_type *type; | ||
253 | int modload_attempted = 0; | ||
254 | |||
255 | retry: | ||
256 | afinfo = xfrm_state_get_afinfo(family); | ||
257 | if (unlikely(afinfo == NULL)) | ||
258 | return NULL; | ||
259 | typemap = afinfo->type_map; | ||
260 | |||
261 | type = typemap[proto]; | ||
262 | if (unlikely(type && !try_module_get(type->owner))) | ||
263 | type = NULL; | ||
264 | if (!type && !modload_attempted) { | ||
265 | xfrm_state_put_afinfo(afinfo); | ||
266 | request_module("xfrm-type-%d-%d", family, proto); | ||
267 | modload_attempted = 1; | ||
268 | goto retry; | ||
269 | } | ||
270 | |||
271 | xfrm_state_put_afinfo(afinfo); | ||
272 | return type; | ||
273 | } | ||
274 | |||
275 | static void xfrm_put_type(struct xfrm_type *type) | ||
276 | { | ||
277 | module_put(type->owner); | ||
278 | } | ||
279 | |||
280 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | ||
281 | { | ||
282 | struct xfrm_state_afinfo *afinfo; | ||
283 | struct xfrm_mode **modemap; | ||
284 | int err; | ||
285 | |||
286 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
287 | return -EINVAL; | ||
288 | |||
289 | afinfo = xfrm_state_lock_afinfo(family); | ||
290 | if (unlikely(afinfo == NULL)) | ||
291 | return -EAFNOSUPPORT; | ||
292 | |||
293 | err = -EEXIST; | ||
294 | modemap = afinfo->mode_map; | ||
295 | if (modemap[mode->encap]) | ||
296 | goto out; | ||
297 | |||
298 | err = -ENOENT; | ||
299 | if (!try_module_get(afinfo->owner)) | ||
300 | goto out; | ||
301 | |||
302 | mode->afinfo = afinfo; | ||
303 | modemap[mode->encap] = mode; | ||
304 | err = 0; | ||
305 | |||
306 | out: | ||
307 | xfrm_state_unlock_afinfo(afinfo); | ||
308 | return err; | ||
309 | } | ||
310 | EXPORT_SYMBOL(xfrm_register_mode); | ||
311 | |||
312 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | ||
313 | { | ||
314 | struct xfrm_state_afinfo *afinfo; | ||
315 | struct xfrm_mode **modemap; | ||
316 | int err; | ||
317 | |||
318 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
319 | return -EINVAL; | ||
320 | |||
321 | afinfo = xfrm_state_lock_afinfo(family); | ||
322 | if (unlikely(afinfo == NULL)) | ||
323 | return -EAFNOSUPPORT; | ||
324 | |||
325 | err = -ENOENT; | ||
326 | modemap = afinfo->mode_map; | ||
327 | if (likely(modemap[mode->encap] == mode)) { | ||
328 | modemap[mode->encap] = NULL; | ||
329 | module_put(mode->afinfo->owner); | ||
330 | err = 0; | ||
331 | } | ||
332 | |||
333 | xfrm_state_unlock_afinfo(afinfo); | ||
334 | return err; | ||
335 | } | ||
336 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
337 | |||
338 | static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
339 | { | ||
340 | struct xfrm_state_afinfo *afinfo; | ||
341 | struct xfrm_mode *mode; | ||
342 | int modload_attempted = 0; | ||
343 | |||
344 | if (unlikely(encap >= XFRM_MODE_MAX)) | ||
345 | return NULL; | ||
346 | |||
347 | retry: | ||
348 | afinfo = xfrm_state_get_afinfo(family); | ||
349 | if (unlikely(afinfo == NULL)) | ||
350 | return NULL; | ||
351 | |||
352 | mode = afinfo->mode_map[encap]; | ||
353 | if (unlikely(mode && !try_module_get(mode->owner))) | ||
354 | mode = NULL; | ||
355 | if (!mode && !modload_attempted) { | ||
356 | xfrm_state_put_afinfo(afinfo); | ||
357 | request_module("xfrm-mode-%d-%d", family, encap); | ||
358 | modload_attempted = 1; | ||
359 | goto retry; | ||
360 | } | ||
361 | |||
362 | xfrm_state_put_afinfo(afinfo); | ||
363 | return mode; | ||
364 | } | ||
365 | |||
366 | static void xfrm_put_mode(struct xfrm_mode *mode) | ||
367 | { | ||
368 | module_put(mode->owner); | ||
369 | } | ||
370 | |||
190 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 371 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
191 | { | 372 | { |
192 | del_timer_sync(&x->timer); | 373 | del_timer_sync(&x->timer); |
@@ -196,8 +377,10 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
196 | kfree(x->calg); | 377 | kfree(x->calg); |
197 | kfree(x->encap); | 378 | kfree(x->encap); |
198 | kfree(x->coaddr); | 379 | kfree(x->coaddr); |
199 | if (x->mode) | 380 | if (x->inner_mode) |
200 | xfrm_put_mode(x->mode); | 381 | xfrm_put_mode(x->inner_mode); |
382 | if (x->outer_mode) | ||
383 | xfrm_put_mode(x->outer_mode); | ||
201 | if (x->type) { | 384 | if (x->type) { |
202 | x->type->destructor(x); | 385 | x->type->destructor(x); |
203 | xfrm_put_type(x->type); | 386 | xfrm_put_type(x->type); |
@@ -1699,7 +1882,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1699 | } | 1882 | } |
1700 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1883 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1701 | 1884 | ||
1702 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | 1885 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) |
1703 | { | 1886 | { |
1704 | struct xfrm_state_afinfo *afinfo; | 1887 | struct xfrm_state_afinfo *afinfo; |
1705 | if (unlikely(family >= NPROTO)) | 1888 | if (unlikely(family >= NPROTO)) |
@@ -1711,14 +1894,11 @@ struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | |||
1711 | return afinfo; | 1894 | return afinfo; |
1712 | } | 1895 | } |
1713 | 1896 | ||
1714 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1897 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1715 | { | 1898 | { |
1716 | read_unlock(&xfrm_state_afinfo_lock); | 1899 | read_unlock(&xfrm_state_afinfo_lock); |
1717 | } | 1900 | } |
1718 | 1901 | ||
1719 | EXPORT_SYMBOL(xfrm_state_get_afinfo); | ||
1720 | EXPORT_SYMBOL(xfrm_state_put_afinfo); | ||
1721 | |||
1722 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ | 1902 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ |
1723 | void xfrm_state_delete_tunnel(struct xfrm_state *x) | 1903 | void xfrm_state_delete_tunnel(struct xfrm_state *x) |
1724 | { | 1904 | { |
@@ -1769,6 +1949,14 @@ int xfrm_init_state(struct xfrm_state *x) | |||
1769 | goto error; | 1949 | goto error; |
1770 | 1950 | ||
1771 | err = -EPROTONOSUPPORT; | 1951 | err = -EPROTONOSUPPORT; |
1952 | x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); | ||
1953 | if (x->inner_mode == NULL) | ||
1954 | goto error; | ||
1955 | |||
1956 | if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | ||
1957 | family != x->sel.family) | ||
1958 | goto error; | ||
1959 | |||
1772 | x->type = xfrm_get_type(x->id.proto, family); | 1960 | x->type = xfrm_get_type(x->id.proto, family); |
1773 | if (x->type == NULL) | 1961 | if (x->type == NULL) |
1774 | goto error; | 1962 | goto error; |
@@ -1777,8 +1965,8 @@ int xfrm_init_state(struct xfrm_state *x) | |||
1777 | if (err) | 1965 | if (err) |
1778 | goto error; | 1966 | goto error; |
1779 | 1967 | ||
1780 | x->mode = xfrm_get_mode(x->props.mode, family); | 1968 | x->outer_mode = xfrm_get_mode(x->props.mode, family); |
1781 | if (x->mode == NULL) | 1969 | if (x->outer_mode == NULL) |
1782 | goto error; | 1970 | goto error; |
1783 | 1971 | ||
1784 | x->km.state = XFRM_STATE_VALID; | 1972 | x->km.state = XFRM_STATE_VALID; |