aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2007-03-06 04:42:21 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-06 12:30:26 -0500
commit7a37f5787e76bf1765c1add3a9a7163f841a28bb (patch)
treef67e69f082bf6a6083e3b0cff089d1bba1d1da0c /net
parent0e8cd28a084691587549630dce728661401d343b (diff)
[PATCH] knfsd: use recv_msg to get peer address for NFSD instead of code-copying
The sunrpc server code needs to know the source and destination address for UDP packets so it can reply properly. It currently copies code out of the network stack to pick the pieces out of the skb. This is ugly and causes compile problems with the IPv6 stuff. So, rip that out and use recv_msg instead. This is a much cleaner interface, but has a slight cost in that the checksum is now checked before the copy, so we don't benefit from doing both at the same time. This can probably be fixed. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net')
-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/*