Ejemplo n.º 1
0
static void
command(unsigned long io, char *com)
{
  mpcwrite((char *) &io, sizeof io);
  if (io & IOC_IN) mpcwrite(com, IOCPARM_LEN(io));
  if (io & IOC_OUT) mpcread(com, IOCPARM_LEN(io));
}
Ejemplo n.º 2
0
int
_ioctl(int fd, unsigned long com, ...)
#endif
{
	unsigned int size;
	va_list ap;
	void *data;

	size = IOCPARM_LEN(com);
	if (size > 0) {
		va_start(ap, com);
		if (com & IOC_VOID) {
			/*
			 * In the (size > 0 && com & IOC_VOID) case, the
			 * kernel assigns the value of data to an int
			 * and passes a pointer to that int down.
			 */
			/*
			 * XXX-BD: there is no telling what real
			 * applications are passing here.  We may want an
			 * __np_va_space_remaining() or the like to peak
			 * at the passed argument rather than crashing
			 * deep in a library.
			 */
			data = (void *)(intptr_t)(va_arg(ap, int));
		} else {
Ejemplo n.º 3
0
int ioctl(int fd, int request, ...) {
    void *data;
    va_list args;

    va_start(args, request);
    data = (request & IOC_INOUT) ? va_arg(args, void *) : NULL;
    va_end(args);

    if(data == NULL && (request & IOC_INOUT) && IOCPARM_LEN(request) != 0) {
        errno = EFAULT;
        return -1;
    }

    fd = request != FIONBIO ? _socketGetFd(fd) : fd;
    if(fd == -1)
        return -1;

    switch(request) {
        case FIONBIO: {
            // See note in fcntl (below)
            int flags = fcntl(fd, F_GETFL, 0);
            if(flags == -1)
                return -1;
            flags = *(int *)data != 0 ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
            return fcntl(fd, F_SETFL, flags);
        }
        case BIOCSETF:
        case BIOCSETWF:
        case BIOCSETFNR: {
            int ret;
            struct bpf_program *prog = (struct bpf_program *)data;
            if(prog->bf_len > BPF_MAXBUFSIZE) {
                errno = EINVAL;
                return -1;
            }

            struct bpf_program_serialized *prog_ser = (struct bpf_program_serialized *)malloc(sizeof(struct bpf_program_serialized));
            if(prog_ser == NULL) {
                errno = ENOMEM;
                return -1;
            }

            prog_ser->bf_len = prog->bf_len;
            memcpy(prog_ser->bf_insns, prog->bf_insns, prog->bf_len);

            request = _IOC(request & IOC_DIRMASK, IOCGROUP(request), IOCBASECMD(request), sizeof(struct bpf_program_serialized));
            ret = bsdIoctl(fd, request, prog_ser);
            free(prog_ser);
            return _socketParseBsdResult(NULL, ret);
        }
        default:
            return _socketParseBsdResult(NULL, bsdIoctl(fd, request, data));
    }
}
Ejemplo n.º 4
0
int
uts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *l)
{
    int error = 0;
    struct uts_softc *sc = v;
    struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;

    DPRINTF(("uts_ioctl(%d, '%c', %d)\n",
             IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));

    switch (cmd) {
    case WSMOUSEIO_SCALIBCOORDS:
        if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 &&
                wsmc->miny >= 0 && wsmc->maxy >= 0 &&
                wsmc->resx >= 0 && wsmc->resy >= 0 &&
                wsmc->minx < 32768 && wsmc->maxx < 32768 &&
                wsmc->miny < 32768 && wsmc->maxy < 32768 &&
                (wsmc->maxx - wsmc->minx) != 0 &&
                (wsmc->maxy - wsmc->miny) != 0 &&
                wsmc->resx < 32768 && wsmc->resy < 32768 &&
                wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
                wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
            return (EINVAL);

        sc->sc_tsscale.minx = wsmc->minx;
        sc->sc_tsscale.maxx = wsmc->maxx;
        sc->sc_tsscale.miny = wsmc->miny;
        sc->sc_tsscale.maxy = wsmc->maxy;
        sc->sc_tsscale.swapxy = wsmc->swapxy;
        sc->sc_tsscale.resx = wsmc->resx;
        sc->sc_tsscale.resy = wsmc->resy;
        sc->sc_rawmode = wsmc->samplelen;
        break;
    case WSMOUSEIO_GCALIBCOORDS:
        wsmc->minx = sc->sc_tsscale.minx;
        wsmc->maxx = sc->sc_tsscale.maxx;
        wsmc->miny = sc->sc_tsscale.miny;
        wsmc->maxy = sc->sc_tsscale.maxy;
        wsmc->swapxy = sc->sc_tsscale.swapxy;
        wsmc->resx = sc->sc_tsscale.resx;
        wsmc->resy = sc->sc_tsscale.resy;
        wsmc->samplelen = sc->sc_rawmode;
        break;
    case WSMOUSEIO_GTYPE:
        *(u_int *)data = WSMOUSE_TYPE_TPANEL;
        break;
    default:
        error = ENOTTY;
        break;
    }

    return (error);
}
Ejemplo n.º 5
0
/**
 * Device I/O Control entry point.
 *
 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
 * @param   Dev         The device number (major+minor).
 * @param   iCmd        The IOCtl command.
 * @param   pData       Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
 * @param   fFlags      Flag saying we're a character device (like we didn't know already).
 * @param   pProcess    The process issuing this request.
 */
static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
{
    uint32_t cbReq = IOCPARM_LEN(iCmd);
    PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
    int rc;

    Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
    switch (IOCBASECMD(iCmd))
    {
        case IOCBASECMD(VBOXNETADP_CTL_ADD):
        {
            if (   (IOC_DIRMASK & iCmd) != IOC_INOUT
                || cbReq < sizeof(VBOXNETADPREQ))
                return EINVAL;

            PVBOXNETADP pNew;
            Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
            rc = vboxNetAdpCreate(&pNew,
                                  pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
                                  pReq->szName : NULL);
            if (RT_FAILURE(rc))
                return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;

            Assert(strlen(pReq->szName) < sizeof(pReq->szName));
            strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
            pReq->szName[sizeof(pReq->szName) - 1] = '\0';
            Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
            break;
        }

        case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
        {
            if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
                return EINVAL;

            PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
            if (!pAdp)
                return EINVAL;

            rc = vboxNetAdpDestroy(pAdp);
            if (RT_FAILURE(rc))
                return EINVAL;
            Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
            break;
        }

        default:
            printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
            return EINVAL;
    }

    return 0;
}
Ejemplo n.º 6
0
/**
 * Driver ioctl, an alternate entry point for this character driver.
 *
 * @param   Dev             Device number
 * @param   iCmd            Operation identifier
 * @param   iArgs           Arguments from user to driver
 * @param   Mode            Information bitfield (read/write, address space etc.)
 * @param   pCred           User credentials
 * @param   pVal            Return value for calling process.
 *
 * @return  corresponding solaris error code.
 */
static int vgdrvSolarisIOCtl(dev_t Dev, int iCmd, intptr_t iArgs, int Mode, cred_t *pCred, int *pVal)
{
    /*
     * Get the session from the soft state item.
     */
    vboxguest_state_t *pState = ddi_get_soft_state(g_pvgdrvSolarisState, getminor(Dev));
    if (!pState)
    {
        LogRel(("vgdrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
        return EINVAL;
    }

    PVBOXGUESTSESSION pSession = pState->pSession;
    if (!pSession)
    {
        LogRel(("vgdrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
        return DDI_SUCCESS;
    }

    /*
     * Deal with fast requests.
     */
    if (VBGL_IOCTL_IS_FAST(iCmd))
    {
        *pVal = VGDrvCommonIoCtlFast(iCmd, &g_DevExt, pSession);
        return 0;
    }

    /*
     * It's kind of simple if this is a kernel session, take slow path if user land.
     */
    if (pSession->R0Process == NIL_RTR0PROCESS)
    {
        if (IOCPARM_LEN(iCmd) == sizeof(VBGLREQHDR))
        {
            PVBGLREQHDR pHdr = (PVBGLREQHDR)iArgs;
            int rc;
            if (iCmd != VBGL_IOCTL_IDC_DISCONNECT)
                rc =VGDrvCommonIoCtl(iCmd, &g_DevExt, pSession, pHdr, RT_MAX(pHdr->cbIn, pHdr->cbOut));
            else
            {
                pState->pSession = NULL;
                rc = VGDrvCommonIoCtl(iCmd, &g_DevExt, pSession, pHdr, RT_MAX(pHdr->cbIn, pHdr->cbOut));
                if (RT_FAILURE(rc))
                    pState->pSession = pSession;
            }
            return rc;
        }
    }

    return vgdrvSolarisIOCtlSlow(pSession, iCmd, Mode, iArgs);
}
Ejemplo n.º 7
0
int
main(int ac, char **av)
{
	unsigned long cmd;
	const char *name;
	char *cp;
	int group, i;

	if (ac < 2)
		usage(av);
	printf("  command :  dir  group num  len name\n");
	for (i = 1; i < ac; i++) {
		errno = 0;
		cmd = strtoul(av[i], &cp, 0);
		if (*cp != '\0' || errno != 0) {
			fprintf(stderr, "Invalid integer: %s\n", av[i]);
			usage(av);
		}
		printf("0x%08lx: ", cmd);
		switch (cmd & IOC_DIRMASK) {
		case IOC_VOID:
			printf("VOID ");
			break;
		case IOC_OUT:
			printf("OUT  ");
			break;
		case IOC_IN:
			printf("IN   ");
			break;
		case IOC_INOUT:
			printf("INOUT");
			break;
		default:
			printf("%01lx ???", (cmd & IOC_DIRMASK) >> 29);
			break;
		}
		printf(" ");
		group = IOCGROUP(cmd);
		if (isprint(group))
			printf(" '%c' ", group);
		else
			printf(" 0x%02x", group);
		printf(" %3lu %4lu", cmd & 0xff, IOCPARM_LEN(cmd));
		name = sysdecode_ioctlname(cmd);
		if (name != NULL)
			printf(" %s", name);
		printf("\n");
	}
	return (0);
}
Ejemplo n.º 8
0
static int
sgx_linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
{
	uint8_t data[SGX_IOCTL_MAX_DATA_LEN];
	cap_rights_t rights;
	struct file *fp;
	u_long cmd;
	int error;
	int len;

	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
	if (error != 0)
		return (error);

	cmd = args->cmd;

	args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
	if (cmd & LINUX_IOC_IN)
		args->cmd |= IOC_IN;
	if (cmd & LINUX_IOC_OUT)
		args->cmd |= IOC_OUT;

	len = IOCPARM_LEN(cmd);
	if (len > SGX_IOCTL_MAX_DATA_LEN) {
		printf("%s: Can't copy data: cmd len is too big %d\n",
		    __func__, len);
		return (EINVAL);
	}

	if (cmd & LINUX_IOC_IN) {
		error = copyin((void *)args->arg, data, len);
		if (error) {
			printf("%s: Can't copy data, error %d\n",
			    __func__, error);
			return (EINVAL);
		}
	}

	error = (fo_ioctl(fp, args->cmd, (caddr_t)data, td->td_ucred, td));
	fdrop(fp, td);

	return (error);
}
Ejemplo n.º 9
0
/**
 * Driver ioctl, an alternate entry point for this character driver.
 *
 * @param   Dev             Device number
 * @param   Cmd             Operation identifier
 * @param   pArg            Arguments from user to driver
 * @param   Mode            Information bitfield (read/write, address space etc.)
 * @param   pCred           User credentials
 * @param   pVal            Return value for calling process.
 *
 * @return  corresponding solaris error code.
 */
static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
{
    LogFlow((DEVICE_NAME ":VBoxGuestSolarisIOCtl\n"));

    /*
     * Get the session from the soft state item.
     */
    vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
    if (!pState)
    {
        LogRel((DEVICE_NAME "::IOCtl: no state data for %d\n", getminor(Dev)));
        return EINVAL;
    }

    PVBOXGUESTSESSION pSession = pState->pSession;
    if (!pSession)
    {
        LogRel((DEVICE_NAME "::IOCtl: no session data for %d\n", getminor(Dev)));
        return EINVAL;
    }

    /*
     * Read and validate the request wrapper.
     */
    VBGLBIGREQ ReqWrap;
    if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
    {
        LogRel((DEVICE_NAME "::IOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
        return ENOTTY;
    }

    int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%#x.\n", pArg, Cmd, rc));
        return EINVAL;
    }

    if (ReqWrap.u32Magic != VBGLBIGREQ_MAGIC)
    {
        LogRel((DEVICE_NAME "::IOCtl: bad magic %#x; pArg=%p Cmd=%#x.\n", ReqWrap.u32Magic, pArg, Cmd));
        return EINVAL;
    }
    if (RT_UNLIKELY(ReqWrap.cbData > _1M*16))
    {
        LogRel((DEVICE_NAME "::IOCtl: bad size %#x; pArg=%p Cmd=%#x.\n", ReqWrap.cbData, pArg, Cmd));
        return EINVAL;
    }

    /*
     * Read the request payload if any; requests like VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS have no data payload.
     */
    void *pvBuf = NULL;
    if (RT_LIKELY(ReqWrap.cbData > 0))
    {
        pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
        if (RT_UNLIKELY(!pvBuf))
        {
            LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
            return ENOMEM;
        }

        rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
        if (RT_UNLIKELY(rc))
        {
            RTMemTmpFree(pvBuf);
            LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
            return EFAULT;
        }
        if (RT_UNLIKELY(!VALID_PTR(pvBuf)))
        {
            RTMemTmpFree(pvBuf);
            LogRel((DEVICE_NAME "::IOCtl: pvBuf invalid pointer %p\n", pvBuf));
            return EINVAL;
        }
    }
    Log((DEVICE_NAME "::IOCtl: pSession=%p pid=%d.\n", pSession, (int)RTProcSelf()));

    /*
     * Process the IOCtl.
     */
    size_t cbDataReturned = 0;
    rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, ReqWrap.cbData, &cbDataReturned);
    if (RT_SUCCESS(rc))
    {
        rc = 0;
        if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
        {
            LogRel((DEVICE_NAME "::IOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
            cbDataReturned = ReqWrap.cbData;
        }
        if (cbDataReturned > 0)
        {
            rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
            if (RT_UNLIKELY(rc))
            {
                LogRel((DEVICE_NAME "::IOCtl: ddi_copyout failed; pvBuf=%p pArg=%p cbDataReturned=%u Cmd=%d. rc=%d\n",
                        pvBuf, pArg, cbDataReturned, Cmd, rc));
                rc = EFAULT;
            }
        }
    }
    else
    {
        /*
         * We Log() instead of LogRel() here because VBOXGUEST_IOCTL_WAITEVENT can return VERR_TIMEOUT,
         * VBOXGUEST_IOCTL_CANCEL_ALL_EVENTS can return VERR_INTERRUPTED and possibly more in the future;
         * which are not really failures that require logging.
         */
        Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", Cmd, rc));
        rc = RTErrConvertToErrno(rc);
    }
    *pVal = rc;
    if (pvBuf)
        RTMemTmpFree(pvBuf);
    return rc;
}
/**
 * IOCTL handler
 *
 */
static int VBoxGuestFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
{
    LogFlow((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl\n"));

    int rc = 0;

    /*
     * Validate the input.
     */
    PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pDev->si_drv1;
    if (RT_UNLIKELY(!VALID_PTR(pSession)))
        return EINVAL;

    /*
     * Validate the request wrapper.
     */
    if (IOCPARM_LEN(ulCmd) != sizeof(VBGLBIGREQ))
    {
        Log((DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad request %lu size=%lu expected=%d\n", ulCmd, IOCPARM_LEN(ulCmd), sizeof(VBGLBIGREQ)));
        return ENOTTY;
    }

    PVBGLBIGREQ ReqWrap = (PVBGLBIGREQ)pvData;
    if (ReqWrap->u32Magic != VBGLBIGREQ_MAGIC)
    {
        Log((DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad magic %#x; pArg=%p Cmd=%lu.\n", ReqWrap->u32Magic, pvData, ulCmd));
        return EINVAL;
    }
    if (RT_UNLIKELY(   ReqWrap->cbData == 0
                    || ReqWrap->cbData > _1M*16))
    {
        printf(DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad size %#x; pArg=%p Cmd=%lu.\n", ReqWrap->cbData, pvData, ulCmd);
        return EINVAL;
    }

    /*
     * Read the request.
     */
    void *pvBuf = RTMemTmpAlloc(ReqWrap->cbData);
    if (RT_UNLIKELY(!pvBuf))
    {
        Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap->cbData));
        return ENOMEM;
    }

    rc = copyin((void *)(uintptr_t)ReqWrap->pvDataR3, pvBuf, ReqWrap->cbData);
    if (RT_UNLIKELY(rc))
    {
        RTMemTmpFree(pvBuf);
        Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: copyin failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, pvData, ulCmd, rc));
        return EFAULT;
    }
    if (RT_UNLIKELY(   ReqWrap->cbData != 0
                    && !VALID_PTR(pvBuf)))
    {
        RTMemTmpFree(pvBuf);
        Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: pvBuf invalid pointer %p\n", pvBuf));
        return EINVAL;
    }
    Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: pSession=%p pid=%d.\n", pSession, (int)RTProcSelf()));

    /*
     * Process the IOCtl.
     */
    size_t cbDataReturned;
    rc = VbgdCommonIoCtl(ulCmd, &g_DevExt, pSession, pvBuf, ReqWrap->cbData, &cbDataReturned);
    if (RT_SUCCESS(rc))
    {
        rc = 0;
        if (RT_UNLIKELY(cbDataReturned > ReqWrap->cbData))
        {
            Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap->cbData));
            cbDataReturned = ReqWrap->cbData;
        }
        if (cbDataReturned > 0)
        {
            rc = copyout(pvBuf, (void *)(uintptr_t)ReqWrap->pvDataR3, cbDataReturned);
            if (RT_UNLIKELY(rc))
            {
                Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: copyout failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, pvData, ulCmd, rc));
                rc = EFAULT;
            }
        }
    }
    else
    {
        Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: VbgdCommonIoCtl failed. rc=%d\n", rc));
        rc = EFAULT;
    }
    RTMemTmpFree(pvBuf);
    return rc;
}
/**
 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
 *
 * @returns Solaris errno.
 *
 * @param   pSession    The session.
 * @param   Cmd         The IOCtl command.
 * @param   Mode        Information bitfield (for specifying ownership of data)
 * @param   iArg        User space address of the request buffer.
 */
static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
{
    int         rc;
    uint32_t    cbBuf = 0;
    union
    {
        SUPREQHDR   Hdr;
        uint8_t     abBuf[64];
    }           StackBuf;
    PSUPREQHDR  pHdr;


    /*
     * Read the header.
     */
    if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
        return EINVAL;
    }
    rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
        return EFAULT;
    }
    if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
        return EINVAL;
    }
    cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
    if (RT_UNLIKELY(    StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
                    ||  StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr)
                    ||  cbBuf > _1M*16))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
        return EINVAL;
    }

    /*
     * Buffer the request.
     */
    if (cbBuf <= sizeof(StackBuf))
        pHdr = &StackBuf.Hdr;
    else
    {
        pHdr = RTMemTmpAlloc(cbBuf);
        if (RT_UNLIKELY(!pHdr))
        {
            LogRel(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
            return ENOMEM;
        }
    }
    rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
        if (pHdr != &StackBuf.Hdr)
            RTMemFree(pHdr);
        return EFAULT;
    }

    /*
     * Process the IOCtl.
     */
    rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr, cbBuf);

    /*
     * Copy ioctl data and output buffer back to user space.
     */
    if (RT_LIKELY(!rc))
    {
        uint32_t cbOut = pHdr->cbOut;
        if (RT_UNLIKELY(cbOut > cbBuf))
        {
            LogRel(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
            cbOut = cbBuf;
        }
        rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
        if (RT_UNLIKELY(rc != 0))
        {
            /* this is really bad */
            LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
            rc = EFAULT;
        }
    }
    else
        rc = EINVAL;

    if (pHdr != &StackBuf.Hdr)
        RTMemTmpFree(pHdr);
    return rc;
}
Ejemplo n.º 12
0
/**
 * Worker for VbgdDarwinIOCtl that takes the slow IOCtl functions.
 *
 * @returns Darwin errno.
 *
 * @param pSession  The session.
 * @param iCmd      The IOCtl command.
 * @param pData     Pointer to the kernel copy of the data buffer.
 * @param pProcess  The calling process.
 */
static int VbgdDarwinIOCtlSlow(PVBOXGUESTSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
{
    LogFlow(("VbgdDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));


    /*
     * Buffered or unbuffered?
     */
    void *pvReqData;
    user_addr_t pUser = 0;
    void *pvPageBuf = NULL;
    uint32_t cbReq = IOCPARM_LEN(iCmd);
    if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
    {
        /*
         * Raw buffered request data, common code validates it.
         */
        pvReqData = pData;
    }
    else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
    {
        /*
         * Get the header and figure out how much we're gonna have to read.
         */
        VBGLBIGREQ Hdr;
        pUser = (user_addr_t)*(void **)pData;
        int rc = copyin(pUser, &Hdr, sizeof(Hdr));
        if (RT_UNLIKELY(rc))
        {
            Log(("VbgdDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
            return rc;
        }
        if (RT_UNLIKELY(Hdr.u32Magic != VBGLBIGREQ_MAGIC))
        {
            Log(("VbgdDarwinIOCtlSlow: bad magic u32Magic=%#x; iCmd=%#lx\n", Hdr.u32Magic, iCmd));
            return EINVAL;
        }
        cbReq = Hdr.cbData;
        if (RT_UNLIKELY(cbReq > _1M*16))
        {
            Log(("VbgdDarwinIOCtlSlow: %#x; iCmd=%#lx\n", Hdr.cbData, iCmd));
            return EINVAL;
        }
        pUser = Hdr.pvDataR3;

        /*
         * Allocate buffer and copy in the data.
         */
        pvReqData = RTMemTmpAlloc(cbReq);
        if (!pvReqData)
            pvPageBuf = pvReqData = IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
        if (RT_UNLIKELY(!pvReqData))
        {
            Log(("VbgdDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
            return ENOMEM;
        }
        rc = copyin(pUser, pvReqData, Hdr.cbData);
        if (RT_UNLIKELY(rc))
        {
            Log(("VbgdDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
                 (unsigned long long)pUser, pvReqData, Hdr.cbData, rc, iCmd));
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pvReqData);
            return rc;
        }
    }
    else
    {
        Log(("VbgdDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
        return EINVAL;
    }

    /*
     * Process the IOCtl.
     */
    size_t cbReqRet = 0;
    int rc = VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pSession, pvReqData, cbReq, &cbReqRet);
    if (RT_SUCCESS(rc))
    {
        /*
         * If not buffered, copy back the buffer before returning.
         */
        if (pUser)
        {
            if (cbReqRet > cbReq)
            {
                Log(("VbgdDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbReqRet, cbReq, iCmd));
                cbReqRet = cbReq;
            }
            rc = copyout(pvReqData, pUser, cbReqRet);
            if (RT_UNLIKELY(rc))
                Log(("VbgdDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
                     pvReqData, (unsigned long long)pUser, cbReqRet, rc, iCmd));

            /* cleanup */
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pvReqData);
        }
        else
            rc = 0;
    }
    else
    {
        /*
         * The request failed, just clean up.
         */
        if (pUser)
        {
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pvReqData);
        }

        Log(("VbgdDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
        rc = EINVAL;
    }

    Log2(("VbgdDarwinIOCtlSlow: returns %d\n", rc));
    return rc;
}
Ejemplo n.º 13
0
/**
 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
 *
 * @returns Darwin errno.
 *
 * @param pSession  The session.
 * @param iCmd      The IOCtl command.
 * @param pData     Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
 * @param pProcess  The calling process.
 */
static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
{
    LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));


    /*
     * Buffered or unbuffered?
     */
    PSUPREQHDR pHdr;
    user_addr_t pUser = 0;
    void *pvPageBuf = NULL;
    uint32_t cbReq = IOCPARM_LEN(iCmd);
    if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
    {
        pHdr = (PSUPREQHDR)pData;
        if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY(    RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
                        ||  pHdr->cbIn < sizeof(*pHdr)
                        ||  pHdr->cbOut < sizeof(*pHdr)))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
            return EINVAL;
        }
    }
    else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
    {
        /*
         * Get the header and figure out how much we're gonna have to read.
         */
        SUPREQHDR Hdr;
        pUser = (user_addr_t)*(void **)pData;
        int rc = copyin(pUser, &Hdr, sizeof(Hdr));
        if (RT_UNLIKELY(rc))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
            return rc;
        }
        if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
            return EINVAL;
        }
        cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
        if (RT_UNLIKELY(    Hdr.cbIn < sizeof(Hdr)
                        ||  Hdr.cbOut < sizeof(Hdr)
                        ||  cbReq > _1M*16))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
            return EINVAL;
        }

        /*
         * Allocate buffer and copy in the data.
         */
        pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
        if (!pHdr)
            pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
        if (RT_UNLIKELY(!pHdr))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
            return ENOMEM;
        }
        rc = copyin(pUser, pHdr, Hdr.cbIn);
        if (RT_UNLIKELY(rc))
        {
            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
                        (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pHdr);
            return rc;
        }
    }
    else
    {
        Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
        return EINVAL;
    }

    /*
     * Process the IOCtl.
     */
    int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
    if (RT_LIKELY(!rc))
    {
        /*
         * If not buffered, copy back the buffer before returning.
         */
        if (pUser)
        {
            uint32_t cbOut = pHdr->cbOut;
            if (cbOut > cbReq)
            {
                OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
                cbOut = cbReq;
            }
            rc = copyout(pHdr, pUser, cbOut);
            if (RT_UNLIKELY(rc))
                OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
                            pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));

            /* cleanup */
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pHdr);
        }
    }
    else
    {
        /*
         * The request failed, just clean up.
         */
        if (pUser)
        {
            if (pvPageBuf)
                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
            else
                RTMemTmpFree(pHdr);
        }

        Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
        rc = EINVAL;
    }

    Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
    return rc;
}
Ejemplo n.º 14
0
/*
 * Ioctl system call
 */
int anp_ioctl(int fd,int ucom,caddr_t udata)
{
     struct socket *sock;
     register int com, error;
     register u_int size;
     caddr_t data, memp;
     int tmp;
#define STK_PARAMS	128
     char stkbuf[STK_PARAMS];

     MU_LOCK(kern_lock_p);
     sock=anp_fdfind(fd);

     com=ucom;
/* AC: since we don't support exec() in sim. environment, we don't support
 * these ioctl's either...
 */
#ifdef NOPE
     switch (com = ucom) {
     case FIONCLEX:
	  fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
	  MU_UNLOCK(kern_lock_p);
	  return (0);
     case FIOCLEX:
	  fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
	  MU_UNLOCK(kern_lock_p);
	  return (0);
     }
#endif

     /*
      * Interpret high order word to find amount of data to be
      * copied to/from the user's address space.
      */
     size = IOCPARM_LEN(com);
     if (size > IOCPARM_MAX) {
	  anp_errno=ENOTTY;
	  MU_UNLOCK(kern_lock_p);
	  return -1;
     }
     memp = NULL;
     if (size > sizeof (stkbuf)) {
	  memp = (caddr_t)anp_sys_malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
	  data = memp;
     } else
	  data = stkbuf;
     if (com&IOC_IN) {
	  if (size) {
	       error = copyin(udata, data, (u_int)size);
	       if (error) {
		    if (memp)
			 anp_sys_free(memp, M_IOCTLOPS);
		    anp_errno=error;
		    MU_UNLOCK(kern_lock_p);
		    return -1;
	       }
	  } else
	       *(caddr_t *)data = udata;
     } else if ((com&IOC_OUT) && size)
	  /*
	   * Zero the buffer so the user always
	   * gets back something deterministic.
	   */
	  bzero(data, size);
     else if (com&IOC_VOID)
	  *(caddr_t *)data = udata;

     switch (com) {

     case FIONBIO:
     case FIOASYNC:
	  tmp = *((int *) data);
	  error = (soo_ioctl)(sock, com, (caddr_t)&tmp);
	  break;
#ifdef NOPE
     case FIOSETOWN:
	  tmp = *((int *)data);
	  if (fp->f_type == DTYPE_SOCKET) {
	       ((struct socket *)fp->f_data)->so_pgid = tmp;
	       error = 0;
	       break;
	  }
	  if (tmp <= 0) {
	       tmp = -tmp;
	  } else {
	       struct proc *p1 = pfind(tmp);
	       if (p1 == 0) {
		    error = ESRCH;
		    break;
	       }
	       tmp = p1->p_pgrp->pg_id;
	  }
	  error = (*fp->f_ops->fo_ioctl)
	       (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
	  break;

     case FIOGETOWN:
	  if (fp->f_type == DTYPE_SOCKET) {
	       error = 0;
	       *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
	       break;
	  }
	  error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
	  *(int *)data = -*(int *)data;
	  break;

#endif
     default:
	  error = soo_ioctl(sock, com, data);
	  /*
	   * Copy any data to user, size was
	   * already set and checked above.
	   */
	  if (error == 0 && (com&IOC_OUT) && size)
	       error = copyout(data, udata, (u_int)size);
	  break;
     }
     if (memp)
	  anp_sys_free(memp, M_IOCTLOPS);
     anp_errno=error;
     MU_UNLOCK(kern_lock_p);
     if (anp_errno!=0) {
	  return -1;
     } else {
	  return 0;
     }
}
Ejemplo n.º 15
0
char *
print_arg(struct syscall_args *sc, unsigned long *args, long retval,
    struct trussinfo *trussinfo)
{
	char *tmp;
	pid_t pid;

	tmp = NULL;
	pid = trussinfo->pid;
	switch (sc->type & ARG_MASK) {
	case Hex:
		asprintf(&tmp, "0x%x", (int)args[sc->offset]);
		break;
	case Octal:
		asprintf(&tmp, "0%o", (int)args[sc->offset]);
		break;
	case Int:
		asprintf(&tmp, "%d", (int)args[sc->offset]);
		break;
	case Name: {
		/* NULL-terminated string. */
		char *tmp2;
		tmp2 = get_string(pid, (void*)args[sc->offset], 0);
		asprintf(&tmp, "\"%s\"", tmp2);
		free(tmp2);
		break;
	}
	case BinString: {
		/* Binary block of data that might have printable characters.
		   XXX If type|OUT, assume that the length is the syscall's
		   return value.  Otherwise, assume that the length of the block
		   is in the next syscall argument. */
		int max_string = trussinfo->strsize;
		char tmp2[max_string+1], *tmp3;
		int len;
		int truncated = 0;

		if (sc->type & OUT)
			len = retval;
		else
			len = args[sc->offset + 1];

		/* Don't print more than max_string characters, to avoid word
		   wrap.  If we have to truncate put some ... after the string.
		*/
		if (len > max_string) {
			len = max_string;
			truncated = 1;
		}
		if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
		    != -1) {
			tmp3 = malloc(len * 4 + 1);
			while (len) {
				if (strvisx(tmp3, tmp2, len,
				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
					break;
				len--;
				truncated = 1;
			};
			asprintf(&tmp, "\"%s\"%s", tmp3, truncated ?
			    "..." : "");
			free(tmp3);
		} else {
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		}
		break;
	}
	case StringArray: {
		int num, size, i;
		char *tmp2;
		char *string;
		char *strarray[100];	/* XXX This is ugly. */

		if (get_struct(pid, (void *)args[sc->offset],
		    (void *)&strarray, sizeof(strarray)) == -1)
			err(1, "get_struct %p", (void *)args[sc->offset]);
		num = 0;
		size = 0;

		/* Find out how large of a buffer we'll need. */
		while (strarray[num] != NULL) {
			string = get_string(pid, (void*)strarray[num], 0);
			size += strlen(string);
			free(string);
			num++;
		}
		size += 4 + (num * 4);
		tmp = (char *)malloc(size);
		tmp2 = tmp;

		tmp2 += sprintf(tmp2, " [");
		for (i = 0; i < num; i++) {
			string = get_string(pid, (void*)strarray[i], 0);
			tmp2 += sprintf(tmp2, " \"%s\"%c", string,
			    (i + 1 == num) ? ' ' : ',');
			free(string);
		}
		tmp2 += sprintf(tmp2, "]");
		break;
	}
#ifdef __LP64__
	case Quad:
		asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
#else
	case Quad: {
		unsigned long long ll;
		ll = *(unsigned long long *)(args + sc->offset);
		asprintf(&tmp, "0x%llx", ll);
		break;
	}
#endif
	case Ptr:
		asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	case Readlinkres: {
		char *tmp2;
		if (retval == -1) {
			tmp = strdup("");
			break;
		}
		tmp2 = get_string(pid, (void*)args[sc->offset], retval);
		asprintf(&tmp, "\"%s\"", tmp2);
		free(tmp2);
		break;
	}
	case Ioctl: {
		const char *temp = ioctlname(args[sc->offset]);
		if (temp)
			tmp = strdup(temp);
		else {
			unsigned long arg = args[sc->offset];
			asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
			    arg, arg & IOC_OUT ? "R" : "",
			    arg & IOC_IN ? "W" : "", IOCGROUP(arg),
			    isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?',
			    arg & 0xFF, IOCPARM_LEN(arg));
		}
		break;
	}
	case Umtx: {
		struct umtx umtx;
		if (get_struct(pid, (void *)args[sc->offset], &umtx,
		    sizeof(umtx)) != -1)
			asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner);
		else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Timespec: {
		struct timespec ts;
		if (get_struct(pid, (void *)args[sc->offset], &ts,
		    sizeof(ts)) != -1)
			asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec,
			    ts.tv_nsec);
		else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Timeval: {
		struct timeval tv;
		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
		    != -1)
			asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec,
			    tv.tv_usec);
		else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Timeval2: {
		struct timeval tv[2];
		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
		    != -1)
			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
			    (long)tv[0].tv_sec, tv[0].tv_usec,
			    (long)tv[1].tv_sec, tv[1].tv_usec);
		else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Itimerval: {
		struct itimerval itv;
		if (get_struct(pid, (void *)args[sc->offset], &itv,
		    sizeof(itv)) != -1)
			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
			    (long)itv.it_interval.tv_sec,
			    itv.it_interval.tv_usec,
			    (long)itv.it_value.tv_sec,
			    itv.it_value.tv_usec);
		else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case LinuxSockArgs:
	{
		struct linux_socketcall_args largs;
		if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
		    sizeof(largs)) == -1) {
			err(1, "get_struct %p", (void *)args[sc->offset]);
		}
		const char *what;
		char buf[30];

		switch (largs.what) {
		case LINUX_SOCKET:
			what = "LINUX_SOCKET";
			break;
		case LINUX_BIND:
			what = "LINUX_BIND";
			break;
		case LINUX_CONNECT:
			what = "LINUX_CONNECT";
			break;
		case LINUX_LISTEN:
			what = "LINUX_LISTEN";
			break;
		case LINUX_ACCEPT:
			what = "LINUX_ACCEPT";
			break;
		case LINUX_GETSOCKNAME:
			what = "LINUX_GETSOCKNAME";
			break;
		case LINUX_GETPEERNAME:
			what = "LINUX_GETPEERNAME";
			break;
		case LINUX_SOCKETPAIR:
			what = "LINUX_SOCKETPAIR";
			break;
		case LINUX_SEND:   
			what = "LINUX_SEND";
			break;
		case LINUX_RECV: 
			what = "LINUX_RECV";
			break;
		case LINUX_SENDTO:
			what = "LINUX_SENDTO";
			break;
		case LINUX_RECVFROM:
			what = "LINUX_RECVFROM";
			break;
		case LINUX_SHUTDOWN:
			what = "LINUX_SHUTDOWN";
			break;
		case LINUX_SETSOCKOPT:
			what = "LINUX_SETSOCKOPT";
			break;
		case LINUX_GETSOCKOPT:
			what = "LINUX_GETSOCKOPT";
			break;
		case LINUX_SENDMSG:
			what = "LINUX_SENDMSG";
			break;
		case LINUX_RECVMSG:
			what = "LINUX_RECVMSG";
			break;
		default:
			sprintf(buf, "%d", largs.what);
			what = buf;
			break;
		}
		asprintf(&tmp, "(0x%lx)%s, 0x%lx", args[sc->offset], what, (long unsigned int)largs.args);
		break;
	}
	case Pollfd: {
		/*
		 * XXX: A Pollfd argument expects the /next/ syscall argument
		 * to be the number of fds in the array. This matches the poll
		 * syscall.
		 */
		struct pollfd *pfd;
		int numfds = args[sc->offset+1];
		int bytes = sizeof(struct pollfd) * numfds;
		int i, tmpsize, u, used;
		const int per_fd = 100;

		if ((pfd = malloc(bytes)) == NULL)
			err(1, "Cannot malloc %d bytes for pollfd array",
			    bytes);
		if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
		    != -1) {
			used = 0;
			tmpsize = 1 + per_fd * numfds + 2;
			if ((tmp = malloc(tmpsize)) == NULL)
				err(1, "Cannot alloc %d bytes for poll output",
				    tmpsize);

			tmp[used++] = '{';
			for (i = 0; i < numfds; i++) {

				u = snprintf(tmp + used, per_fd, "%s%d/%s",
				    i > 0 ? " " : "", pfd[i].fd,
				    xlookup_bits(poll_flags, pfd[i].events));
				if (u > 0)
					used += u < per_fd ? u : per_fd;
			}
			tmp[used++] = '}';
			tmp[used++] = '\0';
		} else {
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		}
		free(pfd);
		break;
	}
	case Fd_set: {
		/*
		 * XXX: A Fd_set argument expects the /first/ syscall argument
		 * to be the number of fds in the array.  This matches the
		 * select syscall.
		 */
		fd_set *fds;
		int numfds = args[0];
		int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
		int i, tmpsize, u, used;
		const int per_fd = 20;

		if ((fds = malloc(bytes)) == NULL)
			err(1, "Cannot malloc %d bytes for fd_set array",
			    bytes);
		if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
		    != -1) {
			used = 0;
			tmpsize = 1 + numfds * per_fd + 2;
			if ((tmp = malloc(tmpsize)) == NULL)
				err(1, "Cannot alloc %d bytes for fd_set "
				    "output", tmpsize);

			tmp[used++] = '{';
			for (i = 0; i < numfds; i++) {
				if (FD_ISSET(i, fds)) {
					u = snprintf(tmp + used, per_fd, "%d ",
					    i);
					if (u > 0)
						used += u < per_fd ? u : per_fd;
				}
			}
			if (tmp[used-1] == ' ')
				used--;
			tmp[used++] = '}';
			tmp[used++] = '\0';
		} else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		free(fds);
		break;
	}
	case Signal:
		tmp = strsig2(args[sc->offset]);
		break;
	case Sigset: {
		long sig;
		sigset_t ss;
		int i, used;
		char *signame;

		sig = args[sc->offset];
		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
		    sizeof(ss)) == -1) {
			asprintf(&tmp, "0x%lx", args[sc->offset]);
			break;
		}
		tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
		used = 0;
		for (i = 1; i < sys_nsig; i++) {
			if (sigismember(&ss, i)) {
				signame = strsig(i);
				used += sprintf(tmp + used, "%s|", signame);
				free(signame);
			}
		}
		if (used)
			tmp[used-1] = 0;
		else
			strcpy(tmp, "0x0");
		break;
	}
	case Sigprocmask: {
		switch (args[sc->offset]) {
#define	S(a)	case a: tmp = strdup(#a); break;
			S(SIG_BLOCK);
			S(SIG_UNBLOCK);
			S(SIG_SETMASK);
#undef S
		}
		if (tmp == NULL)
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Fcntlflag: {
		/* XXX output depends on the value of the previous argument */
		switch (args[sc->offset-1]) {
		case F_SETFD:
			tmp = strdup(xlookup_bits(fcntlfd_arg,
			    args[sc->offset]));
			break;
		case F_SETFL:
			tmp = strdup(xlookup_bits(fcntlfl_arg,
			    args[sc->offset]));
			break;
		case F_GETFD:
		case F_GETFL:
		case F_GETOWN:
			tmp = strdup("");
			break;
		default:
			asprintf(&tmp, "0x%lx", args[sc->offset]);
			break;
		}
		break;
	}
	case Open:
		tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
		break;
	case Fcntl:
		tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
		break;
	case Mprot:
		tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
		break;
	case Mmapflags: {
		char *base, *alignstr;
		int align, flags;

		/*
		 * MAP_ALIGNED can't be handled by xlookup_bits(), so
		 * generate that string manually and prepend it to the
		 * string from xlookup_bits().  Have to be careful to
		 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is
		 * the only flag.
		 */
		flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK;
		align = args[sc->offset] & MAP_ALIGNMENT_MASK;
		if (align != 0) {
			if (align == MAP_ALIGNED_SUPER)
				alignstr = strdup("MAP_ALIGNED_SUPER");
			else
				asprintf(&alignstr, "MAP_ALIGNED(%d)",
				    align >> MAP_ALIGNMENT_SHIFT);
			if (flags == 0) {
				tmp = alignstr;
				break;
			}
		} else
			alignstr = NULL;
		base = strdup(xlookup_bits(mmap_flags, flags));
		if (alignstr == NULL) {
			tmp = base;
			break;
		}
		asprintf(&tmp, "%s|%s", alignstr, base);
		free(alignstr);
		free(base);
		break;
	}
	case Whence:
		tmp = strdup(xlookup(whence_arg, args[sc->offset]));
		break;
	case Sockdomain:
		tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
		break;
	case Socktype:
		tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
		break;
	case Shutdown:
		tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
		break;
	case Resource:
		tmp = strdup(xlookup(resource_arg, args[sc->offset]));
		break;
	case Pathconf:
		tmp = strdup(xlookup(pathconf_arg, args[sc->offset]));
		break;
	case Rforkflags:
		tmp = strdup(xlookup_bits(rfork_flags, args[sc->offset]));
		break;
	case Sockaddr: {
		struct sockaddr_storage ss;
		char addr[64];
		struct sockaddr_in *lsin;
		struct sockaddr_in6 *lsin6;
		struct sockaddr_un *sun;
		struct sockaddr *sa;
		char *p;
		u_char *q;
		int i;

		if (args[sc->offset] == 0) {
			asprintf(&tmp, "NULL");
			break;
		}

		/* yuck: get ss_len */
		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
		    sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1)
			err(1, "get_struct %p", (void *)args[sc->offset]);
		/*
		 * If ss_len is 0, then try to guess from the sockaddr type.
		 * AF_UNIX may be initialized incorrectly, so always frob
		 * it by using the "right" size.
		 */
		if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) {
			switch (ss.ss_family) {
			case AF_INET:
				ss.ss_len = sizeof(*lsin);
				break;
			case AF_UNIX:
				ss.ss_len = sizeof(*sun);
				break;
			default:
				/* hurrrr */
				break;
			}
		}
		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
		    ss.ss_len) == -1) {
			err(2, "get_struct %p", (void *)args[sc->offset]);
		}

		switch (ss.ss_family) {
		case AF_INET:
			lsin = (struct sockaddr_in *)&ss;
			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr);
			asprintf(&tmp, "{ AF_INET %s:%d }", addr,
			    htons(lsin->sin_port));
			break;
		case AF_INET6:
			lsin6 = (struct sockaddr_in6 *)&ss;
			inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
			    sizeof addr);
			asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr,
			    htons(lsin6->sin6_port));
			break;
		case AF_UNIX:
			sun = (struct sockaddr_un *)&ss;
			asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path);
			break;
		default:
			sa = (struct sockaddr *)&ss;
			asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data "
			    "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family,
			    &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data -
			    (char *)sa)), "");
			if (tmp != NULL) {
				p = tmp + i;
				for (q = (u_char *)&sa->sa_data;
				    q < (u_char *)sa + sa->sa_len; q++)
					p += sprintf(p, " %#02x,", *q);
			}
		}
		break;
	}
	case Sigaction: {
		struct sigaction sa;
		char *hand;
		const char *h;

		if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
		    != -1) {
			asprintf(&hand, "%p", sa.sa_handler);
			if (sa.sa_handler == SIG_DFL)
				h = "SIG_DFL";
			else if (sa.sa_handler == SIG_IGN)
				h = "SIG_IGN";
			else
				h = hand;

			asprintf(&tmp, "{ %s %s ss_t }", h,
			    xlookup_bits(sigaction_flags, sa.sa_flags));
			free(hand);
		} else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Kevent: {
		/*
		 * XXX XXX: the size of the array is determined by either the
		 * next syscall argument, or by the syscall returnvalue,
		 * depending on which argument number we are.  This matches the
		 * kevent syscall, but luckily that's the only syscall that uses
		 * them.
		 */
		struct kevent *ke;
		int numevents = -1;
		int bytes = 0;
		int i, tmpsize, u, used;
		const int per_ke = 100;

		if (sc->offset == 1)
			numevents = args[sc->offset+1];
		else if (sc->offset == 3 && retval != -1)
			numevents = retval;

		if (numevents >= 0)
			bytes = sizeof(struct kevent) * numevents;
		if ((ke = malloc(bytes)) == NULL)
			err(1, "Cannot malloc %d bytes for kevent array",
			    bytes);
		if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
		    ke, bytes) != -1) {
			used = 0;
			tmpsize = 1 + per_ke * numevents + 2;
			if ((tmp = malloc(tmpsize)) == NULL)
				err(1, "Cannot alloc %d bytes for kevent "
				    "output", tmpsize);

			tmp[used++] = '{';
			for (i = 0; i < numevents; i++) {
				u = snprintf(tmp + used, per_ke,
				    "%s%p,%s,%s,%d,%p,%p",
				    i > 0 ? " " : "",
				    (void *)ke[i].ident,
				    xlookup(kevent_filters, ke[i].filter),
				    xlookup_bits(kevent_flags, ke[i].flags),
				    ke[i].fflags,
				    (void *)ke[i].data,
				    (void *)ke[i].udata);
				if (u > 0)
					used += u < per_ke ? u : per_ke;
			}
			tmp[used++] = '}';
			tmp[used++] = '\0';
		} else {
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		}
		free(ke);
		break;
	}
	case Stat: {
		struct stat st;
		if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
		    != -1) {
			char mode[12];
			strmode(st.st_mode, mode);
			asprintf(&tmp,
			    "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode,
			    (intmax_t)st.st_ino, (intmax_t)st.st_size,
			    (long)st.st_blksize);
		} else {
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		}
		break;
	}
	case Rusage: {
		struct rusage ru;
		if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
		    != -1) {
			asprintf(&tmp,
			    "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }",
			    (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
			    (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
			    ru.ru_inblock, ru.ru_oublock);
		} else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case Rlimit: {
		struct rlimit rl;
		if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
		    != -1) {
			asprintf(&tmp, "{ cur=%ju,max=%ju }",
			    rl.rlim_cur, rl.rlim_max);
		} else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		break;
	}
	case ExitStatus: {
		char *signame;
		int status;
		signame = NULL;
		if (get_struct(pid, (void *)args[sc->offset], &status,
		    sizeof(status)) != -1) {
			if (WIFCONTINUED(status))
				tmp = strdup("{ CONTINUED }");
			else if (WIFEXITED(status))
				asprintf(&tmp, "{ EXITED,val=%d }",
				    WEXITSTATUS(status));
			else if (WIFSIGNALED(status))
				asprintf(&tmp, "{ SIGNALED,sig=%s%s }",
				    signame = strsig2(WTERMSIG(status)),
				    WCOREDUMP(status) ? ",cored" : "");
			else
				asprintf(&tmp, "{ STOPPED,sig=%s }",
				    signame = strsig2(WTERMSIG(status)));
		} else
			asprintf(&tmp, "0x%lx", args[sc->offset]);
		free(signame);
		break;
	}
	case Waitoptions:
		tmp = strdup(xlookup_bits(wait_options, args[sc->offset]));
		break;
	case Idtype:
		tmp = strdup(xlookup(idtype_arg, args[sc->offset]));
		break;
	case Procctl:
		tmp = strdup(xlookup(procctl_arg, args[sc->offset]));
		break;
	default:
		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
	}
Ejemplo n.º 16
0
int
videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
    struct video_softc *sc;
    int unit, error;

    unit = VIDEOUNIT(dev);
    if (unit >= video_cd.cd_ndevs ||
            (sc = video_cd.cd_devs[unit]) == NULL || sc->hw_if == NULL)
        return (ENXIO);

    DPRINTF(("video_ioctl(%d, '%c', %d)\n",
             IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));

    error = EOPNOTSUPP;
    switch (cmd) {
    case VIDIOC_QUERYCAP:
        if (sc->hw_if->querycap)
            error = (sc->hw_if->querycap)(sc->hw_hdl,
                                          (struct v4l2_capability *)data);
        break;
    case VIDIOC_ENUM_FMT:
        if (sc->hw_if->enum_fmt)
            error = (sc->hw_if->enum_fmt)(sc->hw_hdl,
                                          (struct v4l2_fmtdesc *)data);
        break;
    case VIDIOC_ENUM_FRAMESIZES:
        if (sc->hw_if->enum_fsizes)
            error = (sc->hw_if->enum_fsizes)(sc->hw_hdl,
                                             (struct v4l2_frmsizeenum *)data);
        break;
    case VIDIOC_ENUM_FRAMEINTERVALS:
        if (sc->hw_if->enum_fivals)
            error = (sc->hw_if->enum_fivals)(sc->hw_hdl,
                                             (struct v4l2_frmivalenum *)data);
        break;
    case VIDIOC_S_FMT:
        if (!(flags & FWRITE))
            return (EACCES);
        if (sc->hw_if->s_fmt)
            error = (sc->hw_if->s_fmt)(sc->hw_hdl,
                                       (struct v4l2_format *)data);
        break;
    case VIDIOC_G_FMT:
        if (sc->hw_if->g_fmt)
            error = (sc->hw_if->g_fmt)(sc->hw_hdl,
                                       (struct v4l2_format *)data);
        break;
    case VIDIOC_S_PARM:
        if (sc->hw_if->s_parm)
            error = (sc->hw_if->s_parm)(sc->hw_hdl,
                                        (struct v4l2_streamparm *)data);
        break;
    case VIDIOC_G_PARM:
        if (sc->hw_if->g_parm)
            error = (sc->hw_if->g_parm)(sc->hw_hdl,
                                        (struct v4l2_streamparm *)data);
        break;
    case VIDIOC_ENUMINPUT:
        if (sc->hw_if->enum_input)
            error = (sc->hw_if->enum_input)(sc->hw_hdl,
                                            (struct v4l2_input *)data);
        break;
    case VIDIOC_S_INPUT:
        if (sc->hw_if->s_input)
            error = (sc->hw_if->s_input)(sc->hw_hdl,
                                         (int)*data);
        break;
    case VIDIOC_REQBUFS:
        if (sc->hw_if->reqbufs)
            error = (sc->hw_if->reqbufs)(sc->hw_hdl,
                                         (struct v4l2_requestbuffers *)data);
        break;
    case VIDIOC_QUERYBUF:
        if (sc->hw_if->querybuf)
            error = (sc->hw_if->querybuf)(sc->hw_hdl,
                                          (struct v4l2_buffer *)data);
        break;
    case VIDIOC_QBUF:
        if (sc->hw_if->qbuf)
            error = (sc->hw_if->qbuf)(sc->hw_hdl,
                                      (struct v4l2_buffer *)data);
        break;
    case VIDIOC_DQBUF:
        if (!sc->hw_if->dqbuf)
            break;
        /* should have called mmap() before now */
        if (sc->sc_vidmode != VIDMODE_MMAP) {
            error = EINVAL;
            break;
        }
        error = (sc->hw_if->dqbuf)(sc->hw_hdl,
                                   (struct v4l2_buffer *)data);
        sc->sc_frames_ready--;
        break;
    case VIDIOC_STREAMON:
        if (sc->hw_if->streamon)
            error = (sc->hw_if->streamon)(sc->hw_hdl,
                                          (int)*data);
        break;
    case VIDIOC_STREAMOFF:
        if (sc->hw_if->streamoff)
            error = (sc->hw_if->streamoff)(sc->hw_hdl,
                                           (int)*data);
        break;
    case VIDIOC_TRY_FMT:
        if (sc->hw_if->try_fmt)
            error = (sc->hw_if->try_fmt)(sc->hw_hdl,
                                         (struct v4l2_format *)data);
        break;
    case VIDIOC_QUERYCTRL:
        if (sc->hw_if->queryctrl)
            error = (sc->hw_if->queryctrl)(sc->hw_hdl,
                                           (struct v4l2_queryctrl *)data);
        break;
    case VIDIOC_G_CTRL:
        if (sc->hw_if->g_ctrl)
            error = (sc->hw_if->g_ctrl)(sc->hw_hdl,
                                        (struct v4l2_control *)data);
        break;
    case VIDIOC_S_CTRL:
        if (sc->hw_if->s_ctrl)
            error = (sc->hw_if->s_ctrl)(sc->hw_hdl,
                                        (struct v4l2_control *)data);
        break;
    default:
        error = (ENOTTY);
    }

    return (error);
}
Ejemplo n.º 17
0
Archivo: ds.c Proyecto: mmanley/Antares
static status_t 
ds_ioctl(void *cookie, uint32 cmd, void *arg, size_t len)
{
	/*socket_info_t *s = (socket_info_t *) cookie;
    u_int size = IOCPARM_LEN(cmd);
    status_t ret, err;
    ds_ioctl_arg_t buf;
    
    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
    
	err = ret = 0;
    
    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
    
    switch (cmd) {
    case DS_ADJUST_RESOURCE_INFO:
	ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
	break;
    case DS_GET_CARD_SERVICES_INFO:
	ret = CardServices(GetCardServicesInfo, &buf.servinfo);
	break;
    case DS_GET_CONFIGURATION_INFO:
	ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
	break;
    case DS_GET_FIRST_TUPLE:
	ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
	break;
    case DS_GET_NEXT_TUPLE:
	ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
	break;
    case DS_GET_TUPLE_DATA:
	buf.tuple.TupleData = buf.tuple_parse.data;
	buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
	ret = CardServices(GetTupleData, s->handle, &buf.tuple);
	break;
    case DS_PARSE_TUPLE:
	buf.tuple.TupleData = buf.tuple_parse.data;
	ret = CardServices(ParseTuple, s->handle, &buf.tuple,
			   &buf.tuple_parse.parse);
	break;
    case DS_RESET_CARD:
	ret = CardServices(ResetCard, s->handle, NULL);
	break;
    case DS_GET_STATUS:
	ret = CardServices(GetStatus, s->handle, &buf.status);
	break;
    case DS_VALIDATE_CIS:
	ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
	break;
    case DS_SUSPEND_CARD:
	ret = CardServices(SuspendCard, s->handle, NULL);
	break;
    case DS_RESUME_CARD:
	ret = CardServices(ResumeCard, s->handle, NULL);
	break;
    case DS_EJECT_CARD:
	ret = CardServices(EjectCard, s->handle, NULL);
	break;
    case DS_INSERT_CARD:
	ret = CardServices(InsertCard, s->handle, NULL);
	break;
    case DS_ACCESS_CONFIGURATION_REGISTER:
	if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
	    return -EPERM;
	ret = CardServices(AccessConfigurationRegister, s->handle,
			   &buf.conf_reg);
	break;
    case DS_GET_FIRST_REGION:
        ret = CardServices(GetFirstRegion, s->handle, &buf.region);
	break;
    case DS_GET_NEXT_REGION:
	ret = CardServices(GetNextRegion, s->handle, &buf.region);
	break;
    case DS_GET_FIRST_WINDOW:
	buf.win_info.handle = (window_handle_t)s->handle;
	ret = CardServices(GetFirstWindow, &buf.win_info.handle,
			   &buf.win_info.window);
	break;
    case DS_GET_NEXT_WINDOW:
	ret = CardServices(GetNextWindow, &buf.win_info.handle,
			   &buf.win_info.window);
	break;
    case DS_GET_MEM_PAGE:
	ret = CardServices(GetMemPage, buf.win_info.handle,
			   &buf.win_info.map);
	break;
    case DS_REPLACE_CIS:
	ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
	break;
	*/
	client_handle_t h = (client_handle_t) cookie;
    u_int size = IOCPARM_LEN(cmd);
    status_t ret, err;
    ds_ioctl_arg_t buf;
    
    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
    
	err = ret = 0;
	
    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
    
    switch (cmd) {
    case DS_ADJUST_RESOURCE_INFO:
	ret = CardServices(AdjustResourceInfo, h, &buf.adjust);
	break;
    case DS_GET_CARD_SERVICES_INFO:
	ret = CardServices(GetCardServicesInfo, &buf.servinfo);
	break;
    case DS_GET_CONFIGURATION_INFO:
	ret = CardServices(GetConfigurationInfo, h, &buf.config);
	break;
    case DS_GET_FIRST_TUPLE:
	ret = CardServices(GetFirstTuple, h, &buf.tuple);
	break;
    case DS_GET_NEXT_TUPLE:
	ret = CardServices(GetNextTuple, h, &buf.tuple);
	break;
    case DS_GET_TUPLE_DATA:
	buf.tuple.TupleData = buf.tuple_parse.data;
	buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
	ret = CardServices(GetTupleData, h, &buf.tuple);
	break;
    case DS_PARSE_TUPLE:
	buf.tuple.TupleData = buf.tuple_parse.data;
	ret = CardServices(ParseTuple, h, &buf.tuple,
			   &buf.tuple_parse.parse);
	break;
    case DS_RESET_CARD:
	ret = CardServices(ResetCard, h, NULL);
	break;
    case DS_GET_STATUS:
	ret = CardServices(GetStatus, h, &buf.status);
	break;
    case DS_VALIDATE_CIS:
	ret = CardServices(ValidateCIS, h, &buf.cisinfo);
	break;
    case DS_SUSPEND_CARD:
	ret = CardServices(SuspendCard, h, NULL);
	break;
    case DS_RESUME_CARD:
	ret = CardServices(ResumeCard, h, NULL);
	break;
    case DS_EJECT_CARD:
	ret = CardServices(EjectCard, h, NULL);
	break;
    case DS_INSERT_CARD:
	ret = CardServices(InsertCard, h, NULL);
	break;
/*    case DS_ACCESS_CONFIGURATION_REGISTER:
	if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
	    return -EPERM;
	ret = CardServices(AccessConfigurationRegister, h,
			   &buf.conf_reg);
	break;
    case DS_GET_FIRST_REGION:
        ret = CardServices(GetFirstRegion, h, &buf.region);
	break;
    case DS_GET_NEXT_REGION:
	ret = CardServices(GetNextRegion, h, &buf.region);
	break;
    case DS_GET_FIRST_WINDOW:
	buf.win_info.handle = (window_handle_t)h;
	ret = CardServices(GetFirstWindow, &buf.win_info.handle,
			   &buf.win_info.window);
	break;
    case DS_GET_NEXT_WINDOW:
	ret = CardServices(GetNextWindow, &buf.win_info.handle,
			   &buf.win_info.window);
	break;
    case DS_GET_MEM_PAGE:
	ret = CardServices(GetMemPage, buf.win_info.handle,
			   &buf.win_info.map);
	break;*/
    case DS_REPLACE_CIS:
	ret = CardServices(ReplaceCIS, h, &buf.cisdump);
	break;
	
/*    case DS_BIND_REQUEST:
	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
	err = bind_request(i, &buf.bind_info);
	break;
    case DS_GET_DEVICE_INFO:
	err = get_device_info(i, &buf.bind_info, 1);
	break;
    case DS_GET_NEXT_DEVICE:
	err = get_device_info(i, &buf.bind_info, 0);
	break;
    case DS_UNBIND_REQUEST:
	err = unbind_request(i, &buf.bind_info);
	break;
    case DS_BIND_MTD:
	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
	err = bind_mtd(i, &buf.mtd_info);
	break;*/
    default:
    err = -EINVAL;
    }
    
    if ((err == 0) && (ret != CS_SUCCESS)) {
	switch (ret) {
	case CS_BAD_SOCKET: case CS_NO_CARD:
	    err = ENODEV; break;
	case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
	case CS_BAD_TUPLE:
		err = EINVAL; break;
	case CS_IN_USE:
	    err = EBUSY; break;
	case CS_OUT_OF_RESOURCE:
	    err = ENOSPC; break;
	case CS_NO_MORE_ITEMS:
	    err = ENODATA; break;
	case CS_UNSUPPORTED_FUNCTION:
	    err = ENOSYS; break;
	default:
	    err = EIO; break;
	}
    }
    
    if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
     
    return err;
} /* ds_ioctl */
Ejemplo n.º 18
0
/**
 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
 *
 * @returns Solaris errno.
 *
 * @param   pSession    The session.
 * @param   iCmd        The IOCtl command.
 * @param   Mode        Information bitfield (for specifying ownership of data)
 * @param   iArg        User space address of the request buffer.
 */
static int vgdrvSolarisIOCtlSlow(PVBOXGUESTSESSION pSession, int iCmd, int Mode, intptr_t iArg)
{
    int         rc;
    uint32_t    cbBuf = 0;
    union
    {
        VBGLREQHDR  Hdr;
        uint8_t     abBuf[64];
    }           StackBuf;
    PVBGLREQHDR  pHdr;


    /*
     * Read the header.
     */
    if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
    {
        LogRel(("vgdrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
        return EINVAL;
    }
    rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("vgdrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
        return EFAULT;
    }
    if (RT_UNLIKELY(StackBuf.Hdr.uVersion != VBGLREQHDR_VERSION))
    {
        LogRel(("vgdrvSolarisIOCtlSlow: bad header version %#x; iCmd=%#x\n", StackBuf.Hdr.uVersion, iCmd));
        return EINVAL;
    }
    cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
    if (RT_UNLIKELY(   StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
                    || (StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr) && StackBuf.Hdr.cbOut != 0)
                    || cbBuf > _1M*16))
    {
        LogRel(("vgdrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
        return EINVAL;
    }

    /*
     * Buffer the request.
     *
     * Note! Common code revalidates the header sizes and version. So it's
     *       fine to read it once more.
     */
    if (cbBuf <= sizeof(StackBuf))
        pHdr = &StackBuf.Hdr;
    else
    {
        pHdr = RTMemTmpAlloc(cbBuf);
        if (RT_UNLIKELY(!pHdr))
        {
            LogRel(("vgdrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
            return ENOMEM;
        }
    }
    rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("vgdrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
        if (pHdr != &StackBuf.Hdr)
            RTMemFree(pHdr);
        return EFAULT;
    }

    /*
     * Process the IOCtl.
     */
    rc = VGDrvCommonIoCtl(iCmd, &g_DevExt, pSession, pHdr, cbBuf);

    /*
     * Copy ioctl data and output buffer back to user space.
     */
    if (RT_SUCCESS(rc))
    {
        uint32_t cbOut = pHdr->cbOut;
        if (RT_UNLIKELY(cbOut > cbBuf))
        {
            LogRel(("vgdrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
            cbOut = cbBuf;
        }
        rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
        if (RT_UNLIKELY(rc != 0))
        {
            /* this is really bad */
            LogRel(("vgdrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
            rc = EFAULT;
        }
    }
    else
        rc = EINVAL;

    if (pHdr != &StackBuf.Hdr)
        RTMemTmpFree(pHdr);
    return rc;
}
Ejemplo n.º 19
0
int ioctl(int fd, int cmd, ...) {
    va_list vl;
	void *data;
	struct termios	ltermios;
#ifdef NOT_USED
	struct termios	*ptermios;
	struct termio	ltermio;
#endif
	struct termio	*ptermio;
	int				match, tempint;

	//Pull out the command and the data
	va_start(vl, cmd);
	data = va_arg(vl, void *);
	va_end(vl);

	/* 
     These calls have significantly different inputs or outputs
     that we have to manipulate (or re-direct entirely)
	*/
	switch ((unsigned)cmd) {	
	/**** These calls map to fcntl's ****/

	//Set/Clear FD_CLOEXEC state
	case FIOCLEX:	
		return(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC));
	case FIONCLEX:
		return(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC));

	//These are undoced uses for fcntl
	case SIOCGPGRP:
	case FIOGETOWN:
		if ( (tempint = fcntl (fd, F_GETOWN)) != -1)
			*(int *)data = tempint;
		return(tempint);
	case SIOCSPGRP:
	case FIOSETOWN:
		return(fcntl(fd, F_SETOWN, *(int *)data));

	//Set the non-blocking state for reads on and off
	case FIONBIO:
		if (*(int *)data)
			return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK));
		else
			return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK));

	//Set the async state on and off
	case FIOASYNC:
		if (*(int *)data)
			return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC));
		else
			return(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC));

	//Set/Clear exclusive mode
	case TIOCEXCL: {
		struct flock lflock;
		memset(&lflock, 0, sizeof(lflock));
		lflock.l_type = F_WRLCK;			//Fails if file opened read only?
		lflock.l_whence = SEEK_SET;
		lflock.l_start = 0;
		lflock.l_len = 0;
		lflock.l_pid = getpid();
		return(__fcntl2ioctl(fcntl(fd, F_SETLK, &lflock)));
	}
	case TIOCNXCL: {
		struct flock lflock;
		memset(&lflock, 0, sizeof(lflock));
		lflock.l_type = F_UNLCK;
		lflock.l_whence = SEEK_SET;
		lflock.l_start = 0;
		lflock.l_len = 0;
		lflock.l_pid = getpid();
		(void)fcntl(fd, F_GETLK, &lflock);
		return(__fcntl2ioctl(fcntl(fd, F_SETLK, &lflock)));
	}

	//Make the terminal the controlling terminal for the process
	case TIOCSCTTY:
		return(tcsetsid(fd, getpid()));
	//Dis-associate this terminal as the controlling terminal
	case TIOCNOTTY:
		return(tcsetsid(-1, getpid()));

	/**** These calls translate from one type to another using tc[s|g]etattr ****/

	//Terminal properties w/ termio
	case TCGETA: {
		ptermio = (struct termio *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		termios2termio(&ltermios, ptermio);
		return(EOK);
	}
	case TCSETA: {
		ptermio = (struct termio *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);		
		termio2termios(ptermio, &ltermios);
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}
	case TCSETAW: {
		ptermio = (struct termio *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);		
		termio2termios(ptermio, &ltermios);
		return(tcsetattr(fd, TCSADRAIN, &ltermios));
	}
	case TCSETAF: {
		ptermio = (struct termio *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);		
		termio2termios(ptermio, &ltermios);
		return(tcsetattr(fd, TCSAFLUSH, &ltermios));
	}

	//Set terminal state in an sgttyb structure (incomplete)
	case TIOCGETP: {
		struct sgttyb *psgttyb = (struct sgttyb *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		termios2sgttyb(&ltermios, psgttyb);
		return(EOK);
	}	
	case TIOCSETP: {
		struct sgttyb *psgttyb = (struct sgttyb *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		sgttyb2termios(psgttyb, &ltermios);
		return(tcsetattr(fd, TCSAFLUSH, &ltermios));
	}
	case TIOCSETN: {
		struct sgttyb *psgttyb = (struct sgttyb *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		sgttyb2termios(psgttyb, &ltermios);
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}

	//Terminal state in tchars structure
	case TIOCGETC: {
		struct tchars *ptchars = (struct tchars *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		termios2tchars(&ltermios, ptchars);
		return(EOK);
	}
	case TIOCSETC: {
		struct tchars *ptchars = (struct tchars *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		tchars2termios(ptchars, &ltermios);
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}
	
	//Terminal state in an ltchars structure
	case TIOCGLTC: {
		struct ltchars *pltchars = (struct ltchars *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		termios2ltchars(&ltermios, pltchars);
		return(EOK);
	}
	case TIOCSLTC: {
		struct ltchars *pltchars = (struct ltchars *)data;
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		ltchars2termios(pltchars, &ltermios);
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}

	//Set/Get the local flags structure
	case TIOCLGET: {
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		*((int *)data) = (int)ltermios.c_lflag;
		return(EOK);
	}
	case TIOCLSET: {
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		ltermios.c_lflag &= ~0xffff;
		ltermios.c_lflag |= *((int*)data);
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}

	//Clear the break flag (implement TIOCSBRK?)
	case TIOCCBRK: {
		if (tcgetattr(fd, &ltermios) == -1)
			return(-1);
		ltermios.c_iflag &= ~(BRKINT);
		ltermios.c_iflag |= IGNBRK;
		return(tcsetattr(fd, TCSANOW, &ltermios));
	}

	//Set the HUPCL flag 
	case TIOCHPCL: {
		if (tcgetattr(fd, &ltermios) != -1) {
			ltermios.c_cflag |= HUPCL;
			return(tcsetattr(fd, TCSANOW, &ltermios));
		}
	}

	/**** These calls map to devctl's, but need serious data munging ****/

	//Inject a character into the stream
	case TIOCSTI: {	
		return(tcinject(fd, (char*)data, sizeof(char)));
	}

	//Send a break for a period of time
	case TCSBRK: {
		int *duration = (int *) data;				//Duration is measured in ms 
		return(tcsendbreak(fd, *duration));
		//tempint = (((*duration) ? *duration : 300) << 16) | _SERCTL_BRK_CHG | _SERCTL_BRK;
		//return(devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), &ret));
	}

	/**** Modem control operations (via devctl) ****/
	//Clear the state of the modem by ~AND'ing in the int argument
	case TIOCMBIC: {
		int tmpmodem;
		if (_devctl(fd, DCMD_CHR_LINESTATUS, &tmpmodem, sizeof(tmpmodem), _DEVCTL_FLAG_NOTTY) == -1) 
			return(-1);
		tmpmodem &= ~(*((int*)data));
		tempint = 0;
		modem2serctl(&tmpmodem, &tempint);
		return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); 
	}
	//Set the state of the modem by OR'ing in the int argument
	case TIOCMBIS: {
		int tmpmodem;
		if (_devctl(fd, DCMD_CHR_LINESTATUS, &tmpmodem, sizeof(tmpmodem), _DEVCTL_FLAG_NOTTY) == -1) 
			return(-1);
		tmpmodem |= *((int*)data);		
		tempint = 0;
		modem2serctl(&tmpmodem, &tempint);
		return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); 
	}

	//Set the state of the modem lines
	case TIOCMSET: {
		tempint = 0;
		modem2serctl((int*)data, &tempint);
		return(_devctl(fd, DCMD_CHR_SERCTL, &tempint, sizeof(tempint), _DEVCTL_FLAG_NOTTY)); 
	}

	//Set/Clear DTR lines
	case TIOCCDTR: {
		int status; 
		if (_devctl(fd, DCMD_CHR_LINESTATUS, &status, sizeof(status), _DEVCTL_FLAG_NOTTY) == -1)
			return(-1);
		if (status & _LINESTATUS_SER_DTR) {
			status =  _SERCTL_DTR_CHG;
			return(_devctl(fd, DCMD_CHR_SERCTL, &status, sizeof(status), _DEVCTL_FLAG_NOTTY));
		}
		return(EOK);
	}
	case TIOCSDTR: {
		int status; 
		if (_devctl(fd, DCMD_CHR_LINESTATUS, &status, sizeof(status), _DEVCTL_FLAG_NOTTY) == -1)
			return(-1);
		if (!(status & _LINESTATUS_SER_DTR)) {
			status =  _SERCTL_DTR | _SERCTL_DTR_CHG;
			return(_devctl(fd, DCMD_CHR_SERCTL, &status, sizeof(status), _DEVCTL_FLAG_NOTTY));
		}
		return(EOK);
	}
	default:
		break;
	}

/*
 * The following block can go away when 6.4 is released
 * and <sys/sockio.h> from the networking project is
 * generally available.
 */
#ifndef NOSIOCGIFCONF
/* Define these as in the latest <sys/sockio.h> */
#define NOSIOCGIFCONF _IOWR('i', 36, struct ifconf)
#undef SIOCGIFCONF
#define SIOCGIFCONF   _IOWR('i', 38, struct ifconf)
#endif
	/* 
	 Generic handling for all but SIOCGIFCONF networking IOCTL's
	*/
	if ((unsigned)cmd == SIOCGIFCONF || (unsigned)cmd == NOSIOCGIFCONF) {
		io_devctl_t		msg;
		iov_t			wiov[2], riov[3];
		struct ifconf *ifconfp = (struct ifconf *)data;

		msg.i.type = _IO_DEVCTL;
		msg.i.combine_len = sizeof(msg.i);
		msg.i.dcmd = cmd;
		msg.i.zero = 0;
		msg.i.nbytes = ifconfp->ifc_len;

		SETIOV (wiov + 0, &msg, sizeof (msg.i));
		SETIOV (wiov + 1, data, IOCPARM_LEN((unsigned)cmd));
		SETIOV (riov + 0, &msg, sizeof (msg.o));
		SETIOV (riov + 1, ifconfp, sizeof (ifconfp->ifc_len));
		SETIOV (riov + 2, ifconfp->ifc_buf, ifconfp->ifc_len);
		return MsgSendv(fd, wiov, 2, riov, 3);
	}

	/* 
	 These calls require their command types to be translated
	*/
	switch ((unsigned)cmd) {
	case TCGETS:								//Not on NetBSD 
		SETNEWNUM(cmd, TIOCGETA);  match = 1;
		break;

	case TCSETS:								//Not on NetBSD
		SETNEWNUM(cmd, TIOCSETA);  match = 1; 
		break;

	case TCSETSW:								//Not on NetBSD
		SETNEWNUM(cmd, TIOCSETAW);  match = 1;
		break;

	case TCSETSF:								//Not on NetBSD
		SETNEWNUM(cmd, TIOCSETAF);  match = 1;
		break;

	case TIOCSETPGRP:							//Not on Sun
		SETNEWNUM(cmd, TIOCSPGRP);  match = 1;
		break;

	case TIOCGETPGRP:							//Not on Sun
		SETNEWNUM(cmd, TIOCGPGRP);  match = 1; 
		break;

	case TIOCSTOP: 
	case TIOCSTART:							
		//These functions pass in void but we need to pass an int so ...
		data = &tempint;
		tempint = (cmd == TIOCSTOP) ? TCOOFF : TIOCSTART;
		cmd = _IOW(_DCMD_CHR,TCXONC,int);		//Create new command  
	case TCXONC:								//Not on NetBSD
		//Assume incoming data already looks like:
		//data = 0= suspend output = TCOOFF, 1= restart output = TCOON
		//       2= suspend input = TCIOFF,  3= restart input = TCION
		SETNEWNUM(cmd, TCXONC);  match = 1;
		break;

	case TIOCFLUSH: 
		//Need to re-map 0 -> 2, FREAD -> 0, FWRITE -> 1
		switch (*((int*)data)) {
			case 0:      *((int*)data) = TCIOFLUSH; break;
			case FREAD:  *((int*)data) = TCIFLUSH; break;
			case FWRITE: *((int*)data) = TCOFLUSH; break;
			default: break;
		}
		/* Fall Through */
	case TCFLSH:								//Not on NetBSD 
		//Assume input data looks like:
		//data = 0 = flush in, 1 = flush output, 2 = flush both
		SETNEWNUM(cmd, TIOCFLUSH); match = 1;
		break;

	default:
		break;
	}

	//If you got this far then out you go as a generic devctl
	return(_devctl(fd, cmd, data, IOCPARM_LEN((unsigned)cmd), _DEVCTL_FLAG_NOTTY));
	/*
	 Returns different things for different commands:
	 - GETPRGRP returns pid_t 
	 - FIOREAD returns number of chars in input queue
	 - TIOCOUTQ returns number of chars in output queue
	 - 0 for all other cases
	*/
}
Ejemplo n.º 20
0
/**
 * Driver IOCtl entry.
 * @param cookie        The session.
 * @param op            The operation to perform.
 * @param data          The data associated with the operation.
 * @param len           Size of the data in bytes.
 *
 * @return Haiku status code.
 */
static status_t vgdrvHaikuIOCtl(void *cookie, uint32 op, void *data, size_t len)
{
    PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)cookie;
    int rc;
    Log(("vgdrvHaikuIOCtl: cookie=%p op=0x%08x data=%p len=%lu)\n", cookie, op, data, len));

    /*
     * Validate the input.
     */
    if (RT_UNLIKELY(!VALID_PTR(pSession)))
        return EINVAL;

    /*
     * Validate the request wrapper.
     */
#if 0
    if (IOCPARM_LEN(ulCmd) != sizeof(VBGLBIGREQ))
    {
        Log((DRIVER_NAME ": vgdrvHaikuIOCtl: bad request %lu size=%lu expected=%d\n", ulCmd, IOCPARM_LEN(ulCmd),
                                                                                        sizeof(VBGLBIGREQ)));
        return ENOTTY;
    }
#endif

    if (RT_UNLIKELY(len > _1M * 16))
    {
        dprintf(DRIVER_NAME ": vgdrvHaikuIOCtl: bad size %#x; pArg=%p Cmd=%lu.\n", (unsigned)len, data, op);
        return EINVAL;
    }

    /*
     * Read the request.
     */
    void *pvBuf = NULL;
    if (RT_LIKELY(len > 0))
    {
        pvBuf = RTMemTmpAlloc(len);
        if (RT_UNLIKELY(!pvBuf))
        {
            LogRel((DRIVER_NAME ":vgdrvHaikuIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", len));
            return ENOMEM;
        }

        /** @todo r=ramshankar: replace with RTR0MemUserCopyFrom() */
        rc = user_memcpy(pvBuf, data, len);
        if (RT_UNLIKELY(rc < 0))
        {
            RTMemTmpFree(pvBuf);
            LogRel((DRIVER_NAME ":vgdrvHaikuIOCtl: user_memcpy failed; pvBuf=%p data=%p op=%d. rc=%d\n", pvBuf, data, op, rc));
            return EFAULT;
        }
        if (RT_UNLIKELY(!VALID_PTR(pvBuf)))
        {
            RTMemTmpFree(pvBuf);
            LogRel((DRIVER_NAME ":vgdrvHaikuIOCtl: pvBuf invalid pointer %p\n", pvBuf));
            return EINVAL;
        }
    }
    Log(("vgdrvHaikuIOCtl: pSession=%p pid=%d.\n", pSession,(int)RTProcSelf()));

    /*
     * Process the IOCtl.
     */
    size_t cbDataReturned;
    rc = VGDrvCommonIoCtl(op, &g_DevExt, pSession, pvBuf, len, &cbDataReturned);
    if (RT_SUCCESS(rc))
    {
        rc = 0;
        if (RT_UNLIKELY(cbDataReturned > len))
        {
            Log(("vgdrvHaikuIOCtl: too much output data %d expected %d\n", cbDataReturned, len));
            cbDataReturned = len;
        }
        if (cbDataReturned > 0)
        {
            rc = user_memcpy(data, pvBuf, cbDataReturned);
            if (RT_UNLIKELY(rc < 0))
            {
                Log(("vgdrvHaikuIOCtl: user_memcpy failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, data, op, rc));
                rc = EFAULT;
            }
        }
    }
    else
    {
        Log(("vgdrvHaikuIOCtl: VGDrvCommonIoCtl failed. rc=%d\n", rc));
        rc = EFAULT;
    }
    RTMemTmpFree(pvBuf);
    return rc;
}
Ejemplo n.º 21
0
/**
 * Deal with the 'slow' I/O control requests.
 *
 * @returns 0 on success, appropriate errno on failure.
 * @param   pSession    The session.
 * @param   ulCmd       The command.
 * @param   pvData      The request data.
 * @param   pTd         The calling thread.
 */
static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
{
    PSUPREQHDR  pHdr;
    uint32_t    cbReq = IOCPARM_LEN(ulCmd);
    void       *pvUser = NULL;

    /*
     * Buffered request?
     */
    if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
    {
        pHdr = (PSUPREQHDR)pvData;
        if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY(    RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
                        ||  pHdr->cbIn < sizeof(*pHdr)
                        ||  pHdr->cbOut < sizeof(*pHdr)))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
            return EINVAL;
        }
    }
    /*
     * Big unbuffered request?
     */
    else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
    {
        /*
         * Read the header, validate it and figure out how much that needs to be buffered.
         */
        SUPREQHDR Hdr;
        pvUser = *(void **)pvData;
        int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
        if (RT_UNLIKELY(rc))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
            return rc;
        }
        if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
            return EINVAL;
        }
        cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
        if (RT_UNLIKELY(    Hdr.cbIn < sizeof(Hdr)
                        ||  Hdr.cbOut < sizeof(Hdr)
                        ||  cbReq > _1M*16))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
            return EINVAL;
        }

        /*
         * Allocate buffer and copy in the data.
         */
        pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
        if (RT_UNLIKELY(!pHdr))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
            return ENOMEM;
        }
        rc = copyin(pvUser, pHdr, Hdr.cbIn);
        if (RT_UNLIKELY(rc))
        {
            OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
                        pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
            RTMemTmpFree(pHdr);
            return rc;
        }
    }
    else
    {
        Log(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
        return EINVAL;
    }

    /*
     * Process the IOCtl.
     */
    int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr);
    if (RT_LIKELY(!rc))
    {
        /*
         * If unbuffered, copy back the result before returning.
         */
        if (pvUser)
        {
            uint32_t cbOut = pHdr->cbOut;
            if (cbOut > cbReq)
            {
                OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
                cbOut = cbReq;
            }
            rc = copyout(pHdr, pvUser, cbOut);
            if (RT_UNLIKELY(rc))
                OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));

            Log(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));

            /* cleanup */
            RTMemTmpFree(pHdr);
        }
    }
    else
    {
        /*
         * The request failed, just clean up.
         */
        if (pvUser)
            RTMemTmpFree(pHdr);

        Log(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
        rc = EINVAL;
    }

    return rc;
}
static int
acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
{
    union acpi_battery_ioctl_arg *ioctl_arg;
    int error, unit;
    device_t dev;

    /* For commands that use the ioctl_arg struct, validate it first. */
    error = ENXIO;
    unit = 0;
    dev = NULL;
    ioctl_arg = NULL;
    if (IOCPARM_LEN(cmd) == sizeof(*ioctl_arg)) {
	ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
	unit = ioctl_arg->unit;
	if (unit != ACPI_BATTERY_ALL_UNITS)
	    dev = acpi_battery_find_dev(unit);
    }

    /*
     * No security check required: information retrieval only.  If
     * new functions are added here, a check might be required.
     */
    switch (cmd) {
    case ACPIIO_BATT_GET_UNITS:
	*(int *)addr = acpi_battery_get_units();
	error = 0;
	break;
    case ACPIIO_BATT_GET_BATTINFO:
	if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) {
	    bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo));
	    error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo);
	}
	break;
    case ACPIIO_BATT_GET_BIF:
	if (dev != NULL) {
	    bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif));
	    error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif);

	    /*
	     * Remove invalid characters.  Perhaps this should be done
	     * within a convenience function so all callers get the
	     * benefit.
	     */
	    acpi_battery_clean_str(ioctl_arg->bif.model,
		sizeof(ioctl_arg->bif.model));
	    acpi_battery_clean_str(ioctl_arg->bif.serial,
		sizeof(ioctl_arg->bif.serial));
	    acpi_battery_clean_str(ioctl_arg->bif.type,
		sizeof(ioctl_arg->bif.type));
	    acpi_battery_clean_str(ioctl_arg->bif.oeminfo,
		sizeof(ioctl_arg->bif.oeminfo));
	}
	break;
    case ACPIIO_BATT_GET_BST:
	if (dev != NULL) {
	    bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst));
	    error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst);
	}
	break;
    default:
	error = EINVAL;
    }

    return (error);
}
Ejemplo n.º 23
0
/**
 * Deal with the 'slow' I/O control requests.
 *
 * @returns 0 on success, appropriate errno on failure.
 * @param   pSession    The session.
 * @param   ulCmd       The command.
 * @param   pvData      The request data.
 * @param   pTd         The calling thread.
 */
static int vgdrvFreeBSDIOCtlSlow(PVBOXGUESTSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
{
    PVBGLREQHDR pHdr;
    uint32_t    cbReq = IOCPARM_LEN(ulCmd);
    void       *pvUser = NULL;

    /*
     * Buffered request?
     */
    if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
    {
        pHdr = (PVBGLREQHDR)pvData;
        if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY(pHdr->uVersion != VBGLREQHDR_VERSION))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: bad uVersion=%#x; ulCmd=%#lx\n", pHdr->uVersion, ulCmd));
            return EINVAL;
        }
        if (RT_UNLIKELY(   RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
                        || pHdr->cbIn < sizeof(*pHdr)
                        || (pHdr->cbOut < sizeof(*pHdr) && pHdr->cbOut != 0)))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
            return EINVAL;
        }
    }
    /*
     * Big unbuffered request?
     */
    else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
    {
        /*
         * Read the header, validate it and figure out how much that needs to be buffered.
         */
        VBGLREQHDR Hdr;
        pvUser = *(void **)pvData;
        int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
        if (RT_UNLIKELY(rc))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
            return rc;
        }
        if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: bad uVersion=%#x; ulCmd=%#lx\n", Hdr.uVersion, ulCmd));
            return EINVAL;
        }
        cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
        if (RT_UNLIKELY(   Hdr.cbIn < sizeof(Hdr)
                        || (Hdr.cbOut < sizeof(Hdr) && Hdr.cbOut != 0)
                        || cbReq > _1M*16))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
            return EINVAL;
        }

        /*
         * Allocate buffer and copy in the data.
         */
        pHdr = (PVBGLREQHDR)RTMemTmpAlloc(cbReq);
        if (RT_UNLIKELY(!pHdr))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
            return ENOMEM;
        }
        rc = copyin(pvUser, pHdr, Hdr.cbIn);
        if (RT_UNLIKELY(rc))
        {
            LogRel(("vgdrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
                        pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
            RTMemTmpFree(pHdr);
            return rc;
        }
        if (Hdr.cbIn < cbReq)
            RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbReq - Hdr.cbIn);
    }
    else
    {
        Log(("vgdrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
        return EINVAL;
    }

    /*
     * Process the IOCtl.
     */
    int rc = VGDrvCommonIoCtl(ulCmd, &g_DevExt, pSession, pHdr, cbReq);
    if (RT_LIKELY(!rc))
    {
        /*
         * If unbuffered, copy back the result before returning.
         */
        if (pvUser)
        {
            uint32_t cbOut = pHdr->cbOut;
            if (cbOut > cbReq)
            {
                LogRel(("vgdrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
                cbOut = cbReq;
            }
            rc = copyout(pHdr, pvUser, cbOut);
            if (RT_UNLIKELY(rc))
                LogRel(("vgdrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));

            Log(("vgdrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));

            /* cleanup */
            RTMemTmpFree(pHdr);
        }
    }
    else
    {
        /*
         * The request failed, just clean up.
         */
        if (pvUser)
            RTMemTmpFree(pHdr);

        Log(("vgdrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
        rc = EINVAL;
    }

    return rc;
}
Ejemplo n.º 24
0
/*
 * main ioctl syscall.
 *
 * ok, here we are in the biggy.  we have to do fix ups depending
 * on the ioctl command before and afterwards.
 */
int
netbsd32_ioctl(struct lwp *l, const struct netbsd32_ioctl_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) fd;
		syscallarg(netbsd32_u_long) com;
		syscallarg(netbsd32_voidp) data;
	} */
	struct proc *p = l->l_proc;
	struct file *fp;
	struct filedesc *fdp;
	u_long com;
	int error = 0;
	u_int size, size32;
	void *data, *memp = NULL;
	void *data32, *memp32 = NULL;
	unsigned fd;
	fdfile_t *ff;
	int tmp;
#define STK_PARAMS	128
	u_long stkbuf[STK_PARAMS/sizeof(u_long)];
	u_long stkbuf32[STK_PARAMS/sizeof(u_long)];

	/*
	 * we need to translate some commands (_IOW) before calling sys_ioctl,
	 * some after (_IOR), and some both (_IOWR).
	 */
#if 0
	{
char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!",
		"INOUT", "VOID|IN|OUT!" };

printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n",
       SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data),
       dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)],
       IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)),
       IOCPARM_LEN(SCARG(uap, com)));
	}
#endif

	fdp = p->p_fd;
	fd = SCARG(uap, fd);
	if ((fp = fd_getfile(fd)) == NULL)
		return (EBADF);
	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
		error = EBADF;
		goto out;
	}

	ff = fdp->fd_ofiles[SCARG(uap, fd)];
	switch (com = SCARG(uap, com)) {
	case FIOCLEX:
		ff->ff_exclose = true;
		fdp->fd_exclose = true;
		goto out;

	case FIONCLEX:
		ff->ff_exclose = false;
		goto out;
	}

	/*
	 * Interpret high order word to find amount of data to be
	 * copied to/from the user's address space.
	 */
	size = 0;
	size32 = IOCPARM_LEN(com);
	if (size32 > IOCPARM_MAX) {
		error = ENOTTY;
		goto out;
	}
	if (size32 > sizeof(stkbuf)) {
		memp32 = kmem_alloc((size_t)size32, KM_SLEEP);
		data32 = memp32;
	} else
		data32 = (void *)stkbuf32;
	if (com&IOC_IN) {
		if (size32) {
			error = copyin(SCARG_P32(uap, data), data32, size32);
			if (error) {
				if (memp32)
					kmem_free(memp32, (size_t)size32);
				goto out;
			}
			ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data),
			    size32, 0);
		} else
			*(void **)data32 = SCARG_P32(uap, data);
	} else if ((com&IOC_OUT) && size32)
		/*
		 * Zero the buffer so the user always
		 * gets back something deterministic.
		 */
		memset(data32, 0, size32);
	else if (com&IOC_VOID)
		*(void **)data32 = SCARG_P32(uap, data);

	/*
	 * convert various structures, pointers, and other objects that
	 * change size from 32 bit -> 64 bit, for all ioctl commands.
	 */
	switch (SCARG(uap, com)) {
	case FIONBIO:
		mutex_enter(&fp->f_lock);
		if ((tmp = *(int *)data32) != 0)
			fp->f_flag |= FNONBLOCK;
		else
			fp->f_flag &= ~FNONBLOCK;
		mutex_exit(&fp->f_lock);
		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp);
		break;

	case FIOASYNC:
		mutex_enter(&fp->f_lock);
		if ((tmp = *(int *)data32) != 0)
			fp->f_flag |= FASYNC;
		else
			fp->f_flag &= ~FASYNC;
		mutex_exit(&fp->f_lock);
		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (void *)&tmp);
		break;

	case DIOCGPART32:
		IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo);
#if 0	/* not implemented by anything */
	case DIOCRFORMAT32:
		IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op);
	case DIOCWFORMAT32:
		IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op);
#endif

/*
 * only a few ifreq syscalls need conversion and those are
 * all driver specific... XXX
 */
#if 0
	case SIOCGADDRROM3232:
		IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq);
	case SIOCGCHIPID32:
		IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq);
	case SIOCSIFADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq);
	case OSIOCGIFADDR32:
		IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq);
	case SIOCGIFADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq);
	case SIOCSIFDSTADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq);
	case OSIOCGIFDSTADDR32:
		IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq);
	case SIOCGIFDSTADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq);
	case OSIOCGIFBRDADDR32:
		IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq);
	case SIOCGIFBRDADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq);
	case SIOCSIFBRDADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq);
	case OSIOCGIFNETMASK32:
		IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq);
	case SIOCGIFNETMASK32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq);
	case SIOCSIFNETMASK32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq);
	case SIOCGIFMETRIC32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq);
	case SIOCSIFMETRIC32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq);
	case SIOCDIFADDR32:
		IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq);
	case SIOCADDMULTI32:
		IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq);
	case SIOCDELMULTI32:
		IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq);
	case SIOCSIFMEDIA32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq);
	case SIOCSIFMTU32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq);
	case SIOCGIFMTU32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq);
	case BIOCGETIF32:
		IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq);
	case BIOCSETIF32:
		IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq);
	case SIOCPHASE132:
		IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq);
	case SIOCPHASE232:
		IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq);
#endif

	case OOSIOCGIFCONF32:
		IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF, ifconf);
	case OSIOCGIFCONF32:
		IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf);
	case SIOCGIFCONF32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf);

	case SIOCGIFFLAGS32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq);
	case SIOCSIFFLAGS32:
		IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq);

	case SIOCGIFMEDIA32:
		IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq);

	case SIOCSDRVSPEC32:
		IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv);

	case SIOCGETVIFCNT32:
		IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req);

	case SIOCGETSGCNT32:
		IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req);

	default:
#ifdef NETBSD32_MD_IOCTL
		error = netbsd32_md_ioctl(fp, com, data32, l);
#else
		error = (*fp->f_ops->fo_ioctl)(fp, com, data32);
#endif
		break;
	}

	if (error == EPASSTHROUGH)
		error = ENOTTY;

	/*
	 * Copy any data to user, size was
	 * already set and checked above.
	 */
	if (error == 0 && (com&IOC_OUT) && size32) {
		error = copyout(data32, SCARG_P32(uap, data), size32);
		ktrgenio(fd, UIO_READ, SCARG_P32(uap, data),
		    size32, error);
	}

	/* if we malloced data, free it here */
	if (memp32)
		kmem_free(memp32, (size_t)size32);
	if (memp)
		kmem_free(memp, (size_t)size);
 out:
	fd_putfile(fd);
	return (error);
}
Ejemplo n.º 25
0
static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
{
    LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl Dev=%d Cmd=%d pArg=%p Mode=%d\n", Dev, Cmd, pArg));

    /*
     * Get the session from the soft state item.
     */
    vboxusbmon_state_t *pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
    if (!pState)
    {
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: no state data for %d\n", getminor(Dev)));
        return EINVAL;
    }

    /*
     * Read the request wrapper. Though We don't really need wrapper struct. now
     * it's room for the future as Solaris isn't generous regarding the size.
     */
    VBOXUSBREQ ReqWrap;
    if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
    {
        LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
        return ENOTTY;
    }

    int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d.\n", pArg, Cmd, rc));
        return EINVAL;
    }

    if (ReqWrap.u32Magic != VBOXUSBMON_MAGIC)
    {
        LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad magic %#x; pArg=%p Cmd=%d.\n", ReqWrap.u32Magic, pArg, Cmd));
        return EINVAL;
    }
    if (RT_UNLIKELY(   ReqWrap.cbData == 0
                    || ReqWrap.cbData > _1M*16))
    {
        LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad size %#x; pArg=%p Cmd=%d.\n", ReqWrap.cbData, pArg, Cmd));
        return EINVAL;
    }

    /*
     * Read the request.
     */
    void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
    if (RT_UNLIKELY(!pvBuf))
    {
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
        return ENOMEM;
    }

    rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
    if (RT_UNLIKELY(rc))
    {
        RTMemTmpFree(pvBuf);
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
        return EFAULT;
    }
    if (RT_UNLIKELY(   ReqWrap.cbData != 0
                    && !VALID_PTR(pvBuf)))
    {
        RTMemTmpFree(pvBuf);
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pvBuf invalid pointer %p\n", pvBuf));
        return EINVAL;
    }
    Log((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pid=%d.\n", (int)RTProcSelf()));

    /*
     * Process the IOCtl.
     */
    size_t cbDataReturned;
    rc = vboxUSBMonSolarisProcessIOCtl(Cmd, pState, pvBuf, ReqWrap.cbData, &cbDataReturned);
    ReqWrap.rc = rc;
    rc = 0;

    if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
    {
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
        cbDataReturned = ReqWrap.cbData;
    }

    ReqWrap.cbData = cbDataReturned;

    /*
     * Copy the request back to user space.
     */
    rc = ddi_copyout(&ReqWrap, (void *)pArg, sizeof(ReqWrap), Mode);
    if (RT_LIKELY(!rc))
    {
        /*
         * Copy the payload (if any) back to user space.
         */
        if (cbDataReturned > 0)
        {
            rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
            if (RT_UNLIKELY(rc))
            {
                LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
                rc = EFAULT;
            }
        }
    }
    else
    {
        LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout(1) failed pArg=%p Cmd=%d\n", pArg, Cmd));
        rc = EFAULT;
    }

    *pVal = rc;
    RTMemTmpFree(pvBuf);
    return rc;
}
Ejemplo n.º 26
0
static int
acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
{
    union acpi_battery_ioctl_arg *ioctl_arg;
    int error, unit;
    device_t dev;


    /*
     * Giant is acquired to work around a reference counting bug in ACPICA
     * versions prior to 20130328.  If not for that bug this function could
     * be executed concurrently without any problems.
     * The bug is in acpi_BatteryIsPresent -> AcpiGetObjectInfo call tree,
     * where AcpiUtExecute_HID, AcpiUtExecute_UID, etc are executed without
     * protection of any ACPICA lock and may concurrently call
     * AcpiUtRemoveReference on a battery object.
     */
    mtx_lock(&Giant);

    /* For commands that use the ioctl_arg struct, validate it first. */
    error = ENXIO;
    unit = 0;
    dev = NULL;
    ioctl_arg = NULL;
    if (IOCPARM_LEN(cmd) == sizeof(*ioctl_arg)) {
	ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
	unit = ioctl_arg->unit;
	if (unit != ACPI_BATTERY_ALL_UNITS)
	    dev = acpi_battery_find_dev(unit);
    }

    /*
     * No security check required: information retrieval only.  If
     * new functions are added here, a check might be required.
     */
    switch (cmd) {
    case ACPIIO_BATT_GET_UNITS:
	*(int *)addr = acpi_battery_get_units();
	error = 0;
	break;
    case ACPIIO_BATT_GET_BATTINFO:
	if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) {
	    bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo));
	    error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo);
	}
	break;
    case ACPIIO_BATT_GET_BIF:
	if (dev != NULL) {
	    bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif));
	    error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif);

	    /*
	     * Remove invalid characters.  Perhaps this should be done
	     * within a convenience function so all callers get the
	     * benefit.
	     */
	    acpi_battery_clean_str(ioctl_arg->bif.model,
		sizeof(ioctl_arg->bif.model));
	    acpi_battery_clean_str(ioctl_arg->bif.serial,
		sizeof(ioctl_arg->bif.serial));
	    acpi_battery_clean_str(ioctl_arg->bif.type,
		sizeof(ioctl_arg->bif.type));
	    acpi_battery_clean_str(ioctl_arg->bif.oeminfo,
		sizeof(ioctl_arg->bif.oeminfo));
	}
	break;
    case ACPIIO_BATT_GET_BST:
	if (dev != NULL) {
	    bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst));
	    error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst);
	}
	break;
    default:
	error = EINVAL;
    }

    mtx_unlock(&Giant);
    return (error);
}