aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c230
-rw-r--r--net/xfrm/xfrm_state.c174
2 files changed, 404 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b7e537fe2d75..825c60af7723 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2236,3 +2236,233 @@ void __init xfrm_init(void)
2236 xfrm_input_init(); 2236 xfrm_input_init();
2237} 2237}
2238 2238
2239#ifdef CONFIG_XFRM_MIGRATE
2240static 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
2261static 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
2297static 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) */
2327static 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
2370static 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
2404int 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;
2454out:
2455 return err;
2456
2457restore_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#endif
2468
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 24f7bfd07af2..91b02687db52 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -828,6 +828,160 @@ out:
828} 828}
829EXPORT_SYMBOL(xfrm_state_add); 829EXPORT_SYMBOL(xfrm_state_add);
830 830
831#ifdef CONFIG_XFRM_MIGRATE
832struct 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}
907EXPORT_SYMBOL(xfrm_state_clone);
908
909/* xfrm_state_lock is held */
910struct 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}
952EXPORT_SYMBOL(xfrm_migrate_state_find);
953
954struct 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;
978error:
979 kfree(xc);
980 return NULL;
981}
982EXPORT_SYMBOL(xfrm_state_migrate);
983#endif
984
831int xfrm_state_update(struct xfrm_state *x) 985int xfrm_state_update(struct xfrm_state *x)
832{ 986{
833 struct xfrm_state *x1; 987 struct xfrm_state *x1;
@@ -1342,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
1342} 1496}
1343EXPORT_SYMBOL(km_policy_expired); 1497EXPORT_SYMBOL(km_policy_expired);
1344 1498
1499int 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}
1517EXPORT_SYMBOL(km_migrate);
1518
1345int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 1519int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1346{ 1520{
1347 int err = -EINVAL; 1521 int err = -EINVAL;