diff options
-rw-r--r-- | include/linux/sunrpc/svc.h | 5 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 53 |
2 files changed, 48 insertions, 10 deletions
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 6d6892fa1d4..83b3c7b433a 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -270,6 +270,11 @@ static inline struct sockaddr_in *svc_addr_in(struct svc_rqst *rqst) return (struct sockaddr_in *) &rqst->rq_addr; } +static inline struct sockaddr_in6 *svc_addr_in6(struct svc_rqst *rqst) +{ + return (struct sockaddr_in6 *) &rqst->rq_addr; +} + static inline struct sockaddr *svc_addr(struct svc_rqst *rqst) { return (struct sockaddr *) &rqst->rq_addr; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 72831b8a58f..6f509b9cae2 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -721,13 +721,53 @@ svc_write_space(struct sock *sk) } } +static void svc_udp_get_sender_address(struct svc_rqst *rqstp, + struct sk_buff *skb) +{ + switch (rqstp->rq_sock->sk_sk->sk_family) { + case AF_INET: { + /* this seems to come from net/ipv4/udp.c:udp_recvmsg */ + struct sockaddr_in *sin = svc_addr_in(rqstp); + + sin->sin_family = AF_INET; + sin->sin_port = skb->h.uh->source; + sin->sin_addr.s_addr = skb->nh.iph->saddr; + rqstp->rq_addrlen = sizeof(struct sockaddr_in); + /* Remember which interface received this request */ + rqstp->rq_daddr.addr.s_addr = skb->nh.iph->daddr; + } + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: { + /* this is derived from net/ipv6/udp.c:udpv6_recvmesg */ + struct sockaddr_in6 *sin6 = svc_addr_in6(rqstp); + + sin6->sin6_family = AF_INET6; + sin6->sin6_port = skb->h.uh->source; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + if (ipv6_addr_type(&sin6->sin6_addr) & + IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; + ipv6_addr_copy(&sin6->sin6_addr, + &skb->nh.ipv6h->saddr); + rqstp->rq_addrlen = sizeof(struct sockaddr_in); + /* Remember which interface received this request */ + ipv6_addr_copy(&rqstp->rq_daddr.addr6, + &skb->nh.ipv6h->saddr); + } + break; +#endif + } + return; +} + /* * Receive a datagram from a UDP socket. */ static int svc_udp_recvfrom(struct svc_rqst *rqstp) { - struct sockaddr_in *sin = svc_addr_in(rqstp); struct svc_sock *svsk = rqstp->rq_sock; struct svc_serv *serv = svsk->sk_server; struct sk_buff *skb; @@ -785,16 +825,9 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) len = skb->len - sizeof(struct udphdr); rqstp->rq_arg.len = len; - rqstp->rq_prot = IPPROTO_UDP; - - /* Get sender address */ - sin->sin_family = AF_INET; - sin->sin_port = skb->h.uh->source; - sin->sin_addr.s_addr = skb->nh.iph->saddr; - rqstp->rq_addrlen = sizeof(struct sockaddr_in); + rqstp->rq_prot = IPPROTO_UDP; - /* Remember which interface received this request */ - rqstp->rq_daddr.addr.s_addr = skb->nh.iph->daddr; + svc_udp_get_sender_address(rqstp, skb); if (skb_is_nonlinear(skb)) { /* we have to copy */ |