diff options
author | Arnaud Ebalard <arno@natisbad.org> | 2008-10-05 16:33:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-05 16:33:42 -0400 |
commit | 13c1d18931ebb5cf407cb348ef2cd6284d68902d (patch) | |
tree | 6d590f85e48b4cce8f67e42c65b88fce8fcc49c6 | |
parent | 95430c0b140c31cb9e39f876afe1c0e9947d1aaf (diff) |
xfrm: MIGRATE enhancements (draft-ebalard-mext-pfkey-enhanced-migrate)
Provides implementation of the enhancements of XFRM/PF_KEY MIGRATE mechanism
specified in draft-ebalard-mext-pfkey-enhanced-migrate-00. Defines associated
PF_KEY SADB_X_EXT_KMADDRESS extension and XFRM/netlink XFRMA_KMADDRESS
attribute.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/pfkeyv2.h | 13 | ||||
-rw-r--r-- | include/linux/xfrm.h | 10 | ||||
-rw-r--r-- | include/net/xfrm.h | 15 | ||||
-rw-r--r-- | net/key/af_key.c | 86 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 5 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 5 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 57 |
7 files changed, 154 insertions, 37 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 700725ddcaae..01b262959f2e 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h | |||
@@ -226,6 +226,15 @@ struct sadb_x_sec_ctx { | |||
226 | } __attribute__((packed)); | 226 | } __attribute__((packed)); |
227 | /* sizeof(struct sadb_sec_ctx) = 8 */ | 227 | /* sizeof(struct sadb_sec_ctx) = 8 */ |
228 | 228 | ||
229 | /* Used by MIGRATE to pass addresses IKE will use to perform | ||
230 | * negotiation with the peer */ | ||
231 | struct sadb_x_kmaddress { | ||
232 | uint16_t sadb_x_kmaddress_len; | ||
233 | uint16_t sadb_x_kmaddress_exttype; | ||
234 | uint32_t sadb_x_kmaddress_reserved; | ||
235 | } __attribute__((packed)); | ||
236 | /* sizeof(struct sadb_x_kmaddress) == 8 */ | ||
237 | |||
229 | /* Message types */ | 238 | /* Message types */ |
230 | #define SADB_RESERVED 0 | 239 | #define SADB_RESERVED 0 |
231 | #define SADB_GETSPI 1 | 240 | #define SADB_GETSPI 1 |
@@ -346,7 +355,9 @@ struct sadb_x_sec_ctx { | |||
346 | #define SADB_X_EXT_NAT_T_DPORT 22 | 355 | #define SADB_X_EXT_NAT_T_DPORT 22 |
347 | #define SADB_X_EXT_NAT_T_OA 23 | 356 | #define SADB_X_EXT_NAT_T_OA 23 |
348 | #define SADB_X_EXT_SEC_CTX 24 | 357 | #define SADB_X_EXT_SEC_CTX 24 |
349 | #define SADB_EXT_MAX 24 | 358 | /* Used with MIGRATE to pass @ to IKE for negotiation */ |
359 | #define SADB_X_EXT_KMADDRESS 25 | ||
360 | #define SADB_EXT_MAX 25 | ||
350 | 361 | ||
351 | /* Identity Extension values */ | 362 | /* Identity Extension values */ |
352 | #define SADB_IDENTTYPE_RESERVED 0 | 363 | #define SADB_IDENTTYPE_RESERVED 0 |
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index fb0c215a3051..4bc1e6b86cb2 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -279,6 +279,7 @@ enum xfrm_attr_type_t { | |||
279 | XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ | 279 | XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ |
280 | XFRMA_MIGRATE, | 280 | XFRMA_MIGRATE, |
281 | XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */ | 281 | XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */ |
282 | XFRMA_KMADDRESS, /* struct xfrm_user_kmaddress */ | ||
282 | __XFRMA_MAX | 283 | __XFRMA_MAX |
283 | 284 | ||
284 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 285 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
@@ -415,6 +416,15 @@ struct xfrm_user_report { | |||
415 | struct xfrm_selector sel; | 416 | struct xfrm_selector sel; |
416 | }; | 417 | }; |
417 | 418 | ||
419 | /* Used by MIGRATE to pass addresses IKE should use to perform | ||
420 | * SA negotiation with the peer */ | ||
421 | struct xfrm_user_kmaddress { | ||
422 | xfrm_address_t local; | ||
423 | xfrm_address_t remote; | ||
424 | __u32 reserved; | ||
425 | __u16 family; | ||
426 | }; | ||
427 | |||
418 | struct xfrm_user_migrate { | 428 | struct xfrm_user_migrate { |
419 | xfrm_address_t old_daddr; | 429 | xfrm_address_t old_daddr; |
420 | xfrm_address_t old_saddr; | 430 | xfrm_address_t old_saddr; |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index b98d2056f27f..11c890ad8ebb 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -492,6 +492,13 @@ struct xfrm_policy | |||
492 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; | 492 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; |
493 | }; | 493 | }; |
494 | 494 | ||
495 | struct xfrm_kmaddress { | ||
496 | xfrm_address_t local; | ||
497 | xfrm_address_t remote; | ||
498 | u32 reserved; | ||
499 | u16 family; | ||
500 | }; | ||
501 | |||
495 | struct xfrm_migrate { | 502 | struct xfrm_migrate { |
496 | xfrm_address_t old_daddr; | 503 | xfrm_address_t old_daddr; |
497 | xfrm_address_t old_saddr; | 504 | xfrm_address_t old_saddr; |
@@ -531,7 +538,7 @@ struct xfrm_mgr | |||
531 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); | 538 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); |
532 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); | 539 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); |
533 | int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); | 540 | int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); |
534 | int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles); | 541 | int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k); |
535 | }; | 542 | }; |
536 | 543 | ||
537 | extern int xfrm_register_km(struct xfrm_mgr *km); | 544 | extern int xfrm_register_km(struct xfrm_mgr *km); |
@@ -1432,12 +1439,14 @@ extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, | |||
1432 | 1439 | ||
1433 | #ifdef CONFIG_XFRM_MIGRATE | 1440 | #ifdef CONFIG_XFRM_MIGRATE |
1434 | extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1441 | extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1435 | struct xfrm_migrate *m, int num_bundles); | 1442 | struct xfrm_migrate *m, int num_bundles, |
1443 | struct xfrm_kmaddress *k); | ||
1436 | extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m); | 1444 | extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m); |
1437 | extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, | 1445 | extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, |
1438 | struct xfrm_migrate *m); | 1446 | struct xfrm_migrate *m); |
1439 | extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1447 | extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1440 | struct xfrm_migrate *m, int num_bundles); | 1448 | struct xfrm_migrate *m, int num_bundles, |
1449 | struct xfrm_kmaddress *k); | ||
1441 | #endif | 1450 | #endif |
1442 | 1451 | ||
1443 | extern wait_queue_head_t km_waitq; | 1452 | extern wait_queue_head_t km_waitq; |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 7ae641df70bd..362fe317e1f3 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -398,6 +398,7 @@ static u8 sadb_ext_min_len[] = { | |||
398 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), | 398 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), |
399 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), | 399 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), |
400 | [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), | 400 | [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), |
401 | [SADB_X_EXT_KMADDRESS] = (u8) sizeof(struct sadb_x_kmaddress), | ||
401 | }; | 402 | }; |
402 | 403 | ||
403 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ | 404 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ |
@@ -2384,24 +2385,21 @@ static int pfkey_sockaddr_pair_size(sa_family_t family) | |||
2384 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); | 2385 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); |
2385 | } | 2386 | } |
2386 | 2387 | ||
2387 | static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, | 2388 | static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, |
2388 | xfrm_address_t *saddr, xfrm_address_t *daddr, | 2389 | xfrm_address_t *saddr, xfrm_address_t *daddr, |
2389 | u16 *family) | 2390 | u16 *family) |
2390 | { | 2391 | { |
2391 | u8 *sa = (u8 *) (rq + 1); | ||
2392 | int af, socklen; | 2392 | int af, socklen; |
2393 | 2393 | ||
2394 | if (rq->sadb_x_ipsecrequest_len < | 2394 | if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) |
2395 | pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family)) | ||
2396 | return -EINVAL; | 2395 | return -EINVAL; |
2397 | 2396 | ||
2398 | af = pfkey_sockaddr_extract((struct sockaddr *) sa, | 2397 | af = pfkey_sockaddr_extract(sa, saddr); |
2399 | saddr); | ||
2400 | if (!af) | 2398 | if (!af) |
2401 | return -EINVAL; | 2399 | return -EINVAL; |
2402 | 2400 | ||
2403 | socklen = pfkey_sockaddr_len(af); | 2401 | socklen = pfkey_sockaddr_len(af); |
2404 | if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen), | 2402 | if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen), |
2405 | daddr) != af) | 2403 | daddr) != af) |
2406 | return -EINVAL; | 2404 | return -EINVAL; |
2407 | 2405 | ||
@@ -2421,7 +2419,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2421 | return -EINVAL; | 2419 | return -EINVAL; |
2422 | 2420 | ||
2423 | /* old endoints */ | 2421 | /* old endoints */ |
2424 | err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, | 2422 | err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), |
2423 | rq1->sadb_x_ipsecrequest_len, | ||
2424 | &m->old_saddr, &m->old_daddr, | ||
2425 | &m->old_family); | 2425 | &m->old_family); |
2426 | if (err) | 2426 | if (err) |
2427 | return err; | 2427 | return err; |
@@ -2434,7 +2434,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2434 | return -EINVAL; | 2434 | return -EINVAL; |
2435 | 2435 | ||
2436 | /* new endpoints */ | 2436 | /* new endpoints */ |
2437 | err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, | 2437 | err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), |
2438 | rq2->sadb_x_ipsecrequest_len, | ||
2439 | &m->new_saddr, &m->new_daddr, | ||
2438 | &m->new_family); | 2440 | &m->new_family); |
2439 | if (err) | 2441 | if (err) |
2440 | return err; | 2442 | return err; |
@@ -2460,29 +2462,40 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
2460 | int i, len, ret, err = -EINVAL; | 2462 | int i, len, ret, err = -EINVAL; |
2461 | u8 dir; | 2463 | u8 dir; |
2462 | struct sadb_address *sa; | 2464 | struct sadb_address *sa; |
2465 | struct sadb_x_kmaddress *kma; | ||
2463 | struct sadb_x_policy *pol; | 2466 | struct sadb_x_policy *pol; |
2464 | struct sadb_x_ipsecrequest *rq; | 2467 | struct sadb_x_ipsecrequest *rq; |
2465 | struct xfrm_selector sel; | 2468 | struct xfrm_selector sel; |
2466 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | 2469 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; |
2470 | struct xfrm_kmaddress k; | ||
2467 | 2471 | ||
2468 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], | 2472 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], |
2469 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || | 2473 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || |
2470 | !ext_hdrs[SADB_X_EXT_POLICY - 1]) { | 2474 | !ext_hdrs[SADB_X_EXT_POLICY - 1]) { |
2471 | err = -EINVAL; | 2475 | err = -EINVAL; |
2472 | goto out; | 2476 | goto out; |
2473 | } | 2477 | } |
2474 | 2478 | ||
2479 | kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1]; | ||
2475 | pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; | 2480 | pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; |
2476 | if (!pol) { | ||
2477 | err = -EINVAL; | ||
2478 | goto out; | ||
2479 | } | ||
2480 | 2481 | ||
2481 | if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { | 2482 | if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { |
2482 | err = -EINVAL; | 2483 | err = -EINVAL; |
2483 | goto out; | 2484 | goto out; |
2484 | } | 2485 | } |
2485 | 2486 | ||
2487 | if (kma) { | ||
2488 | /* convert sadb_x_kmaddress to xfrm_kmaddress */ | ||
2489 | k.reserved = kma->sadb_x_kmaddress_reserved; | ||
2490 | ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1), | ||
2491 | 8*(kma->sadb_x_kmaddress_len) - sizeof(*kma), | ||
2492 | &k.local, &k.remote, &k.family); | ||
2493 | if (ret < 0) { | ||
2494 | err = ret; | ||
2495 | goto out; | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2486 | dir = pol->sadb_x_policy_dir - 1; | 2499 | dir = pol->sadb_x_policy_dir - 1; |
2487 | memset(&sel, 0, sizeof(sel)); | 2500 | memset(&sel, 0, sizeof(sel)); |
2488 | 2501 | ||
@@ -2527,7 +2540,8 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
2527 | goto out; | 2540 | goto out; |
2528 | } | 2541 | } |
2529 | 2542 | ||
2530 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); | 2543 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, |
2544 | kma ? &k : NULL); | ||
2531 | 2545 | ||
2532 | out: | 2546 | out: |
2533 | return err; | 2547 | return err; |
@@ -3319,6 +3333,32 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type, | |||
3319 | return 0; | 3333 | return 0; |
3320 | } | 3334 | } |
3321 | 3335 | ||
3336 | |||
3337 | static int set_sadb_kmaddress(struct sk_buff *skb, struct xfrm_kmaddress *k) | ||
3338 | { | ||
3339 | struct sadb_x_kmaddress *kma; | ||
3340 | u8 *sa; | ||
3341 | int family = k->family; | ||
3342 | int socklen = pfkey_sockaddr_len(family); | ||
3343 | int size_req; | ||
3344 | |||
3345 | size_req = (sizeof(struct sadb_x_kmaddress) + | ||
3346 | pfkey_sockaddr_pair_size(family)); | ||
3347 | |||
3348 | kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req); | ||
3349 | memset(kma, 0, size_req); | ||
3350 | kma->sadb_x_kmaddress_len = size_req / 8; | ||
3351 | kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS; | ||
3352 | kma->sadb_x_kmaddress_reserved = k->reserved; | ||
3353 | |||
3354 | sa = (u8 *)(kma + 1); | ||
3355 | if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) || | ||
3356 | !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family)) | ||
3357 | return -EINVAL; | ||
3358 | |||
3359 | return 0; | ||
3360 | } | ||
3361 | |||
3322 | static int set_ipsecrequest(struct sk_buff *skb, | 3362 | static int set_ipsecrequest(struct sk_buff *skb, |
3323 | uint8_t proto, uint8_t mode, int level, | 3363 | uint8_t proto, uint8_t mode, int level, |
3324 | uint32_t reqid, uint8_t family, | 3364 | uint32_t reqid, uint8_t family, |
@@ -3351,7 +3391,8 @@ static int set_ipsecrequest(struct sk_buff *skb, | |||
3351 | 3391 | ||
3352 | #ifdef CONFIG_NET_KEY_MIGRATE | 3392 | #ifdef CONFIG_NET_KEY_MIGRATE |
3353 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 3393 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
3354 | struct xfrm_migrate *m, int num_bundles) | 3394 | struct xfrm_migrate *m, int num_bundles, |
3395 | struct xfrm_kmaddress *k) | ||
3355 | { | 3396 | { |
3356 | int i; | 3397 | int i; |
3357 | int sasize_sel; | 3398 | int sasize_sel; |
@@ -3368,6 +3409,12 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
3368 | if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) | 3409 | if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) |
3369 | return -EINVAL; | 3410 | return -EINVAL; |
3370 | 3411 | ||
3412 | if (k != NULL) { | ||
3413 | /* addresses for KM */ | ||
3414 | size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) + | ||
3415 | pfkey_sockaddr_pair_size(k->family)); | ||
3416 | } | ||
3417 | |||
3371 | /* selector */ | 3418 | /* selector */ |
3372 | sasize_sel = pfkey_sockaddr_size(sel->family); | 3419 | sasize_sel = pfkey_sockaddr_size(sel->family); |
3373 | if (!sasize_sel) | 3420 | if (!sasize_sel) |
@@ -3404,6 +3451,10 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
3404 | hdr->sadb_msg_seq = 0; | 3451 | hdr->sadb_msg_seq = 0; |
3405 | hdr->sadb_msg_pid = 0; | 3452 | hdr->sadb_msg_pid = 0; |
3406 | 3453 | ||
3454 | /* Addresses to be used by KM for negotiation, if ext is available */ | ||
3455 | if (k != NULL && (set_sadb_kmaddress(skb, k) < 0)) | ||
3456 | return -EINVAL; | ||
3457 | |||
3407 | /* selector src */ | 3458 | /* selector src */ |
3408 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); | 3459 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); |
3409 | 3460 | ||
@@ -3449,7 +3500,8 @@ err: | |||
3449 | } | 3500 | } |
3450 | #else | 3501 | #else |
3451 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 3502 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
3452 | struct xfrm_migrate *m, int num_bundles) | 3503 | struct xfrm_migrate *m, int num_bundles, |
3504 | struct xfrm_kmaddress *k) | ||
3453 | { | 3505 | { |
3454 | return -ENOPROTOOPT; | 3506 | return -ENOPROTOOPT; |
3455 | } | 3507 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b7ec08025ffb..832b47c1de80 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -2679,7 +2679,8 @@ static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate) | |||
2679 | } | 2679 | } |
2680 | 2680 | ||
2681 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 2681 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
2682 | struct xfrm_migrate *m, int num_migrate) | 2682 | struct xfrm_migrate *m, int num_migrate, |
2683 | struct xfrm_kmaddress *k) | ||
2683 | { | 2684 | { |
2684 | int i, err, nx_cur = 0, nx_new = 0; | 2685 | int i, err, nx_cur = 0, nx_new = 0; |
2685 | struct xfrm_policy *pol = NULL; | 2686 | struct xfrm_policy *pol = NULL; |
@@ -2723,7 +2724,7 @@ int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
2723 | } | 2724 | } |
2724 | 2725 | ||
2725 | /* Stage 5 - announce */ | 2726 | /* Stage 5 - announce */ |
2726 | km_migrate(sel, dir, type, m, num_migrate); | 2727 | km_migrate(sel, dir, type, m, num_migrate, k); |
2727 | 2728 | ||
2728 | xfrm_pol_put(pol); | 2729 | xfrm_pol_put(pol); |
2729 | 2730 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 747fd8c291a7..508337f97249 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -1814,7 +1814,8 @@ EXPORT_SYMBOL(km_policy_expired); | |||
1814 | 1814 | ||
1815 | #ifdef CONFIG_XFRM_MIGRATE | 1815 | #ifdef CONFIG_XFRM_MIGRATE |
1816 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1816 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1817 | struct xfrm_migrate *m, int num_migrate) | 1817 | struct xfrm_migrate *m, int num_migrate, |
1818 | struct xfrm_kmaddress *k) | ||
1818 | { | 1819 | { |
1819 | int err = -EINVAL; | 1820 | int err = -EINVAL; |
1820 | int ret; | 1821 | int ret; |
@@ -1823,7 +1824,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
1823 | read_lock(&xfrm_km_lock); | 1824 | read_lock(&xfrm_km_lock); |
1824 | list_for_each_entry(km, &xfrm_km_list, list) { | 1825 | list_for_each_entry(km, &xfrm_km_list, list) { |
1825 | if (km->migrate) { | 1826 | if (km->migrate) { |
1826 | ret = km->migrate(sel, dir, type, m, num_migrate); | 1827 | ret = km->migrate(sel, dir, type, m, num_migrate, k); |
1827 | if (!ret) | 1828 | if (!ret) |
1828 | err = ret; | 1829 | err = ret; |
1829 | } | 1830 | } |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 76f75df21e15..4a8a1abb59ee 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1710,12 +1710,23 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1710 | 1710 | ||
1711 | #ifdef CONFIG_XFRM_MIGRATE | 1711 | #ifdef CONFIG_XFRM_MIGRATE |
1712 | static int copy_from_user_migrate(struct xfrm_migrate *ma, | 1712 | static int copy_from_user_migrate(struct xfrm_migrate *ma, |
1713 | struct xfrm_kmaddress *k, | ||
1713 | struct nlattr **attrs, int *num) | 1714 | struct nlattr **attrs, int *num) |
1714 | { | 1715 | { |
1715 | struct nlattr *rt = attrs[XFRMA_MIGRATE]; | 1716 | struct nlattr *rt = attrs[XFRMA_MIGRATE]; |
1716 | struct xfrm_user_migrate *um; | 1717 | struct xfrm_user_migrate *um; |
1717 | int i, num_migrate; | 1718 | int i, num_migrate; |
1718 | 1719 | ||
1720 | if (k != NULL) { | ||
1721 | struct xfrm_user_kmaddress *uk; | ||
1722 | |||
1723 | uk = nla_data(attrs[XFRMA_KMADDRESS]); | ||
1724 | memcpy(&k->local, &uk->local, sizeof(k->local)); | ||
1725 | memcpy(&k->remote, &uk->remote, sizeof(k->remote)); | ||
1726 | k->family = uk->family; | ||
1727 | k->reserved = uk->reserved; | ||
1728 | } | ||
1729 | |||
1719 | um = nla_data(rt); | 1730 | um = nla_data(rt); |
1720 | num_migrate = nla_len(rt) / sizeof(*um); | 1731 | num_migrate = nla_len(rt) / sizeof(*um); |
1721 | 1732 | ||
@@ -1745,6 +1756,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1745 | { | 1756 | { |
1746 | struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); | 1757 | struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); |
1747 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | 1758 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; |
1759 | struct xfrm_kmaddress km, *kmp; | ||
1748 | u8 type; | 1760 | u8 type; |
1749 | int err; | 1761 | int err; |
1750 | int n = 0; | 1762 | int n = 0; |
@@ -1752,19 +1764,20 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1752 | if (attrs[XFRMA_MIGRATE] == NULL) | 1764 | if (attrs[XFRMA_MIGRATE] == NULL) |
1753 | return -EINVAL; | 1765 | return -EINVAL; |
1754 | 1766 | ||
1767 | kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL; | ||
1768 | |||
1755 | err = copy_from_user_policy_type(&type, attrs); | 1769 | err = copy_from_user_policy_type(&type, attrs); |
1756 | if (err) | 1770 | if (err) |
1757 | return err; | 1771 | return err; |
1758 | 1772 | ||
1759 | err = copy_from_user_migrate((struct xfrm_migrate *)m, | 1773 | err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n); |
1760 | attrs, &n); | ||
1761 | if (err) | 1774 | if (err) |
1762 | return err; | 1775 | return err; |
1763 | 1776 | ||
1764 | if (!n) | 1777 | if (!n) |
1765 | return 0; | 1778 | return 0; |
1766 | 1779 | ||
1767 | xfrm_migrate(&pi->sel, pi->dir, type, m, n); | 1780 | xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp); |
1768 | 1781 | ||
1769 | return 0; | 1782 | return 0; |
1770 | } | 1783 | } |
@@ -1795,16 +1808,30 @@ static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) | |||
1795 | return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); | 1808 | return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); |
1796 | } | 1809 | } |
1797 | 1810 | ||
1798 | static inline size_t xfrm_migrate_msgsize(int num_migrate) | 1811 | static int copy_to_user_kmaddress(struct xfrm_kmaddress *k, struct sk_buff *skb) |
1812 | { | ||
1813 | struct xfrm_user_kmaddress uk; | ||
1814 | |||
1815 | memset(&uk, 0, sizeof(uk)); | ||
1816 | uk.family = k->family; | ||
1817 | uk.reserved = k->reserved; | ||
1818 | memcpy(&uk.local, &k->local, sizeof(uk.local)); | ||
1819 | memcpy(&uk.remote, &k->local, sizeof(uk.remote)); | ||
1820 | |||
1821 | return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk); | ||
1822 | } | ||
1823 | |||
1824 | static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma) | ||
1799 | { | 1825 | { |
1800 | return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) | 1826 | return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) |
1801 | + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) | 1827 | + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0) |
1802 | + userpolicy_type_attrsize(); | 1828 | + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) |
1829 | + userpolicy_type_attrsize(); | ||
1803 | } | 1830 | } |
1804 | 1831 | ||
1805 | static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, | 1832 | static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, |
1806 | int num_migrate, struct xfrm_selector *sel, | 1833 | int num_migrate, struct xfrm_kmaddress *k, |
1807 | u8 dir, u8 type) | 1834 | struct xfrm_selector *sel, u8 dir, u8 type) |
1808 | { | 1835 | { |
1809 | struct xfrm_migrate *mp; | 1836 | struct xfrm_migrate *mp; |
1810 | struct xfrm_userpolicy_id *pol_id; | 1837 | struct xfrm_userpolicy_id *pol_id; |
@@ -1821,6 +1848,9 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, | |||
1821 | memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); | 1848 | memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); |
1822 | pol_id->dir = dir; | 1849 | pol_id->dir = dir; |
1823 | 1850 | ||
1851 | if (k != NULL && (copy_to_user_kmaddress(k, skb) < 0)) | ||
1852 | goto nlmsg_failure; | ||
1853 | |||
1824 | if (copy_to_user_policy_type(type, skb) < 0) | 1854 | if (copy_to_user_policy_type(type, skb) < 0) |
1825 | goto nlmsg_failure; | 1855 | goto nlmsg_failure; |
1826 | 1856 | ||
@@ -1836,23 +1866,25 @@ nlmsg_failure: | |||
1836 | } | 1866 | } |
1837 | 1867 | ||
1838 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1868 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1839 | struct xfrm_migrate *m, int num_migrate) | 1869 | struct xfrm_migrate *m, int num_migrate, |
1870 | struct xfrm_kmaddress *k) | ||
1840 | { | 1871 | { |
1841 | struct sk_buff *skb; | 1872 | struct sk_buff *skb; |
1842 | 1873 | ||
1843 | skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate), GFP_ATOMIC); | 1874 | skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); |
1844 | if (skb == NULL) | 1875 | if (skb == NULL) |
1845 | return -ENOMEM; | 1876 | return -ENOMEM; |
1846 | 1877 | ||
1847 | /* build migrate */ | 1878 | /* build migrate */ |
1848 | if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0) | 1879 | if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) |
1849 | BUG(); | 1880 | BUG(); |
1850 | 1881 | ||
1851 | return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); | 1882 | return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); |
1852 | } | 1883 | } |
1853 | #else | 1884 | #else |
1854 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1885 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1855 | struct xfrm_migrate *m, int num_migrate) | 1886 | struct xfrm_migrate *m, int num_migrate, |
1887 | struct xfrm_kmaddress *k) | ||
1856 | { | 1888 | { |
1857 | return -ENOPROTOOPT; | 1889 | return -ENOPROTOOPT; |
1858 | } | 1890 | } |
@@ -1901,6 +1933,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
1901 | [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, | 1933 | [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, |
1902 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, | 1934 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, |
1903 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 1935 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
1936 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | ||
1904 | }; | 1937 | }; |
1905 | 1938 | ||
1906 | static struct xfrm_link { | 1939 | static struct xfrm_link { |