aboutsummaryrefslogtreecommitdiffstats
path: root/net/key/af_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/key/af_key.c')
-rw-r--r--net/key/af_key.c422
1 files changed, 422 insertions, 0 deletions
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
2349static 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
2364static 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
2409static 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
2451static 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
2530static 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
2348static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 2538static 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
2478static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) 2669static 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
3313static 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
3381static 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
3442static 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
3535static 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
3121static int pfkey_sendmsg(struct kiocb *kiocb, 3542static 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
3292static void __exit ipsec_pfkey_exit(void) 3714static void __exit ipsec_pfkey_exit(void)