diff options
author | Patrick Mooney <patrick.f.mooney@gmail.com> | 2014-12-31 19:26:49 +0000 |
---|---|---|
committer | Patrick Mooney <patrick.f.mooney@gmail.com> | 2014-12-31 19:38:09 +0000 |
commit | 0255a6f9dc26c7acbff2a3013e51cfc1d880723a (patch) | |
tree | 2b6b97f7d33d78e5f1c348e7e3abcbec2f3b712d | |
parent | 75861d9dbca411cd7ab5c8f1aecdaa98dd4a8e46 (diff) | |
download | illumos-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.c | 73 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h | 8 |
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 */ |