aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/svcsock.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 9d7a819149ce..a89d04bd3855 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -36,6 +36,7 @@
36#include <net/sock.h> 36#include <net/sock.h>
37#include <net/checksum.h> 37#include <net/checksum.h>
38#include <net/ip.h> 38#include <net/ip.h>
39#include <net/ipv6.h>
39#include <net/tcp_states.h> 40#include <net/tcp_states.h>
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
41#include <asm/ioctls.h> 42#include <asm/ioctls.h>
@@ -446,6 +447,43 @@ svc_wake_up(struct svc_serv *serv)
446 } 447 }
447} 448}
448 449
450union svc_pktinfo_u {
451 struct in_pktinfo pkti;
452#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
453 struct in6_pktinfo pkti6;
454#endif
455};
456
457static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
458{
459 switch (rqstp->rq_sock->sk_sk->sk_family) {
460 case AF_INET: {
461 struct in_pktinfo *pki = CMSG_DATA(cmh);
462
463 cmh->cmsg_level = SOL_IP;
464 cmh->cmsg_type = IP_PKTINFO;
465 pki->ipi_ifindex = 0;
466 pki->ipi_spec_dst.s_addr = rqstp->rq_daddr.addr.s_addr;
467 cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
468 }
469 break;
470#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
471 case AF_INET6: {
472 struct in6_pktinfo *pki = CMSG_DATA(cmh);
473
474 cmh->cmsg_level = SOL_IPV6;
475 cmh->cmsg_type = IPV6_PKTINFO;
476 pki->ipi6_ifindex = 0;
477 ipv6_addr_copy(&pki->ipi6_addr,
478 &rqstp->rq_daddr.addr6);
479 cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
480 }
481 break;
482#endif
483 }
484 return;
485}
486
449/* 487/*
450 * Generic sendto routine 488 * Generic sendto routine
451 */ 489 */
@@ -455,9 +493,8 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
455 struct svc_sock *svsk = rqstp->rq_sock; 493 struct svc_sock *svsk = rqstp->rq_sock;
456 struct socket *sock = svsk->sk_sock; 494 struct socket *sock = svsk->sk_sock;
457 int slen; 495 int slen;
458 char buffer[CMSG_SPACE(sizeof(struct in_pktinfo))]; 496 char buffer[CMSG_SPACE(sizeof(union svc_pktinfo_u))];
459 struct cmsghdr *cmh = (struct cmsghdr *)buffer; 497 struct cmsghdr *cmh = (struct cmsghdr *)buffer;
460 struct in_pktinfo *pki = (struct in_pktinfo *)CMSG_DATA(cmh);
461 int len = 0; 498 int len = 0;
462 int result; 499 int result;
463 int size; 500 int size;
@@ -470,21 +507,15 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
470 slen = xdr->len; 507 slen = xdr->len;
471 508
472 if (rqstp->rq_prot == IPPROTO_UDP) { 509 if (rqstp->rq_prot == IPPROTO_UDP) {
473 /* set the source and destination */ 510 struct msghdr msg = {
474 struct msghdr msg; 511 .msg_name = &rqstp->rq_addr,
475 msg.msg_name = &rqstp->rq_addr; 512 .msg_namelen = rqstp->rq_addrlen,
476 msg.msg_namelen = rqstp->rq_addrlen; 513 .msg_control = cmh,
477 msg.msg_iov = NULL; 514 .msg_controllen = sizeof(buffer),
478 msg.msg_iovlen = 0; 515 .msg_flags = MSG_MORE,
479 msg.msg_flags = MSG_MORE; 516 };
480 517
481 msg.msg_control = cmh; 518 svc_set_cmsg_data(rqstp, cmh);
482 msg.msg_controllen = sizeof(buffer);
483 cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
484 cmh->cmsg_level = SOL_IP;
485 cmh->cmsg_type = IP_PKTINFO;
486 pki->ipi_ifindex = 0;
487 pki->ipi_spec_dst.s_addr = rqstp->rq_daddr.addr.s_addr;
488 519
489 if (sock_sendmsg(sock, &msg, 0) < 0) 520 if (sock_sendmsg(sock, &msg, 0) < 0)
490 goto out; 521 goto out;