|
@@ -431,6 +431,32 @@ static void svc_tcp_write_space(struct sock *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.
|
|
|
* 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)
|
|
|
* hosts, this can change from msg to msg. Note that only the IP
|
|
|
* address changes, the port number should remain the same.
|
|
|
*/
|
|
|
-static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
|
|
|
- struct cmsghdr *cmh)
|
|
|
+static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
|
|
|
+ struct cmsghdr *cmh)
|
|
|
{
|
|
|
- struct svc_sock *svsk =
|
|
|
- container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
|
|
|
- switch (svsk->sk_sk->sk_family) {
|
|
|
- case AF_INET: {
|
|
|
- struct in_pktinfo *pki = CMSG_DATA(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;
|
|
|
- }
|
|
|
+ switch (cmh->cmsg_level) {
|
|
|
+ case SOL_IP:
|
|
|
+ return svc_udp_get_dest_address4(rqstp, cmh);
|
|
|
+ case SOL_IPV6:
|
|
|
+ return svc_udp_get_dest_address6(rqstp, cmh);
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
|
|
|
|
|
rqstp->rq_prot = IPPROTO_UDP;
|
|
|
|
|
|
- if (cmh->cmsg_level != IPPROTO_IP ||
|
|
|
- cmh->cmsg_type != IP_PKTINFO) {
|
|
|
+ if (!svc_udp_get_dest_address(rqstp, cmh)) {
|
|
|
if (net_ratelimit())
|
|
|
- printk("rpcsvc: received unknown control message:"
|
|
|
- "%d/%d\n",
|
|
|
- cmh->cmsg_level, cmh->cmsg_type);
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "svc: received unknown control message %d/%d; "
|
|
|
+ "dropping RPC reply datagram\n",
|
|
|
+ cmh->cmsg_level, cmh->cmsg_type);
|
|
|
skb_free_datagram(svsk->sk_sk, skb);
|
|
|
return 0;
|
|
|
}
|
|
|
- svc_udp_get_dest_address(rqstp, cmh);
|
|
|
|
|
|
if (skb_is_nonlinear(skb)) {
|
|
|
/* we have to copy */
|
|
@@ -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)
|
|
|
{
|
|
|
- int one = 1;
|
|
|
- mm_segment_t oldfs;
|
|
|
+ int err, level, optname, one = 1;
|
|
|
|
|
|
svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
|
|
|
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)
|
|
|
set_bit(XPT_DATA, &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 */
|
|
|
- svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO,
|
|
|
- (char __user *)&one, sizeof(one));
|
|
|
- set_fs(oldfs);
|
|
|
+ switch (svsk->sk_sk->sk_family) {
|
|
|
+ case AF_INET:
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
/*
|