aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaud Ebalard <arno@natisbad.org>2008-10-05 16:33:42 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-05 16:33:42 -0400
commit13c1d18931ebb5cf407cb348ef2cd6284d68902d (patch)
tree6d590f85e48b4cce8f67e42c65b88fce8fcc49c6
parent95430c0b140c31cb9e39f876afe1c0e9947d1aaf (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.h13
-rw-r--r--include/linux/xfrm.h10
-rw-r--r--include/net/xfrm.h15
-rw-r--r--net/key/af_key.c86
-rw-r--r--net/xfrm/xfrm_policy.c5
-rw-r--r--net/xfrm/xfrm_state.c5
-rw-r--r--net/xfrm/xfrm_user.c57
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 */
231struct 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 */
421struct xfrm_user_kmaddress {
422 xfrm_address_t local;
423 xfrm_address_t remote;
424 __u32 reserved;
425 __u16 family;
426};
427
418struct xfrm_user_migrate { 428struct 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
495struct xfrm_kmaddress {
496 xfrm_address_t local;
497 xfrm_address_t remote;
498 u32 reserved;
499 u16 family;
500};
501
495struct xfrm_migrate { 502struct 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
537extern int xfrm_register_km(struct xfrm_mgr *km); 544extern 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
1434extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1441extern 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);
1436extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m); 1444extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m);
1437extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, 1445extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1438 struct xfrm_migrate *m); 1446 struct xfrm_migrate *m);
1439extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1447extern 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
1443extern wait_queue_head_t km_waitq; 1452extern 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
2387static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, 2388static 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
3337static 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
3322static int set_ipsecrequest(struct sk_buff *skb, 3362static 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
3353static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 3393static 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
3451static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 3502static 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
2681int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 2681int 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
1816int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1816int 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
1712static int copy_from_user_migrate(struct xfrm_migrate *ma, 1712static 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
1798static inline size_t xfrm_migrate_msgsize(int num_migrate) 1811static 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
1824static 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
1805static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, 1832static 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
1838static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1868static 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
1854static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1885static 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
1906static struct xfrm_link { 1939static struct xfrm_link {