aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svcsock.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2009-07-13 10:54:26 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-07-14 17:39:46 -0400
commit7702ce40bc84a02e88aa20f95333df8cff5f9d37 (patch)
tree72e9e0fb07175486cf2b6996cf8d94b1d0d7c466 /net/sunrpc/svcsock.c
parent9208faf297dddfa97a86d7224b6bf94f2e346dd9 (diff)
SUNRPC: handle IPv6 PKTINFO when extracting destination address
PKTINFO is needed to scrape the caller's IP address off the socket so RPC datagram replies are routed correctly. Fill in missing pieces in the kernel RPC server's UDP receive path to request IPv6 PKTINFO and correctly parse the IPv6 cmsg header. Without this patch, kernel RPC services drop all incoming requests on UDP on IPv6. Related commit: 7a37f5787e76bf1765c1add3a9a7163f841a28bb Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: Neil Brown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r--net/sunrpc/svcsock.c84
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 */
437static 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 */
450static 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 */
441static void svc_udp_get_dest_address(struct svc_rqst *rqstp, 467static 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
652static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) 671static 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/*