aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svcsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r--net/sunrpc/svcsock.c72
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
724static void svc_udp_get_sender_address(struct svc_rqst *rqstp, 724static 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)
884static void 882static void
885svc_udp_init(struct svc_sock *svsk) 883svc_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/*