diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
| -rw-r--r-- | net/xfrm/xfrm_state.c | 186 |
1 files changed, 71 insertions, 115 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 178baaa037e5..3edbf4b26116 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -173,7 +173,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
| 173 | int __xfrm_state_delete(struct xfrm_state *x); | 173 | int __xfrm_state_delete(struct xfrm_state *x); |
| 174 | 174 | ||
| 175 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 175 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
| 176 | bool km_is_alive(const struct km_event *c); | 176 | static bool km_is_alive(const struct km_event *c); |
| 177 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); | 177 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); |
| 178 | 178 | ||
| 179 | static DEFINE_SPINLOCK(xfrm_type_lock); | 179 | static DEFINE_SPINLOCK(xfrm_type_lock); |
| @@ -330,100 +330,67 @@ static void xfrm_put_type_offload(const struct xfrm_type_offload *type) | |||
| 330 | module_put(type->owner); | 330 | module_put(type->owner); |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | static DEFINE_SPINLOCK(xfrm_mode_lock); | 333 | static const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = { |
| 334 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | 334 | [XFRM_MODE_BEET] = { |
| 335 | { | 335 | .encap = XFRM_MODE_BEET, |
| 336 | struct xfrm_state_afinfo *afinfo; | 336 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 337 | struct xfrm_mode **modemap; | 337 | .family = AF_INET, |
| 338 | int err; | 338 | }, |
| 339 | 339 | [XFRM_MODE_TRANSPORT] = { | |
| 340 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 340 | .encap = XFRM_MODE_TRANSPORT, |
| 341 | return -EINVAL; | 341 | .family = AF_INET, |
| 342 | 342 | }, | |
| 343 | afinfo = xfrm_state_get_afinfo(family); | 343 | [XFRM_MODE_TUNNEL] = { |
| 344 | if (unlikely(afinfo == NULL)) | 344 | .encap = XFRM_MODE_TUNNEL, |
| 345 | return -EAFNOSUPPORT; | 345 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 346 | 346 | .family = AF_INET, | |
| 347 | err = -EEXIST; | 347 | }, |
| 348 | modemap = afinfo->mode_map; | 348 | }; |
| 349 | spin_lock_bh(&xfrm_mode_lock); | 349 | |
| 350 | if (modemap[mode->encap]) | 350 | static const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = { |
| 351 | goto out; | 351 | [XFRM_MODE_BEET] = { |
| 352 | 352 | .encap = XFRM_MODE_BEET, | |
| 353 | err = -ENOENT; | 353 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 354 | if (!try_module_get(afinfo->owner)) | 354 | .family = AF_INET6, |
| 355 | goto out; | 355 | }, |
| 356 | 356 | [XFRM_MODE_ROUTEOPTIMIZATION] = { | |
| 357 | mode->afinfo = afinfo; | 357 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, |
| 358 | modemap[mode->encap] = mode; | 358 | .family = AF_INET6, |
| 359 | err = 0; | 359 | }, |
| 360 | 360 | [XFRM_MODE_TRANSPORT] = { | |
| 361 | out: | 361 | .encap = XFRM_MODE_TRANSPORT, |
| 362 | spin_unlock_bh(&xfrm_mode_lock); | 362 | .family = AF_INET6, |
| 363 | rcu_read_unlock(); | 363 | }, |
| 364 | return err; | 364 | [XFRM_MODE_TUNNEL] = { |
| 365 | } | 365 | .encap = XFRM_MODE_TUNNEL, |
| 366 | EXPORT_SYMBOL(xfrm_register_mode); | 366 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 367 | 367 | .family = AF_INET6, | |
| 368 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | 368 | }, |
| 369 | { | 369 | }; |
| 370 | struct xfrm_state_afinfo *afinfo; | 370 | |
| 371 | struct xfrm_mode **modemap; | 371 | static const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) |
| 372 | int err; | 372 | { |
| 373 | 373 | const struct xfrm_mode *mode; | |
| 374 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
| 375 | return -EINVAL; | ||
| 376 | |||
| 377 | afinfo = xfrm_state_get_afinfo(family); | ||
| 378 | if (unlikely(afinfo == NULL)) | ||
| 379 | return -EAFNOSUPPORT; | ||
| 380 | |||
| 381 | err = -ENOENT; | ||
| 382 | modemap = afinfo->mode_map; | ||
| 383 | spin_lock_bh(&xfrm_mode_lock); | ||
| 384 | if (likely(modemap[mode->encap] == mode)) { | ||
| 385 | modemap[mode->encap] = NULL; | ||
| 386 | module_put(mode->afinfo->owner); | ||
| 387 | err = 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | spin_unlock_bh(&xfrm_mode_lock); | ||
| 391 | rcu_read_unlock(); | ||
| 392 | return err; | ||
| 393 | } | ||
| 394 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
| 395 | |||
| 396 | static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
| 397 | { | ||
| 398 | struct xfrm_state_afinfo *afinfo; | ||
| 399 | struct xfrm_mode *mode; | ||
| 400 | int modload_attempted = 0; | ||
| 401 | 374 | ||
| 402 | if (unlikely(encap >= XFRM_MODE_MAX)) | 375 | if (unlikely(encap >= XFRM_MODE_MAX)) |
| 403 | return NULL; | 376 | return NULL; |
| 404 | 377 | ||
| 405 | retry: | 378 | switch (family) { |
| 406 | afinfo = xfrm_state_get_afinfo(family); | 379 | case AF_INET: |
| 407 | if (unlikely(afinfo == NULL)) | 380 | mode = &xfrm4_mode_map[encap]; |
| 408 | return NULL; | 381 | if (mode->family == family) |
| 409 | 382 | return mode; | |
| 410 | mode = READ_ONCE(afinfo->mode_map[encap]); | 383 | break; |
| 411 | if (unlikely(mode && !try_module_get(mode->owner))) | 384 | case AF_INET6: |
| 412 | mode = NULL; | 385 | mode = &xfrm6_mode_map[encap]; |
| 413 | 386 | if (mode->family == family) | |
| 414 | rcu_read_unlock(); | 387 | return mode; |
| 415 | if (!mode && !modload_attempted) { | 388 | break; |
| 416 | request_module("xfrm-mode-%d-%d", family, encap); | 389 | default: |
| 417 | modload_attempted = 1; | 390 | break; |
| 418 | goto retry; | ||
| 419 | } | 391 | } |
| 420 | 392 | ||
| 421 | return mode; | 393 | return NULL; |
| 422 | } | ||
| 423 | |||
| 424 | static void xfrm_put_mode(struct xfrm_mode *mode) | ||
| 425 | { | ||
| 426 | module_put(mode->owner); | ||
| 427 | } | 394 | } |
| 428 | 395 | ||
| 429 | void xfrm_state_free(struct xfrm_state *x) | 396 | void xfrm_state_free(struct xfrm_state *x) |
| @@ -444,12 +411,6 @@ static void ___xfrm_state_destroy(struct xfrm_state *x) | |||
| 444 | kfree(x->coaddr); | 411 | kfree(x->coaddr); |
| 445 | kfree(x->replay_esn); | 412 | kfree(x->replay_esn); |
| 446 | kfree(x->preplay_esn); | 413 | kfree(x->preplay_esn); |
| 447 | if (x->inner_mode) | ||
| 448 | xfrm_put_mode(x->inner_mode); | ||
| 449 | if (x->inner_mode_iaf) | ||
| 450 | xfrm_put_mode(x->inner_mode_iaf); | ||
| 451 | if (x->outer_mode) | ||
| 452 | xfrm_put_mode(x->outer_mode); | ||
| 453 | if (x->type_offload) | 414 | if (x->type_offload) |
| 454 | xfrm_put_type_offload(x->type_offload); | 415 | xfrm_put_type_offload(x->type_offload); |
| 455 | if (x->type) { | 416 | if (x->type) { |
| @@ -590,8 +551,6 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
| 590 | x->lft.hard_packet_limit = XFRM_INF; | 551 | x->lft.hard_packet_limit = XFRM_INF; |
| 591 | x->replay_maxage = 0; | 552 | x->replay_maxage = 0; |
| 592 | x->replay_maxdiff = 0; | 553 | x->replay_maxdiff = 0; |
| 593 | x->inner_mode = NULL; | ||
| 594 | x->inner_mode_iaf = NULL; | ||
| 595 | spin_lock_init(&x->lock); | 554 | spin_lock_init(&x->lock); |
| 596 | } | 555 | } |
| 597 | return x; | 556 | return x; |
| @@ -2066,7 +2025,7 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address | |||
| 2066 | } | 2025 | } |
| 2067 | EXPORT_SYMBOL(km_report); | 2026 | EXPORT_SYMBOL(km_report); |
| 2068 | 2027 | ||
| 2069 | bool km_is_alive(const struct km_event *c) | 2028 | static bool km_is_alive(const struct km_event *c) |
| 2070 | { | 2029 | { |
| 2071 | struct xfrm_mgr *km; | 2030 | struct xfrm_mgr *km; |
| 2072 | bool is_alive = false; | 2031 | bool is_alive = false; |
| @@ -2082,7 +2041,6 @@ bool km_is_alive(const struct km_event *c) | |||
| 2082 | 2041 | ||
| 2083 | return is_alive; | 2042 | return is_alive; |
| 2084 | } | 2043 | } |
| 2085 | EXPORT_SYMBOL(km_is_alive); | ||
| 2086 | 2044 | ||
| 2087 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 2045 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
| 2088 | { | 2046 | { |
| @@ -2195,6 +2153,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) | |||
| 2195 | 2153 | ||
| 2196 | return rcu_dereference(xfrm_state_afinfo[family]); | 2154 | return rcu_dereference(xfrm_state_afinfo[family]); |
| 2197 | } | 2155 | } |
| 2156 | EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); | ||
| 2198 | 2157 | ||
| 2199 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | 2158 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) |
| 2200 | { | 2159 | { |
| @@ -2242,8 +2201,9 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) | |||
| 2242 | 2201 | ||
| 2243 | int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | 2202 | int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) |
| 2244 | { | 2203 | { |
| 2245 | struct xfrm_state_afinfo *afinfo; | 2204 | const struct xfrm_state_afinfo *afinfo; |
| 2246 | struct xfrm_mode *inner_mode; | 2205 | const struct xfrm_mode *inner_mode; |
| 2206 | const struct xfrm_mode *outer_mode; | ||
| 2247 | int family = x->props.family; | 2207 | int family = x->props.family; |
| 2248 | int err; | 2208 | int err; |
| 2249 | 2209 | ||
| @@ -2269,25 +2229,22 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2269 | goto error; | 2229 | goto error; |
| 2270 | 2230 | ||
| 2271 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | 2231 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && |
| 2272 | family != x->sel.family) { | 2232 | family != x->sel.family) |
| 2273 | xfrm_put_mode(inner_mode); | ||
| 2274 | goto error; | 2233 | goto error; |
| 2275 | } | ||
| 2276 | 2234 | ||
| 2277 | x->inner_mode = inner_mode; | 2235 | x->inner_mode = *inner_mode; |
| 2278 | } else { | 2236 | } else { |
| 2279 | struct xfrm_mode *inner_mode_iaf; | 2237 | const struct xfrm_mode *inner_mode_iaf; |
| 2280 | int iafamily = AF_INET; | 2238 | int iafamily = AF_INET; |
| 2281 | 2239 | ||
| 2282 | inner_mode = xfrm_get_mode(x->props.mode, x->props.family); | 2240 | inner_mode = xfrm_get_mode(x->props.mode, x->props.family); |
| 2283 | if (inner_mode == NULL) | 2241 | if (inner_mode == NULL) |
| 2284 | goto error; | 2242 | goto error; |
| 2285 | 2243 | ||
| 2286 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { | 2244 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) |
| 2287 | xfrm_put_mode(inner_mode); | ||
| 2288 | goto error; | 2245 | goto error; |
| 2289 | } | 2246 | |
| 2290 | x->inner_mode = inner_mode; | 2247 | x->inner_mode = *inner_mode; |
| 2291 | 2248 | ||
| 2292 | if (x->props.family == AF_INET) | 2249 | if (x->props.family == AF_INET) |
| 2293 | iafamily = AF_INET6; | 2250 | iafamily = AF_INET6; |
| @@ -2295,9 +2252,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2295 | inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); | 2252 | inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); |
| 2296 | if (inner_mode_iaf) { | 2253 | if (inner_mode_iaf) { |
| 2297 | if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) | 2254 | if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) |
| 2298 | x->inner_mode_iaf = inner_mode_iaf; | 2255 | x->inner_mode_iaf = *inner_mode_iaf; |
| 2299 | else | ||
| 2300 | xfrm_put_mode(inner_mode_iaf); | ||
| 2301 | } | 2256 | } |
| 2302 | } | 2257 | } |
| 2303 | 2258 | ||
| @@ -2311,12 +2266,13 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2311 | if (err) | 2266 | if (err) |
| 2312 | goto error; | 2267 | goto error; |
| 2313 | 2268 | ||
| 2314 | x->outer_mode = xfrm_get_mode(x->props.mode, family); | 2269 | outer_mode = xfrm_get_mode(x->props.mode, family); |
| 2315 | if (x->outer_mode == NULL) { | 2270 | if (!outer_mode) { |
| 2316 | err = -EPROTONOSUPPORT; | 2271 | err = -EPROTONOSUPPORT; |
| 2317 | goto error; | 2272 | goto error; |
| 2318 | } | 2273 | } |
| 2319 | 2274 | ||
| 2275 | x->outer_mode = *outer_mode; | ||
| 2320 | if (init_replay) { | 2276 | if (init_replay) { |
| 2321 | err = xfrm_init_replay(x); | 2277 | err = xfrm_init_replay(x); |
| 2322 | if (err) | 2278 | if (err) |
