aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorShinta Sugimoto <shinta.sugimoto@ericsson.com>2007-02-08 16:11:42 -0500
committerDavid S. Miller <davem@davemloft.net>2007-02-08 16:11:42 -0500
commit80c9abaabf4283f7cf4a0b3597cd302506635b7f (patch)
tree7dd4270a22e039c827114d182c2071a84826f563 /net
parent9934e81c8c4981342dab3e386aff5d4499bea0d2 (diff)
[XFRM]: Extension for dynamic update of endpoint address(es)
Extend the XFRM framework so that endpoint address(es) in the XFRM databases could be dynamically updated according to a request (MIGRATE message) from user application. Target XFRM policy is first identified by the selector in the MIGRATE message. Next, the endpoint addresses of the matching templates and XFRM states are updated according to the MIGRATE message. Signed-off-by: Shinta Sugimoto <shinta.sugimoto@ericsson.com> Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-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;