diff options
author | Shinta Sugimoto <shinta.sugimoto@ericsson.com> | 2007-02-08 16:14:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-02-08 16:14:33 -0500 |
commit | 08de61beab8a21c8e0b3906a97defda5f1f66ece (patch) | |
tree | f9b49420d9a9a7c13d8b6f0d9488a152d8af3550 | |
parent | d0473655c8293b49808c9488152573beab4458cf (diff) |
[PFKEYV2]: Extension for dynamic update of endpoint address(es)
Extend PF_KEYv2 framework so that user application can take advantage
of MIGRATE feature via PF_KEYv2 interface. User application can either
send or receive an MIGRATE message to/from PF_KEY socket.
Detail information can be found in the internet-draft
<draft-sugimoto-mip6-pfkey-migrate>.
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>
-rw-r--r-- | include/linux/pfkeyv2.h | 3 | ||||
-rw-r--r-- | net/key/af_key.c | 422 |
2 files changed, 424 insertions, 1 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 265bafab6494..26a518b67c02 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h | |||
@@ -251,7 +251,8 @@ struct sadb_x_sec_ctx { | |||
251 | #define SADB_X_SPDEXPIRE 21 | 251 | #define SADB_X_SPDEXPIRE 21 |
252 | #define SADB_X_SPDDELETE2 22 | 252 | #define SADB_X_SPDDELETE2 22 |
253 | #define SADB_X_NAT_T_NEW_MAPPING 23 | 253 | #define SADB_X_NAT_T_NEW_MAPPING 23 |
254 | #define SADB_MAX 23 | 254 | #define SADB_X_MIGRATE 24 |
255 | #define SADB_MAX 24 | ||
255 | 256 | ||
256 | /* Security Association flags */ | 257 | /* Security Association flags */ |
257 | #define SADB_SAFLAGS_PFS 1 | 258 | #define SADB_SAFLAGS_PFS 1 |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 5dd5094659a1..b4e444063d1f 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -2345,6 +2345,196 @@ out: | |||
2345 | return err; | 2345 | return err; |
2346 | } | 2346 | } |
2347 | 2347 | ||
2348 | #ifdef CONFIG_NET_KEY_MIGRATE | ||
2349 | static int pfkey_sockaddr_pair_size(sa_family_t family) | ||
2350 | { | ||
2351 | switch (family) { | ||
2352 | case AF_INET: | ||
2353 | return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2); | ||
2354 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2355 | case AF_INET6: | ||
2356 | return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2); | ||
2357 | #endif | ||
2358 | default: | ||
2359 | return 0; | ||
2360 | } | ||
2361 | /* NOTREACHED */ | ||
2362 | } | ||
2363 | |||
2364 | static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, | ||
2365 | xfrm_address_t *saddr, xfrm_address_t *daddr, | ||
2366 | u16 *family) | ||
2367 | { | ||
2368 | struct sockaddr *sa = (struct sockaddr *)(rq + 1); | ||
2369 | if (rq->sadb_x_ipsecrequest_len < | ||
2370 | pfkey_sockaddr_pair_size(sa->sa_family)) | ||
2371 | return -EINVAL; | ||
2372 | |||
2373 | switch (sa->sa_family) { | ||
2374 | case AF_INET: | ||
2375 | { | ||
2376 | struct sockaddr_in *sin; | ||
2377 | sin = (struct sockaddr_in *)sa; | ||
2378 | if ((sin+1)->sin_family != AF_INET) | ||
2379 | return -EINVAL; | ||
2380 | memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4)); | ||
2381 | sin++; | ||
2382 | memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4)); | ||
2383 | *family = AF_INET; | ||
2384 | break; | ||
2385 | } | ||
2386 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2387 | case AF_INET6: | ||
2388 | { | ||
2389 | struct sockaddr_in6 *sin6; | ||
2390 | sin6 = (struct sockaddr_in6 *)sa; | ||
2391 | if ((sin6+1)->sin6_family != AF_INET6) | ||
2392 | return -EINVAL; | ||
2393 | memcpy(&saddr->a6, &sin6->sin6_addr, | ||
2394 | sizeof(saddr->a6)); | ||
2395 | sin6++; | ||
2396 | memcpy(&daddr->a6, &sin6->sin6_addr, | ||
2397 | sizeof(daddr->a6)); | ||
2398 | *family = AF_INET6; | ||
2399 | break; | ||
2400 | } | ||
2401 | #endif | ||
2402 | default: | ||
2403 | return -EINVAL; | ||
2404 | } | ||
2405 | |||
2406 | return 0; | ||
2407 | } | ||
2408 | |||
2409 | static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | ||
2410 | struct xfrm_migrate *m) | ||
2411 | { | ||
2412 | int err; | ||
2413 | struct sadb_x_ipsecrequest *rq2; | ||
2414 | |||
2415 | if (len <= sizeof(struct sadb_x_ipsecrequest) || | ||
2416 | len < rq1->sadb_x_ipsecrequest_len) | ||
2417 | return -EINVAL; | ||
2418 | |||
2419 | /* old endoints */ | ||
2420 | err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, | ||
2421 | &m->old_family); | ||
2422 | if (err) | ||
2423 | return err; | ||
2424 | |||
2425 | rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); | ||
2426 | len -= rq1->sadb_x_ipsecrequest_len; | ||
2427 | |||
2428 | if (len <= sizeof(struct sadb_x_ipsecrequest) || | ||
2429 | len < rq2->sadb_x_ipsecrequest_len) | ||
2430 | return -EINVAL; | ||
2431 | |||
2432 | /* new endpoints */ | ||
2433 | err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, | ||
2434 | &m->new_family); | ||
2435 | if (err) | ||
2436 | return err; | ||
2437 | |||
2438 | if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto || | ||
2439 | rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode || | ||
2440 | rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid) | ||
2441 | return -EINVAL; | ||
2442 | |||
2443 | m->proto = rq1->sadb_x_ipsecrequest_proto; | ||
2444 | m->mode = rq1->sadb_x_ipsecrequest_mode - 1; | ||
2445 | m->reqid = rq1->sadb_x_ipsecrequest_reqid; | ||
2446 | |||
2447 | return ((int)(rq1->sadb_x_ipsecrequest_len + | ||
2448 | rq2->sadb_x_ipsecrequest_len)); | ||
2449 | } | ||
2450 | |||
2451 | static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | ||
2452 | struct sadb_msg *hdr, void **ext_hdrs) | ||
2453 | { | ||
2454 | int i, len, ret, err = -EINVAL; | ||
2455 | u8 dir; | ||
2456 | struct sadb_address *sa; | ||
2457 | struct sadb_x_policy *pol; | ||
2458 | struct sadb_x_ipsecrequest *rq; | ||
2459 | struct xfrm_selector sel; | ||
2460 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | ||
2461 | |||
2462 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], | ||
2463 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || | ||
2464 | !ext_hdrs[SADB_X_EXT_POLICY - 1]) { | ||
2465 | err = -EINVAL; | ||
2466 | goto out; | ||
2467 | } | ||
2468 | |||
2469 | pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; | ||
2470 | if (!pol) { | ||
2471 | err = -EINVAL; | ||
2472 | goto out; | ||
2473 | } | ||
2474 | |||
2475 | if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { | ||
2476 | err = -EINVAL; | ||
2477 | goto out; | ||
2478 | } | ||
2479 | |||
2480 | dir = pol->sadb_x_policy_dir - 1; | ||
2481 | memset(&sel, 0, sizeof(sel)); | ||
2482 | |||
2483 | /* set source address info of selector */ | ||
2484 | sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1]; | ||
2485 | sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); | ||
2486 | sel.prefixlen_s = sa->sadb_address_prefixlen; | ||
2487 | sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); | ||
2488 | sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port; | ||
2489 | if (sel.sport) | ||
2490 | sel.sport_mask = ~0; | ||
2491 | |||
2492 | /* set destination address info of selector */ | ||
2493 | sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1], | ||
2494 | pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); | ||
2495 | sel.prefixlen_d = sa->sadb_address_prefixlen; | ||
2496 | sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); | ||
2497 | sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port; | ||
2498 | if (sel.dport) | ||
2499 | sel.dport_mask = ~0; | ||
2500 | |||
2501 | rq = (struct sadb_x_ipsecrequest *)(pol + 1); | ||
2502 | |||
2503 | /* extract ipsecrequests */ | ||
2504 | i = 0; | ||
2505 | len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy); | ||
2506 | |||
2507 | while (len > 0 && i < XFRM_MAX_DEPTH) { | ||
2508 | ret = ipsecrequests_to_migrate(rq, len, &m[i]); | ||
2509 | if (ret < 0) { | ||
2510 | err = ret; | ||
2511 | goto out; | ||
2512 | } else { | ||
2513 | rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret); | ||
2514 | len -= ret; | ||
2515 | i++; | ||
2516 | } | ||
2517 | } | ||
2518 | |||
2519 | if (!i || len > 0) { | ||
2520 | err = -EINVAL; | ||
2521 | goto out; | ||
2522 | } | ||
2523 | |||
2524 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); | ||
2525 | |||
2526 | out: | ||
2527 | return err; | ||
2528 | } | ||
2529 | #else | ||
2530 | static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | ||
2531 | struct sadb_msg *hdr, void **ext_hdrs) | ||
2532 | { | ||
2533 | return -ENOPROTOOPT; | ||
2534 | } | ||
2535 | #endif | ||
2536 | |||
2537 | |||
2348 | static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 2538 | static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
2349 | { | 2539 | { |
2350 | unsigned int dir; | 2540 | unsigned int dir; |
@@ -2473,6 +2663,7 @@ static pfkey_handler pfkey_funcs[SADB_MAX + 1] = { | |||
2473 | [SADB_X_SPDFLUSH] = pfkey_spdflush, | 2663 | [SADB_X_SPDFLUSH] = pfkey_spdflush, |
2474 | [SADB_X_SPDSETIDX] = pfkey_spdadd, | 2664 | [SADB_X_SPDSETIDX] = pfkey_spdadd, |
2475 | [SADB_X_SPDDELETE2] = pfkey_spdget, | 2665 | [SADB_X_SPDDELETE2] = pfkey_spdget, |
2666 | [SADB_X_MIGRATE] = pfkey_migrate, | ||
2476 | }; | 2667 | }; |
2477 | 2668 | ||
2478 | static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) | 2669 | static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) |
@@ -3118,6 +3309,236 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, | |||
3118 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); | 3309 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); |
3119 | } | 3310 | } |
3120 | 3311 | ||
3312 | #ifdef CONFIG_NET_KEY_MIGRATE | ||
3313 | static int set_sadb_address(struct sk_buff *skb, int sasize, int type, | ||
3314 | struct xfrm_selector *sel) | ||
3315 | { | ||
3316 | struct sadb_address *addr; | ||
3317 | struct sockaddr_in *sin; | ||
3318 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
3319 | struct sockaddr_in6 *sin6; | ||
3320 | #endif | ||
3321 | addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); | ||
3322 | addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; | ||
3323 | addr->sadb_address_exttype = type; | ||
3324 | addr->sadb_address_proto = sel->proto; | ||
3325 | addr->sadb_address_reserved = 0; | ||
3326 | |||
3327 | switch (type) { | ||
3328 | case SADB_EXT_ADDRESS_SRC: | ||
3329 | if (sel->family == AF_INET) { | ||
3330 | addr->sadb_address_prefixlen = sel->prefixlen_s; | ||
3331 | sin = (struct sockaddr_in *)(addr + 1); | ||
3332 | sin->sin_family = AF_INET; | ||
3333 | memcpy(&sin->sin_addr.s_addr, &sel->saddr, | ||
3334 | sizeof(sin->sin_addr.s_addr)); | ||
3335 | sin->sin_port = 0; | ||
3336 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | ||
3337 | } | ||
3338 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
3339 | else if (sel->family == AF_INET6) { | ||
3340 | addr->sadb_address_prefixlen = sel->prefixlen_s; | ||
3341 | sin6 = (struct sockaddr_in6 *)(addr + 1); | ||
3342 | sin6->sin6_family = AF_INET6; | ||
3343 | sin6->sin6_port = 0; | ||
3344 | sin6->sin6_flowinfo = 0; | ||
3345 | sin6->sin6_scope_id = 0; | ||
3346 | memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr, | ||
3347 | sizeof(sin6->sin6_addr.s6_addr)); | ||
3348 | } | ||
3349 | #endif | ||
3350 | break; | ||
3351 | case SADB_EXT_ADDRESS_DST: | ||
3352 | if (sel->family == AF_INET) { | ||
3353 | addr->sadb_address_prefixlen = sel->prefixlen_d; | ||
3354 | sin = (struct sockaddr_in *)(addr + 1); | ||
3355 | sin->sin_family = AF_INET; | ||
3356 | memcpy(&sin->sin_addr.s_addr, &sel->daddr, | ||
3357 | sizeof(sin->sin_addr.s_addr)); | ||
3358 | sin->sin_port = 0; | ||
3359 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | ||
3360 | } | ||
3361 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
3362 | else if (sel->family == AF_INET6) { | ||
3363 | addr->sadb_address_prefixlen = sel->prefixlen_d; | ||
3364 | sin6 = (struct sockaddr_in6 *)(addr + 1); | ||
3365 | sin6->sin6_family = AF_INET6; | ||
3366 | sin6->sin6_port = 0; | ||
3367 | sin6->sin6_flowinfo = 0; | ||
3368 | sin6->sin6_scope_id = 0; | ||
3369 | memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr, | ||
3370 | sizeof(sin6->sin6_addr.s6_addr)); | ||
3371 | } | ||
3372 | #endif | ||
3373 | break; | ||
3374 | default: | ||
3375 | return -EINVAL; | ||
3376 | } | ||
3377 | |||
3378 | return 0; | ||
3379 | } | ||
3380 | |||
3381 | static int set_ipsecrequest(struct sk_buff *skb, | ||
3382 | uint8_t proto, uint8_t mode, int level, | ||
3383 | uint32_t reqid, uint8_t family, | ||
3384 | xfrm_address_t *src, xfrm_address_t *dst) | ||
3385 | { | ||
3386 | struct sadb_x_ipsecrequest *rq; | ||
3387 | struct sockaddr_in *sin; | ||
3388 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
3389 | struct sockaddr_in6 *sin6; | ||
3390 | #endif | ||
3391 | int size_req; | ||
3392 | |||
3393 | size_req = sizeof(struct sadb_x_ipsecrequest) + | ||
3394 | pfkey_sockaddr_pair_size(family); | ||
3395 | |||
3396 | rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req); | ||
3397 | memset(rq, 0, size_req); | ||
3398 | rq->sadb_x_ipsecrequest_len = size_req; | ||
3399 | rq->sadb_x_ipsecrequest_proto = proto; | ||
3400 | rq->sadb_x_ipsecrequest_mode = mode; | ||
3401 | rq->sadb_x_ipsecrequest_level = level; | ||
3402 | rq->sadb_x_ipsecrequest_reqid = reqid; | ||
3403 | |||
3404 | switch (family) { | ||
3405 | case AF_INET: | ||
3406 | sin = (struct sockaddr_in *)(rq + 1); | ||
3407 | sin->sin_family = AF_INET; | ||
3408 | memcpy(&sin->sin_addr.s_addr, src, | ||
3409 | sizeof(sin->sin_addr.s_addr)); | ||
3410 | sin++; | ||
3411 | sin->sin_family = AF_INET; | ||
3412 | memcpy(&sin->sin_addr.s_addr, dst, | ||
3413 | sizeof(sin->sin_addr.s_addr)); | ||
3414 | break; | ||
3415 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
3416 | case AF_INET6: | ||
3417 | sin6 = (struct sockaddr_in6 *)(rq + 1); | ||
3418 | sin6->sin6_family = AF_INET6; | ||
3419 | sin6->sin6_port = 0; | ||
3420 | sin6->sin6_flowinfo = 0; | ||
3421 | sin6->sin6_scope_id = 0; | ||
3422 | memcpy(&sin6->sin6_addr.s6_addr, src, | ||
3423 | sizeof(sin6->sin6_addr.s6_addr)); | ||
3424 | sin6++; | ||
3425 | sin6->sin6_family = AF_INET6; | ||
3426 | sin6->sin6_port = 0; | ||
3427 | sin6->sin6_flowinfo = 0; | ||
3428 | sin6->sin6_scope_id = 0; | ||
3429 | memcpy(&sin6->sin6_addr.s6_addr, dst, | ||
3430 | sizeof(sin6->sin6_addr.s6_addr)); | ||
3431 | break; | ||
3432 | #endif | ||
3433 | default: | ||
3434 | return -EINVAL; | ||
3435 | } | ||
3436 | |||
3437 | return 0; | ||
3438 | } | ||
3439 | #endif | ||
3440 | |||
3441 | #ifdef CONFIG_NET_KEY_MIGRATE | ||
3442 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
3443 | struct xfrm_migrate *m, int num_bundles) | ||
3444 | { | ||
3445 | int i; | ||
3446 | int sasize_sel; | ||
3447 | int size = 0; | ||
3448 | int size_pol = 0; | ||
3449 | struct sk_buff *skb; | ||
3450 | struct sadb_msg *hdr; | ||
3451 | struct sadb_x_policy *pol; | ||
3452 | struct xfrm_migrate *mp; | ||
3453 | |||
3454 | if (type != XFRM_POLICY_TYPE_MAIN) | ||
3455 | return 0; | ||
3456 | |||
3457 | if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) | ||
3458 | return -EINVAL; | ||
3459 | |||
3460 | /* selector */ | ||
3461 | sasize_sel = pfkey_sockaddr_size(sel->family); | ||
3462 | if (!sasize_sel) | ||
3463 | return -EINVAL; | ||
3464 | size += (sizeof(struct sadb_address) + sasize_sel) * 2; | ||
3465 | |||
3466 | /* policy info */ | ||
3467 | size_pol += sizeof(struct sadb_x_policy); | ||
3468 | |||
3469 | /* ipsecrequests */ | ||
3470 | for (i = 0, mp = m; i < num_bundles; i++, mp++) { | ||
3471 | /* old locator pair */ | ||
3472 | size_pol += sizeof(struct sadb_x_ipsecrequest) + | ||
3473 | pfkey_sockaddr_pair_size(mp->old_family); | ||
3474 | /* new locator pair */ | ||
3475 | size_pol += sizeof(struct sadb_x_ipsecrequest) + | ||
3476 | pfkey_sockaddr_pair_size(mp->new_family); | ||
3477 | } | ||
3478 | |||
3479 | size += sizeof(struct sadb_msg) + size_pol; | ||
3480 | |||
3481 | /* alloc buffer */ | ||
3482 | skb = alloc_skb(size, GFP_ATOMIC); | ||
3483 | if (skb == NULL) | ||
3484 | return -ENOMEM; | ||
3485 | |||
3486 | hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg)); | ||
3487 | hdr->sadb_msg_version = PF_KEY_V2; | ||
3488 | hdr->sadb_msg_type = SADB_X_MIGRATE; | ||
3489 | hdr->sadb_msg_satype = pfkey_proto2satype(m->proto); | ||
3490 | hdr->sadb_msg_len = size / 8; | ||
3491 | hdr->sadb_msg_errno = 0; | ||
3492 | hdr->sadb_msg_reserved = 0; | ||
3493 | hdr->sadb_msg_seq = 0; | ||
3494 | hdr->sadb_msg_pid = 0; | ||
3495 | |||
3496 | /* selector src */ | ||
3497 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); | ||
3498 | |||
3499 | /* selector dst */ | ||
3500 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel); | ||
3501 | |||
3502 | /* policy information */ | ||
3503 | pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy)); | ||
3504 | pol->sadb_x_policy_len = size_pol / 8; | ||
3505 | pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; | ||
3506 | pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; | ||
3507 | pol->sadb_x_policy_dir = dir + 1; | ||
3508 | pol->sadb_x_policy_id = 0; | ||
3509 | pol->sadb_x_policy_priority = 0; | ||
3510 | |||
3511 | for (i = 0, mp = m; i < num_bundles; i++, mp++) { | ||
3512 | /* old ipsecrequest */ | ||
3513 | if (set_ipsecrequest(skb, mp->proto, mp->mode + 1, | ||
3514 | (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), | ||
3515 | mp->reqid, mp->old_family, | ||
3516 | &mp->old_saddr, &mp->old_daddr) < 0) { | ||
3517 | return -EINVAL; | ||
3518 | } | ||
3519 | |||
3520 | /* new ipsecrequest */ | ||
3521 | if (set_ipsecrequest(skb, mp->proto, mp->mode + 1, | ||
3522 | (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), | ||
3523 | mp->reqid, mp->new_family, | ||
3524 | &mp->new_saddr, &mp->new_daddr) < 0) { | ||
3525 | return -EINVAL; | ||
3526 | } | ||
3527 | } | ||
3528 | |||
3529 | /* broadcast migrate message to sockets */ | ||
3530 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); | ||
3531 | |||
3532 | return 0; | ||
3533 | } | ||
3534 | #else | ||
3535 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
3536 | struct xfrm_migrate *m, int num_bundles) | ||
3537 | { | ||
3538 | return -ENOPROTOOPT; | ||
3539 | } | ||
3540 | #endif | ||
3541 | |||
3121 | static int pfkey_sendmsg(struct kiocb *kiocb, | 3542 | static int pfkey_sendmsg(struct kiocb *kiocb, |
3122 | struct socket *sock, struct msghdr *msg, size_t len) | 3543 | struct socket *sock, struct msghdr *msg, size_t len) |
3123 | { | 3544 | { |
@@ -3287,6 +3708,7 @@ static struct xfrm_mgr pfkeyv2_mgr = | |||
3287 | .compile_policy = pfkey_compile_policy, | 3708 | .compile_policy = pfkey_compile_policy, |
3288 | .new_mapping = pfkey_send_new_mapping, | 3709 | .new_mapping = pfkey_send_new_mapping, |
3289 | .notify_policy = pfkey_send_policy_notify, | 3710 | .notify_policy = pfkey_send_policy_notify, |
3711 | .migrate = pfkey_send_migrate, | ||
3290 | }; | 3712 | }; |
3291 | 3713 | ||
3292 | static void __exit ipsec_pfkey_exit(void) | 3714 | static void __exit ipsec_pfkey_exit(void) |