Mercurial > illumos > git > illumos-omnios
changeset 18404:dbf319f845d5
OS-4138 lxbrand socket ioctls should be flexible about address family
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
author | Patrick Mooney <patrick.f.mooney@gmail.com> |
---|---|
date | Tue, 07 Apr 2015 00:47:53 +0000 |
parents | e8188476e197 |
children | 7ac3b7113c98 |
files | usr/src/uts/common/brand/lx/os/lx_brand.c usr/src/uts/common/brand/lx/sys/lx_brand.h usr/src/uts/common/brand/lx/syscall/lx_ioctl.c |
diffstat | 3 files changed, 76 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c Wed Apr 08 16:01:25 2015 +0000 +++ b/usr/src/uts/common/brand/lx/os/lx_brand.c Tue Apr 07 00:47:53 2015 +0000 @@ -169,6 +169,7 @@ #include <sys/core.h> #include <sys/stack.h> #include <sys/stat.h> +#include <sys/socket.h> #include <lx_signum.h> int lx_debug = 0; @@ -678,6 +679,15 @@ * This can be changed by a call to setattr() during zone boot. */ (void) strlcpy(data->lxzd_kernel_version, "2.4.21", LX_VERS_MAX); + + /* + * Linux is not at all picky about address family when it comes to + * supporting interface-related ioctls. To mimic this behavior, we'll + * attempt those ioctls against a ksocket configured for that purpose. + */ + (void) ksocket_socket(&data->lxzd_ioctl_sock, AF_INET, SOCK_DGRAM, 0, + 0, zone->zone_kcred); + zone->zone_brand_data = data; /* @@ -690,7 +700,14 @@ void lx_free_brand_data(zone_t *zone) { - kmem_free(zone->zone_brand_data, sizeof (lx_zone_data_t)); + lx_zone_data_t *data = ztolxzd(zone); + ASSERT(data != NULL); + if (data->lxzd_ioctl_sock != NULL) { + ksocket_close(data->lxzd_ioctl_sock, zone->zone_kcred); + data->lxzd_ioctl_sock = NULL; + } + zone->zone_brand_data = NULL; + kmem_free(data, sizeof (*data)); } void
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h Wed Apr 08 16:01:25 2015 +0000 +++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h Tue Apr 07 00:47:53 2015 +0000 @@ -34,6 +34,7 @@ #include <sys/types.h> #include <sys/cpuvar.h> #include <sys/zone.h> +#include <sys/ksocket.h> #endif #ifdef __cplusplus @@ -587,6 +588,7 @@ /* brand specific data */ typedef struct lx_zone_data { char lxzd_kernel_version[LX_VERS_MAX]; + ksocket_t lxzd_ioctl_sock; } lx_zone_data_t; #define BR_CPU_BOUND 0x0001 @@ -599,6 +601,9 @@ #define ptolxproc(p) \ (((p)->p_brand == &lx_brand) ? \ (struct lx_proc_data *)(p)->p_brand_data : NULL) +#define ztolxzd(z) \ + (((z)->zone_brand == &lx_brand) ? \ + (lx_zone_data_t *)(z)->zone_brand_data : NULL) /* Macro for converting to system call arguments. */ #define LX_ARGS(scall) ((struct lx_##scall##_args *)\
--- a/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c Wed Apr 08 16:01:25 2015 +0000 +++ b/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c Tue Apr 07 00:47:53 2015 +0000 @@ -806,11 +806,35 @@ } static int +ict_if_ioctl(vnode_t *vn, int cmd, intptr_t arg, int flags, cred_t *cred) +{ + int error, rv; + lx_zone_data_t *lxzd = ztolxzd(curproc->p_zone); + ksocket_t ks; + + ASSERT(lxzd != NULL); + ks = lxzd->lxzd_ioctl_sock; + + /* + * For ioctls of this type, Illumos is strict about address family + * whereas Linux is lenient. This strictness can be avoided by using + * an internal AF_INET ksocket. + */ + if (ks != NULL) { + error = ksocket_ioctl(ks, cmd, arg, &rv, cred); + } else { + error = VOP_IOCTL(vn, cmd, arg, flags, cred, &rv, NULL); + } + + return (error); +} + +static int ict_siolifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd) { struct ifreq req; struct lifreq lreq; - int error, rv, len; + int error, len; /* Convert from Linux ifreq to illumos lifreq */ if (curproc->p_model == DATAMODEL_LP64) @@ -844,31 +868,31 @@ */ cmd = ((cmd & IOC_INOUT) | _IOW('i', ((cmd & 0xff) + 100), struct lifreq)); - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); break; case SIOCGIFINDEX: cmd = SIOCGLIFINDEX; - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); break; case SIOCGIFFLAGS: cmd = SIOCGLIFFLAGS; - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); if (error == 0) ict_convert_ifflags(&lreq.lifr_flags, B_FALSE); break; case SIOCSIFFLAGS: cmd = SIOCSLIFFLAGS; ict_convert_ifflags(&lreq.lifr_flags, B_TRUE); - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); break; case SIOCGIFHWADDR: cmd = SIOCGLIFHWADDR; - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); /* * SIOCGIFHWADDR on Linux sets sa_family to ARPHRD_ETHER (1) on * ethernet and ARPHRD_LOOPBACK (772) on loopback. @@ -901,8 +925,8 @@ break; } cmd = SIOCGLIFINDEX; - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&lreq, + FLFAKE(fp), fp->f_cred); if (error == 0) { /* lifr_index aliases to the qlen field */ lreq.lifr_index = 1; @@ -939,15 +963,15 @@ lx_ifconf32_t conf; lx_ifreq32_t *oreq; struct ifconf sconf; - int ifcount, error, rv, i, buf_len; + int ifcount, error, i, buf_len; if (copyin((lx_ifconf32_t *)arg, &conf, sizeof (conf)) != 0) return (set_errno(EFAULT)); /* They want to know how many interfaces there are. */ if (conf.if_len <= 0 || conf.if_buf == NULL) { - error = VOP_IOCTL(fp->f_vnode, SIOCGIFNUM, (intptr_t)&ifcount, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, SIOCGIFNUM, + (intptr_t)&ifcount, FLFAKE(fp), fp->f_cred); if (error != 0) return (set_errno(error)); @@ -964,8 +988,8 @@ sconf.ifc_len = ifcount * sizeof (struct ifreq); sconf.ifc_req = (struct ifreq *)kmem_alloc(sconf.ifc_len, KM_SLEEP); - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&sconf, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&sconf, FLFAKE(fp), + fp->f_cred); if (error != 0) { kmem_free(sconf.ifc_req, ifcount * sizeof (struct ifreq)); return (set_errno(error)); @@ -981,13 +1005,13 @@ conf.if_len = i * sizeof (*oreq); kmem_free(sconf.ifc_req, ifcount * sizeof (struct ifreq)); - rv = 0; + error = 0; if (copyout(oreq, (caddr_t)(uintptr_t)conf.if_buf, conf.if_len) != 0 || copyout(&conf, (lx_ifconf32_t *)arg, sizeof (conf)) != 0) - rv = set_errno(EFAULT); + error = set_errno(EFAULT); kmem_free(oreq, buf_len); - return (rv); + return (error); } static int @@ -996,15 +1020,15 @@ lx_ifconf64_t conf; lx_ifreq64_t *oreq; struct ifconf sconf; - int ifcount, error, rv, i, buf_len; + int ifcount, error, i, buf_len; if (copyin((lx_ifconf64_t *)arg, &conf, sizeof (conf)) != 0) return (set_errno(EFAULT)); /* They want to know how many interfaces there are. */ if (conf.if_len <= 0 || conf.if_buf == NULL) { - error = VOP_IOCTL(fp->f_vnode, SIOCGIFNUM, (intptr_t)&ifcount, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, SIOCGIFNUM, + (intptr_t)&ifcount, FLFAKE(fp), fp->f_cred); if (error != 0) return (set_errno(error)); @@ -1021,8 +1045,8 @@ sconf.ifc_len = ifcount * sizeof (struct ifreq); sconf.ifc_req = (struct ifreq *)kmem_alloc(sconf.ifc_len, KM_SLEEP); - error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&sconf, - FLFAKE(fp), fp->f_cred, &rv, NULL); + error = ict_if_ioctl(fp->f_vnode, cmd, (intptr_t)&sconf, FLFAKE(fp), + fp->f_cred); if (error != 0) { kmem_free(sconf.ifc_req, ifcount * sizeof (struct ifreq)); return (set_errno(error)); @@ -1038,13 +1062,13 @@ conf.if_len = i * sizeof (*oreq); kmem_free(sconf.ifc_req, ifcount * sizeof (struct ifreq)); - rv = 0; + error = 0; if (copyout(oreq, (caddr_t)(uintptr_t)conf.if_buf, conf.if_len) != 0 || copyout(&conf, (lx_ifconf64_t *)arg, sizeof (conf)) != 0) - rv = set_errno(EFAULT); + error = set_errno(EFAULT); kmem_free(oreq, buf_len); - return (rv); + return (error); } static int