Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 04 Sep 1997 15:19:14 +1000
From:      Stephen McKay <syssgm@dtir.qld.gov.au>
To:        Mike Smith <mike@smith.net.au>, Simon Shapiro <Shimon@i-Connect.Net>
Cc:        freebsd-hackers@freebsd.org, syssgm@dtir.qld.gov.au
Subject:   Re: IOCTL Commands - Where is my mistake? 
Message-ID:  <199709040519.PAA09446@ogre.dtir.qld.gov.au>
In-Reply-To: <199709040247.MAA00870@word.smith.net.au> from Mike Smith at "Thu, 04 Sep 1997 02:47:22 %2B0000"
References:  <199709040247.MAA00870@word.smith.net.au>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thursday, 4th September 1997, Mike Smith wrote:

>... the correct approach would seem to be :
>
>struct foo {
>	int a, b;
>};
>
>#define FOO_IOCTL	_IOWR('F', 1, struct foo)
>
>...
>	struct foo	bar;
>...
>	ioctl(fd, FOO_IOCTL, bar);
>...
>
>	case FOO_IOCTL:
>	{
>	struct foo	oof = (struct foo *)cmdarg;
>...
>		<access foo via oof>
>...
>	}
>
>This will copy the 'bar' structure into and out of the kernel (tune 
>with the macro to suit), and allow you to call the ioctl handler from 
>within the kernel (eg. from one of the ABI emulation layers).
>
>I hope this a) makes sense, and b) works for you.

Well Mike, I'm pretty sure now that you've made a boo-boo. :-)

I direct your attention to TIOCGWINSZ and a typical use of this in
nvi/cl/cl_term.c:

    struct winsize win;

    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) {
	...
    }

The definition of TIOCGWINSZ:

    #define TIOCGWINSZ      _IOR('t', 104, struct winsize)

and some code from kern/tty.c:

int
ttioctl(tp, cmd, data, flag)
        register struct tty *tp;
        int cmd, flag;
        void *data;
{
...
        case TIOCGWINSZ:                /* get window size */
                *(struct winsize *)data = tp->t_winsize;
                break;
...
}

There are a few levels of calls between ioctl() in kern/sys_generic.c and
ttioctl() in kern/tty.c but 'data' stays the same.

>From this, I expect that Simon wants to use his ioctl like:

    dpt_perf_t metrics;

    if ( (result = ioctl(fd, DPT_IOCTL_INTERNAL_METRICS, &metrics)) != 0 ) {
	...
    }

Define his ioctl like:

    #define DPT_IOCTL_INTERNAL_METRICS       _IOR('D', 1, dpt_perf_t)

And put this in his driver:

    int
    dpt_ioctl(dev_t dev, int cmd, caddr_t cmdarg, int flags, struct proc *p)

    ...

	switch (cmd) {
	case DPT_IOCTL_INTERNAL_METRICS:
	    *(dpt_perf_t *)cmdarg = dpt->performance;
	    break;

The reason that:

    #define DPT_IOCTL_INTERNAL_METRICS      IOC_INOUT | 1

works with his current driver code is sheer luck, as Mike says.  The size
is encoded as 0, and that falls through some odd code in ioctl() and hands
you a cmdarg that points to the pointer that was passed in from user mode.
A zero size should be an error in my books.

Stephen.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199709040519.PAA09446>