summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2015-09-11 17:00:34 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2015-09-11 17:00:34 +0000
commit04e897ad9798e6c5ac51301efad5f47fabc50b78 (patch)
tree2f59f3a68bc306cca915687c943adc5c360798c8 /usr/src
parentf13fe5b0067651c187b89429b442473f0dfe1b8d (diff)
downloadillumos-joyent-04e897ad9798e6c5ac51301efad5f47fabc50b78.tar.gz
OS-4647 lx fails to mount nfs share - Transport endpoint is already connected
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/truss/print.c1
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/socket.c4
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_socket.c19
-rw-r--r--usr/src/uts/common/inet/udp/udp.c24
-rw-r--r--usr/src/uts/common/inet/udp/udp_opt_data.c4
-rw-r--r--usr/src/uts/common/inet/udp_impl.h3
-rw-r--r--usr/src/uts/common/netinet/udp.h2
7 files changed, 53 insertions, 4 deletions
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index 66a9d7387e..2b59676e30 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -2001,6 +2001,7 @@ udp_optname(private_t *pri, long val)
case UDP_RCVHDR: return ("UDP_RCVHDR");
case UDP_NAT_T_ENDPOINT: return ("UDP_NAT_T_ENDPOINT");
case UDP_SRCPORT_HASH: return ("UDP_SRCPORT_HASH");
+ case UDP_SND_TO_CONNECTED: return ("UDP_SND_TO_CONNECTED");
default: (void) snprintf(pri->code_buf,
sizeof (pri->code_buf), "0x%lx",
diff --git a/usr/src/lib/brand/lx/lx_brand/common/socket.c b/usr/src/lib/brand/lx/lx_brand/common/socket.c
index 264d7ad345..d5f7161524 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/socket.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/socket.c
@@ -1090,6 +1090,10 @@ lx_setsockopt(int sockfd, int level, int optname, void *optval, int optlen)
strcmp(lx_cmd_name, "traceroute") == 0)
return (0);
+ if (optname == LX_IP_RECVERR &&
+ strcmp(lx_cmd_name, "mount.nfs") == 0)
+ return (0);
+
if (optname == LX_IP_MTU_DISCOVER) {
/*
* Native programs such as traceroute use IP_DONTFRAG
diff --git a/usr/src/uts/common/brand/lx/syscall/lx_socket.c b/usr/src/uts/common/brand/lx/syscall/lx_socket.c
index 1b4b24aa86..023c61b082 100644
--- a/usr/src/uts/common/brand/lx/syscall/lx_socket.c
+++ b/usr/src/uts/common/brand/lx/syscall/lx_socket.c
@@ -48,6 +48,8 @@
#include <netpacket/packet.h>
#include <sockcommon.h>
#include <socktpi_impl.h>
+#include <netinet/udp.h>
+#include <sys/sdt.h>
#include <sys/lx_brand.h>
#include <sys/lx_socket.h>
@@ -1177,7 +1179,7 @@ lx_connect(long sock, uintptr_t name, socklen_t namelen)
}
/*
- * Ensure the name is size appropriately before we alloc memory and
+ * Ensure the name is sized appropriately before we alloc memory and
* copy it in from userspace. We need at least the address family to
* make later sizing decisions.
*/
@@ -1213,6 +1215,21 @@ lx_connect(long sock, uintptr_t name, socklen_t namelen)
mutex_exit(&sad->lxsad_lock);
}
+ /*
+ * When connecting to a UDP socket, configure it so that future
+ * sendto/sendmsg operations are allowed to specify a destination
+ * address. See the Posix spec. for sendto(2). Linux allows this while
+ * illumos would return EISCONN if the option is not set.
+ */
+ if (error == 0 && so->so_protocol == IPPROTO_UDP &&
+ (so->so_family == AF_INET || so->so_family == AF_INET6)) {
+ int val = 1;
+
+ DTRACE_PROBE(lx__connect__udp);
+ (void) socket_setsockopt(so, IPPROTO_UDP, UDP_SND_TO_CONNECTED,
+ &val, sizeof (val), CRED());
+ }
+
releasef(sock);
if (addr != NULL) {
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index eec3beddd2..7f468a190e 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -1673,6 +1673,11 @@ udp_opt_get(conn_t *connp, t_scalar_t level, t_scalar_t name,
*i1 = udp->udp_vxlanhash;
mutex_exit(&connp->conn_lock);
return (sizeof (int));
+ case UDP_SND_TO_CONNECTED:
+ mutex_enter(&connp->conn_lock);
+ *i1 = udp->udp_snd_to_conn ? 1 : 0;
+ mutex_exit(&connp->conn_lock);
+ return (sizeof (int));
}
}
mutex_enter(&connp->conn_lock);
@@ -1828,6 +1833,11 @@ udp_do_opt_set(conn_opt_arg_t *coa, int level, int name,
}
/* Fully handled this option. */
return (0);
+ case UDP_SND_TO_CONNECTED:
+ mutex_enter(&connp->conn_lock);
+ udp->udp_snd_to_conn = onoff;
+ mutex_exit(&connp->conn_lock);
+ return (0);
}
break;
}
@@ -6051,6 +6061,7 @@ udp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
ushort_t ipversion;
pid_t pid = curproc->p_pid;
ip_xmit_attr_t *ixa;
+ boolean_t snd_to_conn;
ASSERT(DB_TYPE(mp) == M_DATA);
@@ -6088,10 +6099,21 @@ udp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
else
return (error);
}
- if (udp->udp_state == TS_DATA_XFER) {
+
+ /*
+ * Check if we're allowed to send to a connection on which we've
+ * already called 'connect'. The posix spec. allows both behaviors but
+ * historically we've returned an error if already connected. The
+ * client can allow this via a sockopt.
+ */
+ mutex_enter(&connp->conn_lock);
+ snd_to_conn = (udp->udp_snd_to_conn != 0);
+ mutex_exit(&connp->conn_lock);
+ if (udp->udp_state == TS_DATA_XFER && !snd_to_conn) {
UDPS_BUMP_MIB(us, udpOutErrors);
return (EISCONN);
}
+
error = proto_verify_ip_addr(connp->conn_family,
(struct sockaddr *)msg->msg_name, msg->msg_namelen);
if (error != 0) {
diff --git a/usr/src/uts/common/inet/udp/udp_opt_data.c b/usr/src/uts/common/inet/udp/udp_opt_data.c
index fec3dec4c9..847e2cdde6 100644
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c
@@ -293,7 +293,9 @@ opdes_t udp_opt_arr[] = {
},
{ UDP_NAT_T_ENDPOINT, IPPROTO_UDP, OA_RW, OA_RW, OP_PRIVPORT, 0, sizeof (int),
0 },
-{ UDP_SRCPORT_HASH, IPPROTO_UDP, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int), 0 }
+{ UDP_SRCPORT_HASH, IPPROTO_UDP, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int), 0 },
+{ UDP_SND_TO_CONNECTED, IPPROTO_UDP, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
+ 0 }
};
/*
diff --git a/usr/src/uts/common/inet/udp_impl.h b/usr/src/uts/common/inet/udp_impl.h
index 3b07abc309..ebba10c0f7 100644
--- a/usr/src/uts/common/inet/udp_impl.h
+++ b/usr/src/uts/common/inet/udp_impl.h
@@ -182,8 +182,9 @@ typedef struct udp_s {
udp_vxlanhash: 1, /* UDP_SRCPORT_HASH option */
/* Because there's only VXLAN, cheat */
/* and only use a single bit */
+ udp_snd_to_conn: 1, /* UDP_SND_TO_CONNECTED option */
- udp_pad_to_bit_31 : 28;
+ udp_pad_to_bit_31 : 27;
/* Following 2 fields protected by the uf_lock */
struct udp_s *udp_bind_hash; /* Bind hash chain */
diff --git a/usr/src/uts/common/netinet/udp.h b/usr/src/uts/common/netinet/udp.h
index fb9f8a0976..74cff75d43 100644
--- a/usr/src/uts/common/netinet/udp.h
+++ b/usr/src/uts/common/netinet/udp.h
@@ -1,6 +1,7 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
*/
/*
@@ -34,6 +35,7 @@ struct udphdr {
#define UDP_RCVHDR 0x0102 /* for internal use only */
#define UDP_NAT_T_ENDPOINT 0x0103 /* for internal use only */
#define UDP_SRCPORT_HASH 0x0104 /* for internal use only */
+#define UDP_SND_TO_CONNECTED 0x0105 /* for internal use only */
/*
* Hash definitions for UDP_SRCPORT_HASH that effectively tell UDP how to go