summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2014-12-31 19:26:49 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2014-12-31 19:38:09 +0000
commit0255a6f9dc26c7acbff2a3013e51cfc1d880723a (patch)
tree2b6b97f7d33d78e5f1c348e7e3abcbec2f3b712d
parent75861d9dbca411cd7ab5c8f1aecdaa98dd4a8e46 (diff)
downloadillumos-joyent-0255a6f9dc26c7acbff2a3013e51cfc1d880723a.tar.gz
OS-3639 lxbrand ping6 is broken
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/socket.c73
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h8
2 files changed, 79 insertions, 2 deletions
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 ec8a935dd7..c24b184061 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/socket.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/socket.c
@@ -45,6 +45,7 @@
#include <sys/un.h>
#include <netinet/tcp.h>
#include <netinet/igmp.h>
+#include <netinet/icmp6.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/lx_debug.h>
@@ -326,6 +327,17 @@ static const int ltos_ipv6_sockopts[LX_IPV6_TCLASS + 1] = {
};
/*
+ * Linux Illumos
+ * ----- -------
+ *
+ * ICMP6_FILTER 1 ICMP6_FILTER 1
+ */
+
+static const int ltos_icmpv6_sockopts[LX_ICMP6_FILTER + 1] = {
+ OPTNOTSUP, ICMP6_FILTER
+};
+
+/*
*
* TCP socket option mapping:
*
@@ -454,8 +466,9 @@ static const int ltos_socket_sockopts[LX_SO_BPF_EXTENSIONS + 1] = {
* See the Linux raw.7 man page for description of the socket options.
* In Linux ICMP_FILTER is defined as 1 in include/uapi/linux/icmp.h
*/
-static const int ltos_raw_sockopts[LX_ICMP_FILTER + 1] = {
- OPTNOTSUP, OPTNOTSUP
+static const int ltos_raw_sockopts[LX_IPV6_CHECKSUM + 1] = {
+ OPTNOTSUP, OPTNOTSUP, OPTNOTSUP, OPTNOTSUP,
+ OPTNOTSUP, OPTNOTSUP, OPTNOTSUP, OPTNOTSUP
};
#define PROTO_SOCKOPTS(opts) \
@@ -466,6 +479,8 @@ static const int ltos_raw_sockopts[LX_ICMP_FILTER + 1] = {
*/
static lx_proto_opts_t ip_sockopts_tbl = PROTO_SOCKOPTS(ltos_ip_sockopts);
static lx_proto_opts_t ipv6_sockopts_tbl = PROTO_SOCKOPTS(ltos_ipv6_sockopts);
+static lx_proto_opts_t icmpv6_sockopts_tbl =
+ PROTO_SOCKOPTS(ltos_icmpv6_sockopts);
static lx_proto_opts_t socket_sockopts_tbl =
PROTO_SOCKOPTS(ltos_socket_sockopts);
static lx_proto_opts_t igmp_sockopts_tbl = PROTO_SOCKOPTS(ltos_igmp_sockopts);
@@ -1663,6 +1678,7 @@ get_proto_opt_tbl(int level)
case LX_IPPROTO_IGMP: return (&igmp_sockopts_tbl);
case LX_IPPROTO_TCP: return (&tcp_sockopts_tbl);
case LX_IPPROTO_IPV6: return (&ipv6_sockopts_tbl);
+ case LX_IPPROTO_ICMPV6: return (&icmpv6_sockopts_tbl);
case LX_IPPROTO_RAW: return (&raw_sockopts_tbl);
default:
lx_unsupported("Unsupported sockopt level %d", level);
@@ -1756,6 +1772,24 @@ lx_setsockopt(int sockfd, int level, int optname, void *optval, int optlen)
*/
if (optname == LX_IPV6_MTU)
return (0);
+ } else if (level == LX_IPPROTO_ICMPV6) {
+ if (optname == LX_ICMP6_FILTER && optval != NULL) {
+ int i;
+ icmp6_filter_t *filter;
+ /*
+ * Surprise! Linux's ICMP6_FILTER is inverted, when
+ * compared to illumos
+ */
+ if (optlen != sizeof (icmp6_filter_t))
+ return (-EINVAL);
+ if ((filter = SAFE_ALLOCA(optlen)) == NULL)
+ return (-ENOMEM);
+ if (uucopy(optval, filter, optlen) != 0)
+ return (-EFAULT);
+ for (i = 0; i < 8; i++)
+ filter->__icmp6_filt[i] ^= 0xffffffff;
+ optval = filter;
+ }
} else if (level == LX_SOL_SOCKET) {
/* Linux ignores this option. */
if (optname == LX_SO_BSDCOMPAT)
@@ -1770,6 +1804,14 @@ lx_setsockopt(int sockfd, int level, int optname, void *optval, int optlen)
if (optname == LX_ICMP_FILTER &&
strcmp(lx_cmd_name, "ping") == 0)
return (0);
+ /*
+ * Ping6 tries to set the IPV6_CHECKSUM offset in a way that
+ * illumos won't allow. Quietly ignore this to prevent it from
+ * complaining.
+ */
+ if (optname == LX_IPV6_CHECKSUM &&
+ strcmp(lx_cmd_name, "ping6") == 0)
+ return (0);
}
if (!converted) {
@@ -1878,6 +1920,33 @@ lx_getsockopt(int sockfd, int level, int optname, void *optval, int *optlenp)
return (-errno);
return (0);
}
+ if ((level == LX_IPPROTO_ICMPV6) && (optname == LX_ICMP6_FILTER)) {
+ icmp6_filter_t *filter;
+ int i;
+
+ /* Verify there's going to be enough room for the results. */
+ if (uucopy(optlenp, &r, sizeof (int)) != 0)
+ return (-errno);
+ if (r < sizeof (icmp6_filter_t))
+ return (-EINVAL);
+ if ((filter = SAFE_ALLOCA(sizeof (icmp6_filter_t))) == NULL)
+ return (-ENOMEM);
+
+ r = getsockopt(sockfd, IPPROTO_ICMPV6, ICMP6_FILTER, filter,
+ optlenp);
+ if (r != 0)
+ return (-errno);
+
+ /*
+ * ICMP6_FILTER is inverted on Linux. Make it so before copying
+ * back to caller's buffer.
+ */
+ for (i = 0; i < 8; i++)
+ filter->__icmp6_filt[i] ^= 0xffffffff;
+ if ((uucopy(filter, optval, sizeof (icmp6_filter_t))) != 0)
+ return (-errno);
+ return (0);
+ }
orig_optname = optname;
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h
index a5ea7ec76a..58df91a0b7 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h
@@ -111,6 +111,7 @@ extern "C" {
#define LX_IPPROTO_TCP 6
#define LX_IPPROTO_UDP 17
#define LX_IPPROTO_IPV6 41
+#define LX_IPPROTO_ICMPV6 58
#define LX_IPPROTO_RAW 255
/*
@@ -207,6 +208,13 @@ extern "C" {
#define LX_IPV6_TCLASS 67
/*
+ * Options for use with [gs]etsockopt at the IP level.
+ * IPPROTO_ICMPV6
+ */
+
+#define LX_ICMP6_FILTER 1
+
+/*
* Options for use with [gs]etsockopt at the TCP level.
* IPPROTO_TCP
*/