diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/svcsock.c | 84 |
1 files changed, 56 insertions, 28 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 23128ee191ae..99a826dcc32e 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -432,29 +432,49 @@ static void svc_tcp_write_space(struct sock *sk) | |||
432 | } | 432 | } |
433 | 433 | ||
434 | /* | 434 | /* |
435 | * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo | ||
436 | */ | ||
437 | static int svc_udp_get_dest_address4(struct svc_rqst *rqstp, | ||
438 | struct cmsghdr *cmh) | ||
439 | { | ||
440 | struct in_pktinfo *pki = CMSG_DATA(cmh); | ||
441 | if (cmh->cmsg_type != IP_PKTINFO) | ||
442 | return 0; | ||
443 | rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; | ||
444 | return 1; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * See net/ipv6/datagram.c : datagram_recv_ctl | ||
449 | */ | ||
450 | static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, | ||
451 | struct cmsghdr *cmh) | ||
452 | { | ||
453 | struct in6_pktinfo *pki = CMSG_DATA(cmh); | ||
454 | if (cmh->cmsg_type != IPV6_PKTINFO) | ||
455 | return 0; | ||
456 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); | ||
457 | return 1; | ||
458 | } | ||
459 | |||
460 | /* | ||
435 | * Copy the UDP datagram's destination address to the rqstp structure. | 461 | * Copy the UDP datagram's destination address to the rqstp structure. |
436 | * The 'destination' address in this case is the address to which the | 462 | * The 'destination' address in this case is the address to which the |
437 | * peer sent the datagram, i.e. our local address. For multihomed | 463 | * peer sent the datagram, i.e. our local address. For multihomed |
438 | * hosts, this can change from msg to msg. Note that only the IP | 464 | * hosts, this can change from msg to msg. Note that only the IP |
439 | * address changes, the port number should remain the same. | 465 | * address changes, the port number should remain the same. |
440 | */ | 466 | */ |
441 | static void svc_udp_get_dest_address(struct svc_rqst *rqstp, | 467 | static int svc_udp_get_dest_address(struct svc_rqst *rqstp, |
442 | struct cmsghdr *cmh) | 468 | struct cmsghdr *cmh) |
443 | { | 469 | { |
444 | struct svc_sock *svsk = | 470 | switch (cmh->cmsg_level) { |
445 | container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); | 471 | case SOL_IP: |
446 | switch (svsk->sk_sk->sk_family) { | 472 | return svc_udp_get_dest_address4(rqstp, cmh); |
447 | case AF_INET: { | 473 | case SOL_IPV6: |
448 | struct in_pktinfo *pki = CMSG_DATA(cmh); | 474 | return svc_udp_get_dest_address6(rqstp, cmh); |
449 | rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; | ||
450 | break; | ||
451 | } | ||
452 | case AF_INET6: { | ||
453 | struct in6_pktinfo *pki = CMSG_DATA(cmh); | ||
454 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); | ||
455 | break; | ||
456 | } | ||
457 | } | 475 | } |
476 | |||
477 | return 0; | ||
458 | } | 478 | } |
459 | 479 | ||
460 | /* | 480 | /* |
@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
531 | 551 | ||
532 | rqstp->rq_prot = IPPROTO_UDP; | 552 | rqstp->rq_prot = IPPROTO_UDP; |
533 | 553 | ||
534 | if (cmh->cmsg_level != IPPROTO_IP || | 554 | if (!svc_udp_get_dest_address(rqstp, cmh)) { |
535 | cmh->cmsg_type != IP_PKTINFO) { | ||
536 | if (net_ratelimit()) | 555 | if (net_ratelimit()) |
537 | printk("rpcsvc: received unknown control message:" | 556 | printk(KERN_WARNING |
538 | "%d/%d\n", | 557 | "svc: received unknown control message %d/%d; " |
539 | cmh->cmsg_level, cmh->cmsg_type); | 558 | "dropping RPC reply datagram\n", |
559 | cmh->cmsg_level, cmh->cmsg_type); | ||
540 | skb_free_datagram(svsk->sk_sk, skb); | 560 | skb_free_datagram(svsk->sk_sk, skb); |
541 | return 0; | 561 | return 0; |
542 | } | 562 | } |
543 | svc_udp_get_dest_address(rqstp, cmh); | ||
544 | 563 | ||
545 | if (skb_is_nonlinear(skb)) { | 564 | if (skb_is_nonlinear(skb)) { |
546 | /* we have to copy */ | 565 | /* we have to copy */ |
@@ -651,8 +670,7 @@ static struct svc_xprt_class svc_udp_class = { | |||
651 | 670 | ||
652 | static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) | 671 | static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) |
653 | { | 672 | { |
654 | int one = 1; | 673 | int err, level, optname, one = 1; |
655 | mm_segment_t oldfs; | ||
656 | 674 | ||
657 | svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); | 675 | svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); |
658 | clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); | 676 | clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); |
@@ -671,12 +689,22 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
671 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | 689 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); |
672 | set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); | 690 | set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); |
673 | 691 | ||
674 | oldfs = get_fs(); | ||
675 | set_fs(KERNEL_DS); | ||
676 | /* make sure we get destination address info */ | 692 | /* make sure we get destination address info */ |
677 | svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO, | 693 | switch (svsk->sk_sk->sk_family) { |
678 | (char __user *)&one, sizeof(one)); | 694 | case AF_INET: |
679 | set_fs(oldfs); | 695 | level = SOL_IP; |
696 | optname = IP_PKTINFO; | ||
697 | break; | ||
698 | case AF_INET6: | ||
699 | level = SOL_IPV6; | ||
700 | optname = IPV6_RECVPKTINFO; | ||
701 | break; | ||
702 | default: | ||
703 | BUG(); | ||
704 | } | ||
705 | err = kernel_setsockopt(svsk->sk_sock, level, optname, | ||
706 | (char *)&one, sizeof(one)); | ||
707 | dprintk("svc: kernel_setsockopt returned %d\n", err); | ||
680 | } | 708 | } |
681 | 709 | ||
682 | /* | 710 | /* |