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 /net/key/af_key.c | |
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>
Diffstat (limited to 'net/key/af_key.c')
-rw-r--r-- | net/key/af_key.c | 86 |
1 files changed, 69 insertions, 17 deletions
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 | } |