diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/Kconfig | 26 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 231 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 184 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 173 |
4 files changed, 609 insertions, 5 deletions
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 0faab6332586..577a4f821b98 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig | |||
@@ -24,6 +24,17 @@ config XFRM_SUB_POLICY | |||
24 | 24 | ||
25 | If unsure, say N. | 25 | If unsure, say N. |
26 | 26 | ||
27 | config XFRM_MIGRATE | ||
28 | bool "Transformation migrate database (EXPERIMENTAL)" | ||
29 | depends on XFRM && EXPERIMENTAL | ||
30 | ---help--- | ||
31 | A feature to update locator(s) of a given IPsec security | ||
32 | association dynamically. This feature is required, for | ||
33 | instance, in a Mobile IPv6 environment with IPsec configuration | ||
34 | where mobile nodes change their attachment point to the Internet. | ||
35 | |||
36 | If unsure, say N. | ||
37 | |||
27 | config NET_KEY | 38 | config NET_KEY |
28 | tristate "PF_KEY sockets" | 39 | tristate "PF_KEY sockets" |
29 | select XFRM | 40 | select XFRM |
@@ -34,4 +45,19 @@ config NET_KEY | |||
34 | 45 | ||
35 | Say Y unless you know what you are doing. | 46 | Say Y unless you know what you are doing. |
36 | 47 | ||
48 | config NET_KEY_MIGRATE | ||
49 | bool "PF_KEY MIGRATE (EXPERIMENTAL)" | ||
50 | depends on NET_KEY && EXPERIMENTAL | ||
51 | select XFRM_MIGRATE | ||
52 | ---help--- | ||
53 | Add a PF_KEY MIGRATE message to PF_KEYv2 socket family. | ||
54 | The PF_KEY MIGRATE message is used to dynamically update | ||
55 | locator(s) of a given IPsec security association. | ||
56 | This feature is required, for instance, in a Mobile IPv6 | ||
57 | environment with IPsec configuration where mobile nodes | ||
58 | change their attachment point to the Internet. Detail | ||
59 | information can be found in the internet-draft | ||
60 | <draft-sugimoto-mip6-pfkey-migrate>. | ||
61 | |||
62 | If unsure, say N. | ||
37 | 63 | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b7e537fe2d75..fa7ce060b454 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -2236,3 +2236,234 @@ void __init xfrm_init(void) | |||
2236 | xfrm_input_init(); | 2236 | xfrm_input_init(); |
2237 | } | 2237 | } |
2238 | 2238 | ||
2239 | #ifdef CONFIG_XFRM_MIGRATE | ||
2240 | static int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp, | ||
2241 | struct xfrm_selector *sel_tgt) | ||
2242 | { | ||
2243 | if (sel_cmp->proto == IPSEC_ULPROTO_ANY) { | ||
2244 | if (sel_tgt->family == sel_cmp->family && | ||
2245 | xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr, | ||
2246 | sel_cmp->family) == 0 && | ||
2247 | xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr, | ||
2248 | sel_cmp->family) == 0 && | ||
2249 | sel_tgt->prefixlen_d == sel_cmp->prefixlen_d && | ||
2250 | sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) { | ||
2251 | return 1; | ||
2252 | } | ||
2253 | } else { | ||
2254 | if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) { | ||
2255 | return 1; | ||
2256 | } | ||
2257 | } | ||
2258 | return 0; | ||
2259 | } | ||
2260 | |||
2261 | static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel, | ||
2262 | u8 dir, u8 type) | ||
2263 | { | ||
2264 | struct xfrm_policy *pol, *ret = NULL; | ||
2265 | struct hlist_node *entry; | ||
2266 | struct hlist_head *chain; | ||
2267 | u32 priority = ~0U; | ||
2268 | |||
2269 | read_lock_bh(&xfrm_policy_lock); | ||
2270 | chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir); | ||
2271 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
2272 | if (xfrm_migrate_selector_match(sel, &pol->selector) && | ||
2273 | pol->type == type) { | ||
2274 | ret = pol; | ||
2275 | priority = ret->priority; | ||
2276 | break; | ||
2277 | } | ||
2278 | } | ||
2279 | chain = &xfrm_policy_inexact[dir]; | ||
2280 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
2281 | if (xfrm_migrate_selector_match(sel, &pol->selector) && | ||
2282 | pol->type == type && | ||
2283 | pol->priority < priority) { | ||
2284 | ret = pol; | ||
2285 | break; | ||
2286 | } | ||
2287 | } | ||
2288 | |||
2289 | if (ret) | ||
2290 | xfrm_pol_hold(ret); | ||
2291 | |||
2292 | read_unlock_bh(&xfrm_policy_lock); | ||
2293 | |||
2294 | return ret; | ||
2295 | } | ||
2296 | |||
2297 | static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t) | ||
2298 | { | ||
2299 | int match = 0; | ||
2300 | |||
2301 | if (t->mode == m->mode && t->id.proto == m->proto && | ||
2302 | (m->reqid == 0 || t->reqid == m->reqid)) { | ||
2303 | switch (t->mode) { | ||
2304 | case XFRM_MODE_TUNNEL: | ||
2305 | case XFRM_MODE_BEET: | ||
2306 | if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr, | ||
2307 | m->old_family) == 0 && | ||
2308 | xfrm_addr_cmp(&t->saddr, &m->old_saddr, | ||
2309 | m->old_family) == 0) { | ||
2310 | match = 1; | ||
2311 | } | ||
2312 | break; | ||
2313 | case XFRM_MODE_TRANSPORT: | ||
2314 | /* in case of transport mode, template does not store | ||
2315 | any IP addresses, hence we just compare mode and | ||
2316 | protocol */ | ||
2317 | match = 1; | ||
2318 | break; | ||
2319 | default: | ||
2320 | break; | ||
2321 | } | ||
2322 | } | ||
2323 | return match; | ||
2324 | } | ||
2325 | |||
2326 | /* update endpoint address(es) of template(s) */ | ||
2327 | static int xfrm_policy_migrate(struct xfrm_policy *pol, | ||
2328 | struct xfrm_migrate *m, int num_migrate) | ||
2329 | { | ||
2330 | struct xfrm_migrate *mp; | ||
2331 | struct dst_entry *dst; | ||
2332 | int i, j, n = 0; | ||
2333 | |||
2334 | write_lock_bh(&pol->lock); | ||
2335 | if (unlikely(pol->dead)) { | ||
2336 | /* target policy has been deleted */ | ||
2337 | write_unlock_bh(&pol->lock); | ||
2338 | return -ENOENT; | ||
2339 | } | ||
2340 | |||
2341 | for (i = 0; i < pol->xfrm_nr; i++) { | ||
2342 | for (j = 0, mp = m; j < num_migrate; j++, mp++) { | ||
2343 | if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) | ||
2344 | continue; | ||
2345 | n++; | ||
2346 | if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL) | ||
2347 | continue; | ||
2348 | /* update endpoints */ | ||
2349 | memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, | ||
2350 | sizeof(pol->xfrm_vec[i].id.daddr)); | ||
2351 | memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr, | ||
2352 | sizeof(pol->xfrm_vec[i].saddr)); | ||
2353 | pol->xfrm_vec[i].encap_family = mp->new_family; | ||
2354 | /* flush bundles */ | ||
2355 | while ((dst = pol->bundles) != NULL) { | ||
2356 | pol->bundles = dst->next; | ||
2357 | dst_free(dst); | ||
2358 | } | ||
2359 | } | ||
2360 | } | ||
2361 | |||
2362 | write_unlock_bh(&pol->lock); | ||
2363 | |||
2364 | if (!n) | ||
2365 | return -ENODATA; | ||
2366 | |||
2367 | return 0; | ||
2368 | } | ||
2369 | |||
2370 | static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate) | ||
2371 | { | ||
2372 | int i, j; | ||
2373 | |||
2374 | if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) | ||
2375 | return -EINVAL; | ||
2376 | |||
2377 | for (i = 0; i < num_migrate; i++) { | ||
2378 | if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr, | ||
2379 | m[i].old_family) == 0) && | ||
2380 | (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr, | ||
2381 | m[i].old_family) == 0)) | ||
2382 | return -EINVAL; | ||
2383 | if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || | ||
2384 | xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) | ||
2385 | return -EINVAL; | ||
2386 | |||
2387 | /* check if there is any duplicated entry */ | ||
2388 | for (j = i + 1; j < num_migrate; j++) { | ||
2389 | if (!memcmp(&m[i].old_daddr, &m[j].old_daddr, | ||
2390 | sizeof(m[i].old_daddr)) && | ||
2391 | !memcmp(&m[i].old_saddr, &m[j].old_saddr, | ||
2392 | sizeof(m[i].old_saddr)) && | ||
2393 | m[i].proto == m[j].proto && | ||
2394 | m[i].mode == m[j].mode && | ||
2395 | m[i].reqid == m[j].reqid && | ||
2396 | m[i].old_family == m[j].old_family) | ||
2397 | return -EINVAL; | ||
2398 | } | ||
2399 | } | ||
2400 | |||
2401 | return 0; | ||
2402 | } | ||
2403 | |||
2404 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
2405 | struct xfrm_migrate *m, int num_migrate) | ||
2406 | { | ||
2407 | int i, err, nx_cur = 0, nx_new = 0; | ||
2408 | struct xfrm_policy *pol = NULL; | ||
2409 | struct xfrm_state *x, *xc; | ||
2410 | struct xfrm_state *x_cur[XFRM_MAX_DEPTH]; | ||
2411 | struct xfrm_state *x_new[XFRM_MAX_DEPTH]; | ||
2412 | struct xfrm_migrate *mp; | ||
2413 | |||
2414 | if ((err = xfrm_migrate_check(m, num_migrate)) < 0) | ||
2415 | goto out; | ||
2416 | |||
2417 | /* Stage 1 - find policy */ | ||
2418 | if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) { | ||
2419 | err = -ENOENT; | ||
2420 | goto out; | ||
2421 | } | ||
2422 | |||
2423 | /* Stage 2 - find and update state(s) */ | ||
2424 | for (i = 0, mp = m; i < num_migrate; i++, mp++) { | ||
2425 | if ((x = xfrm_migrate_state_find(mp))) { | ||
2426 | x_cur[nx_cur] = x; | ||
2427 | nx_cur++; | ||
2428 | if ((xc = xfrm_state_migrate(x, mp))) { | ||
2429 | x_new[nx_new] = xc; | ||
2430 | nx_new++; | ||
2431 | } else { | ||
2432 | err = -ENODATA; | ||
2433 | goto restore_state; | ||
2434 | } | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | /* Stage 3 - update policy */ | ||
2439 | if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0) | ||
2440 | goto restore_state; | ||
2441 | |||
2442 | /* Stage 4 - delete old state(s) */ | ||
2443 | if (nx_cur) { | ||
2444 | xfrm_states_put(x_cur, nx_cur); | ||
2445 | xfrm_states_delete(x_cur, nx_cur); | ||
2446 | } | ||
2447 | |||
2448 | /* Stage 5 - announce */ | ||
2449 | km_migrate(sel, dir, type, m, num_migrate); | ||
2450 | |||
2451 | xfrm_pol_put(pol); | ||
2452 | |||
2453 | return 0; | ||
2454 | out: | ||
2455 | return err; | ||
2456 | |||
2457 | restore_state: | ||
2458 | if (pol) | ||
2459 | xfrm_pol_put(pol); | ||
2460 | if (nx_cur) | ||
2461 | xfrm_states_put(x_cur, nx_cur); | ||
2462 | if (nx_new) | ||
2463 | xfrm_states_delete(x_new, nx_new); | ||
2464 | |||
2465 | return err; | ||
2466 | } | ||
2467 | EXPORT_SYMBOL(xfrm_migrate); | ||
2468 | #endif | ||
2469 | |||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index fdb08d9f34aa..91b02687db52 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -183,9 +183,6 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
183 | 183 | ||
184 | int __xfrm_state_delete(struct xfrm_state *x); | 184 | int __xfrm_state_delete(struct xfrm_state *x); |
185 | 185 | ||
186 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | ||
187 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
188 | |||
189 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 186 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
190 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | 187 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
191 | 188 | ||
@@ -831,6 +828,160 @@ out: | |||
831 | } | 828 | } |
832 | EXPORT_SYMBOL(xfrm_state_add); | 829 | EXPORT_SYMBOL(xfrm_state_add); |
833 | 830 | ||
831 | #ifdef CONFIG_XFRM_MIGRATE | ||
832 | struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | ||
833 | { | ||
834 | int err = -ENOMEM; | ||
835 | struct xfrm_state *x = xfrm_state_alloc(); | ||
836 | if (!x) | ||
837 | goto error; | ||
838 | |||
839 | memcpy(&x->id, &orig->id, sizeof(x->id)); | ||
840 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | ||
841 | memcpy(&x->lft, &orig->lft, sizeof(x->lft)); | ||
842 | x->props.mode = orig->props.mode; | ||
843 | x->props.replay_window = orig->props.replay_window; | ||
844 | x->props.reqid = orig->props.reqid; | ||
845 | x->props.family = orig->props.family; | ||
846 | x->props.saddr = orig->props.saddr; | ||
847 | |||
848 | if (orig->aalg) { | ||
849 | x->aalg = xfrm_algo_clone(orig->aalg); | ||
850 | if (!x->aalg) | ||
851 | goto error; | ||
852 | } | ||
853 | x->props.aalgo = orig->props.aalgo; | ||
854 | |||
855 | if (orig->ealg) { | ||
856 | x->ealg = xfrm_algo_clone(orig->ealg); | ||
857 | if (!x->ealg) | ||
858 | goto error; | ||
859 | } | ||
860 | x->props.ealgo = orig->props.ealgo; | ||
861 | |||
862 | if (orig->calg) { | ||
863 | x->calg = xfrm_algo_clone(orig->calg); | ||
864 | if (!x->calg) | ||
865 | goto error; | ||
866 | } | ||
867 | x->props.calgo = orig->props.calgo; | ||
868 | |||
869 | if (orig->encap) { | ||
870 | x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); | ||
871 | if (!x->encap) | ||
872 | goto error; | ||
873 | } | ||
874 | |||
875 | if (orig->coaddr) { | ||
876 | x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), | ||
877 | GFP_KERNEL); | ||
878 | if (!x->coaddr) | ||
879 | goto error; | ||
880 | } | ||
881 | |||
882 | err = xfrm_init_state(x); | ||
883 | if (err) | ||
884 | goto error; | ||
885 | |||
886 | x->props.flags = orig->props.flags; | ||
887 | |||
888 | x->curlft.add_time = orig->curlft.add_time; | ||
889 | x->km.state = orig->km.state; | ||
890 | x->km.seq = orig->km.seq; | ||
891 | |||
892 | return x; | ||
893 | |||
894 | error: | ||
895 | if (errp) | ||
896 | *errp = err; | ||
897 | if (x) { | ||
898 | kfree(x->aalg); | ||
899 | kfree(x->ealg); | ||
900 | kfree(x->calg); | ||
901 | kfree(x->encap); | ||
902 | kfree(x->coaddr); | ||
903 | } | ||
904 | kfree(x); | ||
905 | return NULL; | ||
906 | } | ||
907 | EXPORT_SYMBOL(xfrm_state_clone); | ||
908 | |||
909 | /* xfrm_state_lock is held */ | ||
910 | struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | ||
911 | { | ||
912 | unsigned int h; | ||
913 | struct xfrm_state *x; | ||
914 | struct hlist_node *entry; | ||
915 | |||
916 | if (m->reqid) { | ||
917 | h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, | ||
918 | m->reqid, m->old_family); | ||
919 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
920 | if (x->props.mode != m->mode || | ||
921 | x->id.proto != m->proto) | ||
922 | continue; | ||
923 | if (m->reqid && x->props.reqid != m->reqid) | ||
924 | continue; | ||
925 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | ||
926 | m->old_family) || | ||
927 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | ||
928 | m->old_family)) | ||
929 | continue; | ||
930 | xfrm_state_hold(x); | ||
931 | return x; | ||
932 | } | ||
933 | } else { | ||
934 | h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, | ||
935 | m->old_family); | ||
936 | hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { | ||
937 | if (x->props.mode != m->mode || | ||
938 | x->id.proto != m->proto) | ||
939 | continue; | ||
940 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | ||
941 | m->old_family) || | ||
942 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | ||
943 | m->old_family)) | ||
944 | continue; | ||
945 | xfrm_state_hold(x); | ||
946 | return x; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | return NULL; | ||
951 | } | ||
952 | EXPORT_SYMBOL(xfrm_migrate_state_find); | ||
953 | |||
954 | struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, | ||
955 | struct xfrm_migrate *m) | ||
956 | { | ||
957 | struct xfrm_state *xc; | ||
958 | int err; | ||
959 | |||
960 | xc = xfrm_state_clone(x, &err); | ||
961 | if (!xc) | ||
962 | return NULL; | ||
963 | |||
964 | memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); | ||
965 | memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); | ||
966 | |||
967 | /* add state */ | ||
968 | if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { | ||
969 | /* a care is needed when the destination address of the | ||
970 | state is to be updated as it is a part of triplet */ | ||
971 | xfrm_state_insert(xc); | ||
972 | } else { | ||
973 | if ((err = xfrm_state_add(xc)) < 0) | ||
974 | goto error; | ||
975 | } | ||
976 | |||
977 | return xc; | ||
978 | error: | ||
979 | kfree(xc); | ||
980 | return NULL; | ||
981 | } | ||
982 | EXPORT_SYMBOL(xfrm_state_migrate); | ||
983 | #endif | ||
984 | |||
834 | int xfrm_state_update(struct xfrm_state *x) | 985 | int xfrm_state_update(struct xfrm_state *x) |
835 | { | 986 | { |
836 | struct xfrm_state *x1; | 987 | struct xfrm_state *x1; |
@@ -1345,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) | |||
1345 | } | 1496 | } |
1346 | EXPORT_SYMBOL(km_policy_expired); | 1497 | EXPORT_SYMBOL(km_policy_expired); |
1347 | 1498 | ||
1499 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
1500 | struct xfrm_migrate *m, int num_migrate) | ||
1501 | { | ||
1502 | int err = -EINVAL; | ||
1503 | int ret; | ||
1504 | struct xfrm_mgr *km; | ||
1505 | |||
1506 | read_lock(&xfrm_km_lock); | ||
1507 | list_for_each_entry(km, &xfrm_km_list, list) { | ||
1508 | if (km->migrate) { | ||
1509 | ret = km->migrate(sel, dir, type, m, num_migrate); | ||
1510 | if (!ret) | ||
1511 | err = ret; | ||
1512 | } | ||
1513 | } | ||
1514 | read_unlock(&xfrm_km_lock); | ||
1515 | return err; | ||
1516 | } | ||
1517 | EXPORT_SYMBOL(km_migrate); | ||
1518 | |||
1348 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) | 1519 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) |
1349 | { | 1520 | { |
1350 | int err = -EINVAL; | 1521 | int err = -EINVAL; |
@@ -1458,7 +1629,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1458 | } | 1629 | } |
1459 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1630 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1460 | 1631 | ||
1461 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | 1632 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) |
1462 | { | 1633 | { |
1463 | struct xfrm_state_afinfo *afinfo; | 1634 | struct xfrm_state_afinfo *afinfo; |
1464 | if (unlikely(family >= NPROTO)) | 1635 | if (unlikely(family >= NPROTO)) |
@@ -1470,11 +1641,14 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | |||
1470 | return afinfo; | 1641 | return afinfo; |
1471 | } | 1642 | } |
1472 | 1643 | ||
1473 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1644 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1474 | { | 1645 | { |
1475 | read_unlock(&xfrm_state_afinfo_lock); | 1646 | read_unlock(&xfrm_state_afinfo_lock); |
1476 | } | 1647 | } |
1477 | 1648 | ||
1649 | EXPORT_SYMBOL(xfrm_state_get_afinfo); | ||
1650 | EXPORT_SYMBOL(xfrm_state_put_afinfo); | ||
1651 | |||
1478 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ | 1652 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ |
1479 | void xfrm_state_delete_tunnel(struct xfrm_state *x) | 1653 | void xfrm_state_delete_tunnel(struct xfrm_state *x) |
1480 | { | 1654 | { |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 82f36d396fca..079a5d315759 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1632,6 +1632,176 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1632 | return 0; | 1632 | return 0; |
1633 | } | 1633 | } |
1634 | 1634 | ||
1635 | #ifdef CONFIG_XFRM_MIGRATE | ||
1636 | static int verify_user_migrate(struct rtattr **xfrma) | ||
1637 | { | ||
1638 | struct rtattr *rt = xfrma[XFRMA_MIGRATE-1]; | ||
1639 | struct xfrm_user_migrate *um; | ||
1640 | |||
1641 | if (!rt) | ||
1642 | return -EINVAL; | ||
1643 | |||
1644 | if ((rt->rta_len - sizeof(*rt)) < sizeof(*um)) | ||
1645 | return -EINVAL; | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static int copy_from_user_migrate(struct xfrm_migrate *ma, | ||
1651 | struct rtattr **xfrma, int *num) | ||
1652 | { | ||
1653 | struct rtattr *rt = xfrma[XFRMA_MIGRATE-1]; | ||
1654 | struct xfrm_user_migrate *um; | ||
1655 | int i, num_migrate; | ||
1656 | |||
1657 | um = RTA_DATA(rt); | ||
1658 | num_migrate = (rt->rta_len - sizeof(*rt)) / sizeof(*um); | ||
1659 | |||
1660 | if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) | ||
1661 | return -EINVAL; | ||
1662 | |||
1663 | for (i = 0; i < num_migrate; i++, um++, ma++) { | ||
1664 | memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr)); | ||
1665 | memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr)); | ||
1666 | memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr)); | ||
1667 | memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr)); | ||
1668 | |||
1669 | ma->proto = um->proto; | ||
1670 | ma->mode = um->mode; | ||
1671 | ma->reqid = um->reqid; | ||
1672 | |||
1673 | ma->old_family = um->old_family; | ||
1674 | ma->new_family = um->new_family; | ||
1675 | } | ||
1676 | |||
1677 | *num = i; | ||
1678 | return 0; | ||
1679 | } | ||
1680 | |||
1681 | static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
1682 | struct rtattr **xfrma) | ||
1683 | { | ||
1684 | struct xfrm_userpolicy_id *pi = NLMSG_DATA(nlh); | ||
1685 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | ||
1686 | u8 type; | ||
1687 | int err; | ||
1688 | int n = 0; | ||
1689 | |||
1690 | err = verify_user_migrate((struct rtattr **)xfrma); | ||
1691 | if (err) | ||
1692 | return err; | ||
1693 | |||
1694 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1695 | if (err) | ||
1696 | return err; | ||
1697 | |||
1698 | err = copy_from_user_migrate((struct xfrm_migrate *)m, | ||
1699 | (struct rtattr **)xfrma, &n); | ||
1700 | if (err) | ||
1701 | return err; | ||
1702 | |||
1703 | if (!n) | ||
1704 | return 0; | ||
1705 | |||
1706 | xfrm_migrate(&pi->sel, pi->dir, type, m, n); | ||
1707 | |||
1708 | return 0; | ||
1709 | } | ||
1710 | #else | ||
1711 | static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
1712 | struct rtattr **xfrma) | ||
1713 | { | ||
1714 | return -ENOPROTOOPT; | ||
1715 | } | ||
1716 | #endif | ||
1717 | |||
1718 | #ifdef CONFIG_XFRM_MIGRATE | ||
1719 | static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) | ||
1720 | { | ||
1721 | struct xfrm_user_migrate um; | ||
1722 | |||
1723 | memset(&um, 0, sizeof(um)); | ||
1724 | um.proto = m->proto; | ||
1725 | um.mode = m->mode; | ||
1726 | um.reqid = m->reqid; | ||
1727 | um.old_family = m->old_family; | ||
1728 | memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr)); | ||
1729 | memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr)); | ||
1730 | um.new_family = m->new_family; | ||
1731 | memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr)); | ||
1732 | memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr)); | ||
1733 | |||
1734 | RTA_PUT(skb, XFRMA_MIGRATE, sizeof(um), &um); | ||
1735 | return 0; | ||
1736 | |||
1737 | rtattr_failure: | ||
1738 | return -1; | ||
1739 | } | ||
1740 | |||
1741 | static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, | ||
1742 | int num_migrate, struct xfrm_selector *sel, | ||
1743 | u8 dir, u8 type) | ||
1744 | { | ||
1745 | struct xfrm_migrate *mp; | ||
1746 | struct xfrm_userpolicy_id *pol_id; | ||
1747 | struct nlmsghdr *nlh; | ||
1748 | unsigned char *b = skb->tail; | ||
1749 | int i; | ||
1750 | |||
1751 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id)); | ||
1752 | pol_id = NLMSG_DATA(nlh); | ||
1753 | nlh->nlmsg_flags = 0; | ||
1754 | |||
1755 | /* copy data from selector, dir, and type to the pol_id */ | ||
1756 | memset(pol_id, 0, sizeof(*pol_id)); | ||
1757 | memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); | ||
1758 | pol_id->dir = dir; | ||
1759 | |||
1760 | if (copy_to_user_policy_type(type, skb) < 0) | ||
1761 | goto nlmsg_failure; | ||
1762 | |||
1763 | for (i = 0, mp = m ; i < num_migrate; i++, mp++) { | ||
1764 | if (copy_to_user_migrate(mp, skb) < 0) | ||
1765 | goto nlmsg_failure; | ||
1766 | } | ||
1767 | |||
1768 | nlh->nlmsg_len = skb->tail - b; | ||
1769 | return skb->len; | ||
1770 | nlmsg_failure: | ||
1771 | skb_trim(skb, b - skb->data); | ||
1772 | return -1; | ||
1773 | } | ||
1774 | |||
1775 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
1776 | struct xfrm_migrate *m, int num_migrate) | ||
1777 | { | ||
1778 | struct sk_buff *skb; | ||
1779 | size_t len; | ||
1780 | |||
1781 | len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate); | ||
1782 | len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id)); | ||
1783 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1784 | len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); | ||
1785 | #endif | ||
1786 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1787 | if (skb == NULL) | ||
1788 | return -ENOMEM; | ||
1789 | |||
1790 | /* build migrate */ | ||
1791 | if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0) | ||
1792 | BUG(); | ||
1793 | |||
1794 | NETLINK_CB(skb).dst_group = XFRMNLGRP_MIGRATE; | ||
1795 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, | ||
1796 | GFP_ATOMIC); | ||
1797 | } | ||
1798 | #else | ||
1799 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
1800 | struct xfrm_migrate *m, int num_migrate) | ||
1801 | { | ||
1802 | return -ENOPROTOOPT; | ||
1803 | } | ||
1804 | #endif | ||
1635 | 1805 | ||
1636 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) | 1806 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) |
1637 | 1807 | ||
@@ -1653,6 +1823,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1653 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1823 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1654 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1824 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1655 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), | 1825 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), |
1826 | [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), | ||
1656 | }; | 1827 | }; |
1657 | 1828 | ||
1658 | #undef XMSGSIZE | 1829 | #undef XMSGSIZE |
@@ -1679,6 +1850,7 @@ static struct xfrm_link { | |||
1679 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 1850 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
1680 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, | 1851 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, |
1681 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, | 1852 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, |
1853 | [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, | ||
1682 | }; | 1854 | }; |
1683 | 1855 | ||
1684 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1856 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
@@ -2285,6 +2457,7 @@ static struct xfrm_mgr netlink_mgr = { | |||
2285 | .compile_policy = xfrm_compile_policy, | 2457 | .compile_policy = xfrm_compile_policy, |
2286 | .notify_policy = xfrm_send_policy_notify, | 2458 | .notify_policy = xfrm_send_policy_notify, |
2287 | .report = xfrm_send_report, | 2459 | .report = xfrm_send_report, |
2460 | .migrate = xfrm_send_migrate, | ||
2288 | }; | 2461 | }; |
2289 | 2462 | ||
2290 | static int __init xfrm_user_init(void) | 2463 | static int __init xfrm_user_init(void) |