提交 7702ce40 编写于 作者: C Chuck Lever 提交者: J. Bruce Fields

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: 7a37f578Signed-off-by: NChuck Lever <chuck.lever@oracle.com>
Cc: Neil Brown <neilb@suse.de>
Signed-off-by: NJ. Bruce Fields <bfields@citi.umich.edu>
上级 9208faf2
...@@ -431,6 +431,32 @@ static void svc_tcp_write_space(struct sock *sk) ...@@ -431,6 +431,32 @@ static void svc_tcp_write_space(struct sock *sk)
svc_write_space(sk); svc_write_space(sk);
} }
/*
* See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
*/
static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
struct cmsghdr *cmh)
{
struct in_pktinfo *pki = CMSG_DATA(cmh);
if (cmh->cmsg_type != IP_PKTINFO)
return 0;
rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
return 1;
}
/*
* See net/ipv6/datagram.c : datagram_recv_ctl
*/
static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
struct cmsghdr *cmh)
{
struct in6_pktinfo *pki = CMSG_DATA(cmh);
if (cmh->cmsg_type != IPV6_PKTINFO)
return 0;
ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
return 1;
}
/* /*
* Copy the UDP datagram's destination address to the rqstp structure. * Copy the UDP datagram's destination address to the rqstp structure.
* The 'destination' address in this case is the address to which the * The 'destination' address in this case is the address to which the
...@@ -438,23 +464,17 @@ static void svc_tcp_write_space(struct sock *sk) ...@@ -438,23 +464,17 @@ static void svc_tcp_write_space(struct sock *sk)
* hosts, this can change from msg to msg. Note that only the IP * hosts, this can change from msg to msg. Note that only the IP
* address changes, the port number should remain the same. * address changes, the port number should remain the same.
*/ */
static void svc_udp_get_dest_address(struct svc_rqst *rqstp, static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
struct cmsghdr *cmh) struct cmsghdr *cmh)
{ {
struct svc_sock *svsk = switch (cmh->cmsg_level) {
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); case SOL_IP:
switch (svsk->sk_sk->sk_family) { return svc_udp_get_dest_address4(rqstp, cmh);
case AF_INET: { case SOL_IPV6:
struct in_pktinfo *pki = CMSG_DATA(cmh); return svc_udp_get_dest_address6(rqstp, cmh);
rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
break;
}
case AF_INET6: {
struct in6_pktinfo *pki = CMSG_DATA(cmh);
ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
break;
}
} }
return 0;
} }
/* /*
...@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
rqstp->rq_prot = IPPROTO_UDP; rqstp->rq_prot = IPPROTO_UDP;
if (cmh->cmsg_level != IPPROTO_IP || if (!svc_udp_get_dest_address(rqstp, cmh)) {
cmh->cmsg_type != IP_PKTINFO) {
if (net_ratelimit()) if (net_ratelimit())
printk("rpcsvc: received unknown control message:" printk(KERN_WARNING
"%d/%d\n", "svc: received unknown control message %d/%d; "
cmh->cmsg_level, cmh->cmsg_type); "dropping RPC reply datagram\n",
cmh->cmsg_level, cmh->cmsg_type);
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram(svsk->sk_sk, skb);
return 0; return 0;
} }
svc_udp_get_dest_address(rqstp, cmh);
if (skb_is_nonlinear(skb)) { if (skb_is_nonlinear(skb)) {
/* we have to copy */ /* we have to copy */
...@@ -651,8 +670,7 @@ static struct svc_xprt_class svc_udp_class = { ...@@ -651,8 +670,7 @@ static struct svc_xprt_class svc_udp_class = {
static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
{ {
int one = 1; int err, level, optname, one = 1;
mm_segment_t oldfs;
svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 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,12 +689,22 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
oldfs = get_fs();
set_fs(KERNEL_DS);
/* make sure we get destination address info */ /* make sure we get destination address info */
svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO, switch (svsk->sk_sk->sk_family) {
(char __user *)&one, sizeof(one)); case AF_INET:
set_fs(oldfs); level = SOL_IP;
optname = IP_PKTINFO;
break;
case AF_INET6:
level = SOL_IPV6;
optname = IPV6_RECVPKTINFO;
break;
default:
BUG();
}
err = kernel_setsockopt(svsk->sk_sock, level, optname,
(char *)&one, sizeof(one));
dprintk("svc: kernel_setsockopt returned %d\n", err);
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册