diff options
| author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2014-06-24 14:00:14 +0000 |
|---|---|---|
| committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2014-06-24 14:00:14 +0000 |
| commit | efc6e5cdcc71151f6ee1303ac2ca3d7697c83352 (patch) | |
| tree | 770d07a0860083b4f97fe98b93c797cf1bbf952d | |
| parent | c4478258cb0286c071f0fa69305f9491f0415032 (diff) | |
| download | illumos-joyent-efc6e5cdcc71151f6ee1303ac2ca3d7697c83352.tar.gz | |
OS-3024 lx brand setsockopt(ICMP_FILTER): Protocol not available
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 2 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/socket.c | 123 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h | 2 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h | 15 |
4 files changed, 96 insertions, 46 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c index 545062a279..33dc6c5bde 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c +++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c @@ -98,6 +98,7 @@ static int stol_errno[] = { }; char lx_release[LX_VERS_MAX]; +char lx_cmd_name[MAXNAMLEN]; /* * Map a linux locale ending string to the solaris equivalent. @@ -668,6 +669,7 @@ lx_init(int argc, char *argv[], char *envp[]) lx_debug("VERBOSE mode enabled.\n"); } + (void) strlcpy(lx_cmd_name, basename(argv[0]), sizeof (lx_cmd_name)); lx_debug("executing linux process: %s", argv[0]); lx_debug("branding myself and setting handler to 0x%p", (void *)lx_handler_table); 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 a0b17db673..81407c4c56 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/socket.c +++ b/usr/src/lib/brand/lx/lx_brand/common/socket.c @@ -211,35 +211,26 @@ static const int ltos_socket_sockopts[LX_SO_ACCEPTCONN + 1] = { OPTNOTSUP, OPTNOTSUP, SO_ACCEPTCONN }; +/* + * 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 +}; + #define PROTO_SOCKOPTS(opts) \ { (opts), sizeof ((opts)) / sizeof ((opts)[0]) } /* - * The main Linux to Solaris protocol to options mapping table - * IPPROTO_TAB_SIZE can be set up to IPPROTO_MAX. All entries above - * IPPROTO_TAB_SIZE are in effect not implemented, + * [gs]etsockopt options mapping tables */ - -#define IPPROTO_TAB_SIZE 8 - -static const lx_proto_opts_t ltos_proto_opts[IPPROTO_TAB_SIZE] = { - /* IPPROTO_IP 0 */ - PROTO_SOCKOPTS(ltos_ip_sockopts), - /* SOL_SOCKET 1 */ - PROTO_SOCKOPTS(ltos_socket_sockopts), - /* IPPROTO_IGMP 2 */ - PROTO_SOCKOPTS(ltos_igmp_sockopts), - /* NOT IMPLEMENTED 3 */ - { NULL, 0 }, - /* NOT IMPLEMENTED 4 */ - { NULL, 0 }, - /* NOT IMPLEMENTED 5 */ - { NULL, 0 }, - /* IPPROTO_TCP 6 */ - PROTO_SOCKOPTS(ltos_tcp_sockopts), - /* NOT IMPLEMENTED 7 */ - { NULL, 0 } -}; +static lx_proto_opts_t ip_sockopts_tbl = PROTO_SOCKOPTS(ltos_ip_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); +static lx_proto_opts_t tcp_sockopts_tbl = PROTO_SOCKOPTS(ltos_tcp_sockopts); +static lx_proto_opts_t raw_sockopts_tbl = PROTO_SOCKOPTS(ltos_raw_sockopts); /* * Lifted from socket.h, since these definitions are contained within @@ -1294,6 +1285,21 @@ lx_shutdown(ulong_t *args) return ((r < 0) ? -errno : r); } +static lx_proto_opts_t * +get_proto_opt_tbl(int level) +{ + switch (level) { + case LX_IPPROTO_IP: return (&ip_sockopts_tbl); + case LX_SOL_SOCKET: return (&socket_sockopts_tbl); + case LX_IPPROTO_IGMP: return (&igmp_sockopts_tbl); + case LX_IPPROTO_TCP: return (&tcp_sockopts_tbl); + case LX_IPPROTO_RAW: return (&raw_sockopts_tbl); + default: + lx_unsupported("Unsupported sockopt level %d", level); + return (NULL); + } +} + static int lx_setsockopt(ulong_t *args) { @@ -1304,6 +1310,7 @@ lx_setsockopt(ulong_t *args) int optlen = (int)args[4]; int internal_opt; int r; + lx_proto_opts_t *proto_opts; lx_debug("\tsetsockopt(%d, %d, %d, 0x%p, %d)", sockfd, level, optname, optval, optlen); @@ -1315,17 +1322,15 @@ lx_setsockopt(ulong_t *args) if (optval == NULL) return (-EFAULT); + if ((proto_opts = get_proto_opt_tbl(level)) == NULL) + return (-ENOPROTOOPT); + /* * Do a table lookup of the Solaris equivalent of the given option */ - if (level < IPPROTO_IP || level >= IPPROTO_TAB_SIZE) { - lx_unsupported("Unsupported sockopt level %d", level); - return (-ENOPROTOOPT); - } - - if (ltos_proto_opts[level].maxentries == 0 || - optname <= 0 || optname >= (ltos_proto_opts[level].maxentries)) { - lx_unsupported("Unsupported sockopt %d %d", level, optname); + if (optname <= 0 || optname >= proto_opts->maxentries) { + lx_unsupported("Unsupported sockopt %d, proto %d", optname, + level); return (-ENOPROTOOPT); } @@ -1334,12 +1339,29 @@ lx_setsockopt(ulong_t *args) * socket. Currently we just ignore it to make Linux programs happy. */ if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED)) { - lx_unsupported("Unsupported socket option SO_PASSCRED"); + lx_unsupported("Ignored socket option SO_PASSCRED"); return (0); } + /* + * Ping sets this option. Currently we just ignore it to make ping + * happy. + */ + if (level == LX_IPPROTO_RAW && optname == LX_ICMP_FILTER && + strcmp(lx_cmd_name, "ping") == 0) + return (0); + + /* + * Ping sets this option to receive errors on raw sockets. Currently we + * just ignore it to make ping happy. From the Linux ip.7 man page: + * For raw sockets, IP_RECVERR enables passing of all received ICMP + * errors to the application. + */ + if (level == LX_IPPROTO_IP && optname == LX_IP_RECVERR && + strcmp(lx_cmd_name, "ping") == 0) + return (0); - if ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK)) { + if ((level == LX_IPPROTO_TCP) && (optname == LX_TCP_CORK)) { /* * TCP_CORK is a Linux-only option that instructs the TCP * stack not to send out partial frames. Solaris doesn't @@ -1359,10 +1381,14 @@ lx_setsockopt(ulong_t *args) internal_opt = 1; optval = &internal_opt; } else { - optname = ltos_proto_opts[level].proto[optname]; + int orig_optname = optname; - if (optname == OPTNOTSUP) + optname = proto_opts->proto[optname]; + if (optname == OPTNOTSUP) { + lx_unsupported("unsupported sockopt %d, proto %d", + orig_optname, level); return (-ENOPROTOOPT); + } } if (level == LX_SOL_SOCKET) @@ -1382,6 +1408,8 @@ lx_getsockopt(ulong_t *args) void *optval = (void *)args[3]; int *optlenp = (int *)args[4]; int r; + int orig_optname; + lx_proto_opts_t *proto_opts; lx_debug("\tgetsockopt(%d, %d, %d, 0x%p, 0x%p)", sockfd, level, optname, optval, optlenp); @@ -1394,18 +1422,17 @@ lx_getsockopt(ulong_t *args) if (optval == NULL) return (-EFAULT); - /* - * Do a table lookup of the Solaris equivalent of the given option - */ - if (level < IPPROTO_IP || level >= IPPROTO_TAB_SIZE) - return (-EOPNOTSUPP); + if ((proto_opts = get_proto_opt_tbl(level)) == NULL) + return (-ENOPROTOOPT); - if (ltos_proto_opts[level].maxentries == 0 || - optname <= 0 || optname >= (ltos_proto_opts[level].maxentries)) + if (optname <= 0 || optname >= (proto_opts->maxentries)) { + lx_unsupported("Unsupported sockopt %d, proto %d", optname, + level); return (-ENOPROTOOPT); + } if (((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED)) || - ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK))) { + ((level == LX_IPPROTO_TCP) && (optname == LX_TCP_CORK))) { /* * Linux sets LX_SO_PASSCRED when it wants to send credentials * over a socket. Since we do not support it, it is never set @@ -1466,10 +1493,14 @@ lx_getsockopt(ulong_t *args) return (0); } - optname = ltos_proto_opts[level].proto[optname]; + orig_optname = optname; - if (optname == OPTNOTSUP) + optname = proto_opts->proto[optname]; + if (optname == OPTNOTSUP) { + lx_unsupported("unsupported sockopt %d, proto %d", + orig_optname, level); return (-ENOPROTOOPT); + } if (level == LX_SOL_SOCKET) level = SOL_SOCKET; diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h index a59cc738c6..6b8cca86b7 100644 --- a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h +++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h @@ -33,6 +33,7 @@ #include <stdio.h> #include <alloca.h> +#include <dirent.h> #include <sys/types.h> #include <sys/param.h> #include <sys/lwp.h> @@ -44,6 +45,7 @@ extern "C" { #endif extern char lx_release[LX_VERS_MAX]; +extern char lx_cmd_name[MAXNAMLEN]; extern pid_t zoneinit_pid; /* 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 2e1b162c8c..01d876f273 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 @@ -103,6 +103,15 @@ extern "C" { #define SOCK_INVAL -2 /* + * IP Protocol levels. Some of these match the Illumos IPPROTO_* values. + */ +#define LX_IPPROTO_IP 0 +#define LX_IPPROTO_ICMP 1 +#define LX_IPPROTO_IGMP 2 +#define LX_IPPROTO_TCP 6 +#define LX_IPPROTO_RAW 255 + +/* * Options for use with [gs]etsockopt at the IP level. * IPPROTO_IP */ @@ -203,6 +212,12 @@ extern "C" { #define LX_SO_ACCEPTCONN 30 /* + * Options for use with [gs]etsockopt at the RAW level. + * IPPROTO_RAW + */ +#define LX_ICMP_FILTER 1 + +/* * Linux socketcall indices. * These constitute all 17 socket related system calls * |
