diff options
| -rw-r--r-- | net/sunrpc/svcsock.c | 72 |
1 files changed, 40 insertions, 32 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 63ae94771b8e..32b94cf19f89 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -721,45 +721,23 @@ svc_write_space(struct sock *sk) | |||
| 721 | } | 721 | } |
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | static void svc_udp_get_sender_address(struct svc_rqst *rqstp, | 724 | static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp, |
| 725 | struct sk_buff *skb) | 725 | struct cmsghdr *cmh) |
| 726 | { | 726 | { |
| 727 | switch (rqstp->rq_sock->sk_sk->sk_family) { | 727 | switch (rqstp->rq_sock->sk_sk->sk_family) { |
| 728 | case AF_INET: { | 728 | case AF_INET: { |
| 729 | /* this seems to come from net/ipv4/udp.c:udp_recvmsg */ | 729 | struct in_pktinfo *pki = CMSG_DATA(cmh); |
| 730 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 730 | rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; |
| 731 | |||
| 732 | sin->sin_family = AF_INET; | ||
| 733 | sin->sin_port = skb->h.uh->source; | ||
| 734 | sin->sin_addr.s_addr = skb->nh.iph->saddr; | ||
| 735 | rqstp->rq_addrlen = sizeof(struct sockaddr_in); | ||
| 736 | /* Remember which interface received this request */ | ||
| 737 | rqstp->rq_daddr.addr.s_addr = skb->nh.iph->daddr; | ||
| 738 | } | ||
| 739 | break; | 731 | break; |
| 732 | } | ||
| 740 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 733 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 741 | case AF_INET6: { | 734 | case AF_INET6: { |
| 742 | /* this is derived from net/ipv6/udp.c:udpv6_recvmesg */ | 735 | struct in6_pktinfo *pki = CMSG_DATA(cmh); |
| 743 | struct sockaddr_in6 *sin6 = svc_addr_in6(rqstp); | 736 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); |
| 744 | |||
| 745 | sin6->sin6_family = AF_INET6; | ||
| 746 | sin6->sin6_port = skb->h.uh->source; | ||
| 747 | sin6->sin6_flowinfo = 0; | ||
| 748 | sin6->sin6_scope_id = 0; | ||
| 749 | if (ipv6_addr_type(&sin6->sin6_addr) & | ||
| 750 | IPV6_ADDR_LINKLOCAL) | ||
| 751 | sin6->sin6_scope_id = IP6CB(skb)->iif; | ||
| 752 | ipv6_addr_copy(&sin6->sin6_addr, | ||
| 753 | &skb->nh.ipv6h->saddr); | ||
| 754 | rqstp->rq_addrlen = sizeof(struct sockaddr_in); | ||
| 755 | /* Remember which interface received this request */ | ||
| 756 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, | ||
| 757 | &skb->nh.ipv6h->saddr); | ||
| 758 | } | ||
| 759 | break; | 737 | break; |
| 738 | } | ||
| 760 | #endif | 739 | #endif |
| 761 | } | 740 | } |
| 762 | return; | ||
| 763 | } | 741 | } |
| 764 | 742 | ||
| 765 | /* | 743 | /* |
| @@ -771,7 +749,15 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 771 | struct svc_sock *svsk = rqstp->rq_sock; | 749 | struct svc_sock *svsk = rqstp->rq_sock; |
| 772 | struct svc_serv *serv = svsk->sk_server; | 750 | struct svc_serv *serv = svsk->sk_server; |
| 773 | struct sk_buff *skb; | 751 | struct sk_buff *skb; |
| 752 | char buffer[CMSG_SPACE(sizeof(union svc_pktinfo_u))]; | ||
| 753 | struct cmsghdr *cmh = (struct cmsghdr *)buffer; | ||
| 774 | int err, len; | 754 | int err, len; |
| 755 | struct msghdr msg = { | ||
| 756 | .msg_name = svc_addr(rqstp), | ||
| 757 | .msg_control = cmh, | ||
| 758 | .msg_controllen = sizeof(buffer), | ||
| 759 | .msg_flags = MSG_DONTWAIT, | ||
| 760 | }; | ||
| 775 | 761 | ||
| 776 | if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags)) | 762 | if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags)) |
| 777 | /* udp sockets need large rcvbuf as all pending | 763 | /* udp sockets need large rcvbuf as all pending |
| @@ -797,7 +783,9 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 797 | } | 783 | } |
| 798 | 784 | ||
| 799 | clear_bit(SK_DATA, &svsk->sk_flags); | 785 | clear_bit(SK_DATA, &svsk->sk_flags); |
| 800 | while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { | 786 | while ((err == kernel_recvmsg(svsk->sk_sock, &msg, NULL, |
| 787 | 0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 || | ||
| 788 | (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { | ||
| 801 | if (err == -EAGAIN) { | 789 | if (err == -EAGAIN) { |
| 802 | svc_sock_received(svsk); | 790 | svc_sock_received(svsk); |
| 803 | return err; | 791 | return err; |
| @@ -805,6 +793,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 805 | /* possibly an icmp error */ | 793 | /* possibly an icmp error */ |
| 806 | dprintk("svc: recvfrom returned error %d\n", -err); | 794 | dprintk("svc: recvfrom returned error %d\n", -err); |
| 807 | } | 795 | } |
| 796 | rqstp->rq_addrlen = sizeof(rqstp->rq_addr); | ||
| 808 | if (skb->tstamp.off_sec == 0) { | 797 | if (skb->tstamp.off_sec == 0) { |
| 809 | struct timeval tv; | 798 | struct timeval tv; |
| 810 | 799 | ||
| @@ -827,7 +816,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 827 | 816 | ||
| 828 | rqstp->rq_prot = IPPROTO_UDP; | 817 | rqstp->rq_prot = IPPROTO_UDP; |
| 829 | 818 | ||
| 830 | svc_udp_get_sender_address(rqstp, skb); | 819 | if (cmh->cmsg_level != IPPROTO_IP || |
| 820 | cmh->cmsg_type != IP_PKTINFO) { | ||
| 821 | if (net_ratelimit()) | ||
| 822 | printk("rpcsvc: received unknown control message:" | ||
| 823 | "%d/%d\n", | ||
| 824 | cmh->cmsg_level, cmh->cmsg_type); | ||
| 825 | skb_free_datagram(svsk->sk_sk, skb); | ||
| 826 | return 0; | ||
| 827 | } | ||
| 828 | svc_udp_get_dest_address(rqstp, cmh); | ||
| 831 | 829 | ||
| 832 | if (skb_is_nonlinear(skb)) { | 830 | if (skb_is_nonlinear(skb)) { |
| 833 | /* we have to copy */ | 831 | /* we have to copy */ |
| @@ -884,6 +882,9 @@ svc_udp_sendto(struct svc_rqst *rqstp) | |||
| 884 | static void | 882 | static void |
| 885 | svc_udp_init(struct svc_sock *svsk) | 883 | svc_udp_init(struct svc_sock *svsk) |
| 886 | { | 884 | { |
| 885 | int one = 1; | ||
| 886 | mm_segment_t oldfs; | ||
| 887 | |||
| 887 | svsk->sk_sk->sk_data_ready = svc_udp_data_ready; | 888 | svsk->sk_sk->sk_data_ready = svc_udp_data_ready; |
| 888 | svsk->sk_sk->sk_write_space = svc_write_space; | 889 | svsk->sk_sk->sk_write_space = svc_write_space; |
| 889 | svsk->sk_recvfrom = svc_udp_recvfrom; | 890 | svsk->sk_recvfrom = svc_udp_recvfrom; |
| @@ -899,6 +900,13 @@ svc_udp_init(struct svc_sock *svsk) | |||
| 899 | 900 | ||
| 900 | set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */ | 901 | set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */ |
| 901 | set_bit(SK_CHNGBUF, &svsk->sk_flags); | 902 | set_bit(SK_CHNGBUF, &svsk->sk_flags); |
| 903 | |||
| 904 | oldfs = get_fs(); | ||
| 905 | set_fs(KERNEL_DS); | ||
| 906 | /* make sure we get destination address info */ | ||
| 907 | svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO, | ||
| 908 | (char __user *)&one, sizeof(one)); | ||
| 909 | set_fs(oldfs); | ||
| 902 | } | 910 | } |
| 903 | 911 | ||
| 904 | /* | 912 | /* |
