aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc')
-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/*