diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svcsock.c | 65 |
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 | ||
450 | union 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 | |||
457 | static 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; |