1 /*        $NetBSD: ultrix_ioctl.c,v 1.40 2022/02/09 22:30:27 andvar Exp $ */
2 /*        from : NetBSD: sunos_ioctl.c,v 1.21 1995/10/07 06:27:31 mycroft Exp */
3 
4 /*
5  * Copyright (c) 1993 Markus Wild.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * loosely from: Header: sunos_ioctl.c,v 1.7 93/05/28 04:40:43 torek Exp
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: ultrix_ioctl.c,v 1.40 2022/02/09 22:30:27 andvar Exp $");
32 
33 #if defined(_KERNEL_OPT)
34 #include "opt_compat_ultrix.h"
35 #include "opt_compat_sunos.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/ioctl.h>
44 #include <sys/termios.h>
45 #include <sys/tty.h>
46 #include <sys/socket.h>
47 #include <sys/audioio.h>
48 #include <net/if.h>
49 
50 #include <sys/mount.h>
51 
52 #include <compat/sys/sockio.h>
53 #include <compat/ultrix/ultrix_syscallargs.h>
54 #include <sys/syscallargs.h>
55 
56 #include <compat/sunos/sunos.h>
57 
58 #include <compat/ultrix/ultrix_tty.h>
59 
60 #define emul_termio ultrix_termio
61 #define emul_termios          ultrix_termios
62 
63 /*
64  * SunOS ioctl calls.
65  * This file is something of a hodge-podge.
66  * Support gets added as things turn up....
67  */
68 
69 static const struct speedtab sptab[] = {
70           { 0, 0 },
71           { 50, 1 },
72           { 75, 2 },
73           { 110, 3 },
74           { 134, 4 },
75           { 135, 4 },
76           { 150, 5 },
77           { 200, 6 },
78           { 300, 7 },
79           { 600, 8 },
80           { 1200, 9 },
81           { 1800, 10 },
82           { 2400, 11 },
83           { 4800, 12 },
84           { 9600, 13 },
85           { 19200, 14 },
86           { 38400, 15 },
87           { -1, -1 }
88 };
89 
90 static const uint16_t s2btab[] = {
91           0,
92           50,
93           75,
94           110,
95           134,
96           150,
97           200,
98           300,
99           600,
100           1200,
101           1800,
102           2400,
103           4800,
104           9600,
105           19200,
106           38400,
107 };
108 
109 
110 /*
111  * Translate a single tty control char from the emulation value
112  * to native termios, and vice-versa. Special-case
113  * the value of POSIX_VDISABLE, mapping it to and from 0.
114  */
115 #define NATIVE_TO_EMUL_CC(bsd_cc) \
116  (((bsd_cc)   != _POSIX_VDISABLE) ? (bsd_cc) : 0)
117 
118 #define EMUL_TO_NATIVE_CC(emul_cc) \
119  (emul_cc) ? (emul_cc) : _POSIX_VDISABLE;
120 
121 
122 static void stios2btios(struct emul_termios *, struct termios *);
123 static void btios2stios(struct termios *, struct emul_termios *);
124 static void stios2stio(struct emul_termios *, struct emul_termio *);
125 static void stio2stios(struct emul_termio *, struct emul_termios *);
126 
127 /*
128  * these two conversion functions have mostly been done
129  * with some perl cut&paste, then handedited to comment
130  * out what doesn't exist under NetBSD.
131  * A note from Markus's code:
132  *        (l & BITMASK1) / BITMASK1 * BITMASK2  is translated
133  *        optimally by gcc m68k, much better than any ?: stuff.
134  *        Code may vary with different architectures of course.
135  *
136  * I don't know what optimizer you used, but seeing divu's and
137  * bfextu's in the m68k assembly output did not encourage me...
138  * as well, gcc on the sparc definitely generates much better
139  * code with ?:.
140  */
141 
142 
143 static void
stios2btios(struct emul_termios * st,struct termios * bt)144 stios2btios(struct emul_termios *st, struct termios *bt)
145 {
146           uint32_t l, r;
147 
148           memset(bt, 0, sizeof(*bt));
149 
150           l = st->c_iflag;
151           r =       ((l & 0x00000001) ? IGNBRK    : 0);
152           r |=      ((l & 0x00000002) ? BRKINT    : 0);
153           r |=      ((l & 0x00000004) ? IGNPAR    : 0);
154           r |=      ((l & 0x00000008) ? PARMRK    : 0);
155           r |=      ((l & 0x00000010) ? INPCK     : 0);
156           r |=      ((l & 0x00000020) ? ISTRIP    : 0);
157           r |=      ((l & 0x00000040) ? INLCR     : 0);
158           r |=      ((l & 0x00000080) ? IGNCR     : 0);
159           r |=      ((l & 0x00000100) ? ICRNL     : 0);
160           /*        ((l & 0x00000200) ? IUCLC     : 0) */
161           r |=      ((l & 0x00000400) ? IXON      : 0);
162           r |=      ((l & 0x00000800) ? IXANY     : 0);
163           r |=      ((l & 0x00001000) ? IXOFF     : 0);
164           r |=      ((l & 0x00002000) ? IMAXBEL   : 0);
165           bt->c_iflag = r;
166 
167           l = st->c_oflag;
168           r =       ((l & 0x00000001) ? OPOST     : 0);
169           /*        ((l & 0x00000002) ? OLCUC     : 0) */
170           r |=      ((l & 0x00000004) ? ONLCR     : 0);
171           /*        ((l & 0x00000008) ? OCRNL     : 0) */
172           /*        ((l & 0x00000010) ? ONOCR     : 0) */
173           /*        ((l & 0x00000020) ? ONLRET    : 0) */
174           /*        ((l & 0x00000040) ? OFILL     : 0) */
175           /*        ((l & 0x00000080) ? OFDEL     : 0) */
176           /*        ((l & 0x00000100) ? NLDLY     : 0) */
177           /*        ((l & 0x00000100) ? NL1                 : 0) */
178           /*        ((l & 0x00000600) ? CRDLY     : 0) */
179           /*        ((l & 0x00000200) ? CR1                 : 0) */
180           /*        ((l & 0x00000400) ? CR2                 : 0) */
181           /*        ((l & 0x00000600) ? CR3                 : 0) */
182           /*        ((l & 0x00001800) ? TABDLY    : 0) */
183           /*        ((l & 0x00000800) ? TAB1      : 0) */
184           /*        ((l & 0x00001000) ? TAB2      : 0) */
185           r |=      ((l & 0x00001800) ? OXTABS    : 0);
186           /*        ((l & 0x00002000) ? BSDLY     : 0) */
187           /*        ((l & 0x00002000) ? BS1                 : 0) */
188           /*        ((l & 0x00004000) ? VTDLY     : 0) */
189           /*        ((l & 0x00004000) ? VT1                 : 0) */
190           /*        ((l & 0x00008000) ? FFDLY     : 0) */
191           /*        ((l & 0x00008000) ? FF1                 : 0) */
192           /*        ((l & 0x00010000) ? PAGEOUT   : 0) */
193           /*        ((l & 0x00020000) ? WRAP      : 0) */
194           bt->c_oflag = r;
195 
196           l = st->c_cflag;
197           switch (l & 0x00000030) {
198           case 0:
199                     r = CS5;
200                     break;
201           case 0x00000010:
202                     r = CS6;
203                     break;
204           case 0x00000020:
205                     r = CS7;
206                     break;
207           case 0x00000030:
208                     r = CS8;
209                     break;
210           }
211           r |=      ((l & 0x00000040) ? CSTOPB    : 0);
212           r |=      ((l & 0x00000080) ? CREAD     : 0);
213           r |=      ((l & 0x00000100) ? PARENB    : 0);
214           r |=      ((l & 0x00000200) ? PARODD    : 0);
215           r |=      ((l & 0x00000400) ? HUPCL     : 0);
216           r |=      ((l & 0x00000800) ? CLOCAL    : 0);
217           /*        ((l & 0x00001000) ? LOBLK     : 0) */
218           r |=      ((l & 0x80000000) ? (CRTS_IFLOW|CCTS_OFLOW) : 0);
219           bt->c_cflag = r;
220 
221           bt->c_ispeed = bt->c_ospeed = s2btab[l & 0x0000000f];
222 
223           l = st->c_lflag;
224           r =       ((l & 0x00000001) ? ISIG      : 0);
225           r |=      ((l & 0x00000002) ? ICANON    : 0);
226           /*        ((l & 0x00000004) ? XCASE     : 0) */
227           r |=      ((l & 0x00000008) ? ECHO      : 0);
228           r |=      ((l & 0x00000010) ? ECHOE     : 0);
229           r |=      ((l & 0x00000020) ? ECHOK     : 0);
230           r |=      ((l & 0x00000040) ? ECHONL    : 0);
231           r |=      ((l & 0x00000080) ? NOFLSH    : 0);
232           r |=      ((l & 0x00000100) ? TOSTOP    : 0);
233           r |=      ((l & 0x00000200) ? ECHOCTL   : 0);
234           r |=      ((l & 0x00000400) ? ECHOPRT   : 0);
235           r |=      ((l & 0x00000800) ? ECHOKE    : 0);
236           /*        ((l & 0x00001000) ? DEFECHO   : 0) */
237           r |=      ((l & 0x00002000) ? FLUSHO    : 0);
238           r |=      ((l & 0x00004000) ? PENDIN    : 0);
239           bt->c_lflag = r;
240 
241           bt->c_cc[VINTR]    = EMUL_TO_NATIVE_CC(st->c_cc[0]);
242           bt->c_cc[VQUIT]    = EMUL_TO_NATIVE_CC(st->c_cc[1]);
243           bt->c_cc[VERASE]   = EMUL_TO_NATIVE_CC(st->c_cc[2]);
244           bt->c_cc[VKILL]    = EMUL_TO_NATIVE_CC(st->c_cc[3]);
245           bt->c_cc[VEOF]     = EMUL_TO_NATIVE_CC(st->c_cc[4]);
246           bt->c_cc[VEOL]     = EMUL_TO_NATIVE_CC(st->c_cc[5]);
247           bt->c_cc[VEOL2]    = EMUL_TO_NATIVE_CC(st->c_cc[6]);
248           /* not present on NetBSD */
249           /* bt->c_cc[VSWTCH]   = EMUL_TO_NATIVE_CC(st->c_cc[7]); */
250           bt->c_cc[VSTART]   = EMUL_TO_NATIVE_CC(st->c_cc[10]);
251           bt->c_cc[VSTOP]    = EMUL_TO_NATIVE_CC(st->c_cc[11]);
252           bt->c_cc[VSUSP]    = EMUL_TO_NATIVE_CC(st->c_cc[12]);
253           bt->c_cc[VDSUSP]   = EMUL_TO_NATIVE_CC(st->c_cc[13]);
254           bt->c_cc[VREPRINT] = EMUL_TO_NATIVE_CC(st->c_cc[14]);
255           bt->c_cc[VDISCARD] = EMUL_TO_NATIVE_CC(st->c_cc[15]);
256           bt->c_cc[VWERASE]  = EMUL_TO_NATIVE_CC(st->c_cc[16]);
257           bt->c_cc[VLNEXT]   = EMUL_TO_NATIVE_CC(st->c_cc[17]);
258           bt->c_cc[VSTATUS]  = EMUL_TO_NATIVE_CC(st->c_cc[18]);
259 
260 #ifdef COMPAT_ULTRIX
261           /* Ultrix termio/termios has real vmin/vtime */
262           bt->c_cc[VMIN]         = EMUL_TO_NATIVE_CC(st->c_cc[8]);
263           bt->c_cc[VTIME]        = EMUL_TO_NATIVE_CC(st->c_cc[9]);
264 #else
265           /* if `raw mode', create native VMIN/VTIME from SunOS VEOF/VEOL */
266           bt->c_cc[VMIN]         = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOF];
267           bt->c_cc[VTIME]        = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOL];
268 #endif
269 
270 }
271 
272 /*
273  * Convert bsd termios to "sunos" emulated termios
274  */
275 static void
btios2stios(struct termios * bt,struct emul_termios * st)276 btios2stios(struct termios *bt, struct emul_termios *st)
277 {
278           uint32_t l, r;
279           int speed;
280 
281           memset(st, 0, sizeof(*st));
282 
283           l = bt->c_iflag;
284           r =       ((l &  IGNBRK) ? 0x00000001   : 0);
285           r |=      ((l &  BRKINT) ? 0x00000002   : 0);
286           r |=      ((l &  IGNPAR) ? 0x00000004   : 0);
287           r |=      ((l &  PARMRK) ? 0x00000008   : 0);
288           r |=      ((l &   INPCK) ? 0x00000010   : 0);
289           r |=      ((l &  ISTRIP) ? 0x00000020   : 0);
290           r |=      ((l &   INLCR) ? 0x00000040   : 0);
291           r |=      ((l &   IGNCR) ? 0x00000080   : 0);
292           r |=      ((l &   ICRNL) ? 0x00000100   : 0);
293           /*        ((l &   IUCLC) ? 0x00000200   : 0) */
294           r |=      ((l &    IXON) ? 0x00000400   : 0);
295           r |=      ((l &   IXANY) ? 0x00000800   : 0);
296           r |=      ((l &   IXOFF) ? 0x00001000   : 0);
297           r |=      ((l & IMAXBEL) ? 0x00002000   : 0);
298           st->c_iflag = r;
299 
300           l = bt->c_oflag;
301           r =       ((l &   OPOST) ? 0x00000001   : 0);
302           /*        ((l &   OLCUC) ? 0x00000002   : 0) */
303           r |=      ((l &   ONLCR) ? 0x00000004   : 0);
304           /*        ((l &   OCRNL) ? 0x00000008   : 0) */
305           /*        ((l &   ONOCR) ? 0x00000010   : 0) */
306           /*        ((l &  ONLRET) ? 0x00000020   : 0) */
307           /*        ((l &   OFILL) ? 0x00000040   : 0) */
308           /*        ((l &   OFDEL) ? 0x00000080   : 0) */
309           /*        ((l &   NLDLY) ? 0x00000100   : 0) */
310           /*        ((l &     NL1) ? 0x00000100   : 0) */
311           /*        ((l &   CRDLY) ? 0x00000600   : 0) */
312           /*        ((l &     CR1) ? 0x00000200   : 0) */
313           /*        ((l &     CR2) ? 0x00000400   : 0) */
314           /*        ((l &     CR3) ? 0x00000600   : 0) */
315           /*        ((l &  TABDLY) ? 0x00001800   : 0) */
316           /*        ((l &    TAB1) ? 0x00000800   : 0) */
317           /*        ((l &    TAB2) ? 0x00001000   : 0) */
318           r |=      ((l &  OXTABS) ? 0x00001800   : 0);
319           /*        ((l &   BSDLY) ? 0x00002000   : 0) */
320           /*        ((l &     BS1) ? 0x00002000   : 0) */
321           /*        ((l &   VTDLY) ? 0x00004000   : 0) */
322           /*        ((l &     VT1) ? 0x00004000   : 0) */
323           /*        ((l &   FFDLY) ? 0x00008000   : 0) */
324           /*        ((l &     FF1) ? 0x00008000   : 0) */
325           /*        ((l & PAGEOUT) ? 0x00010000   : 0) */
326           /*        ((l &    WRAP) ? 0x00020000   : 0) */
327           st->c_oflag = r;
328 
329           l = bt->c_cflag;
330           switch (l & CSIZE) {
331           case CS5:
332                     r = 0;
333                     break;
334           case CS6:
335                     r = 0x00000010;
336                     break;
337           case CS7:
338                     r = 0x00000020;
339                     break;
340           case CS8:
341                     r = 0x00000030;
342                     break;
343           }
344           r |=      ((l &  CSTOPB) ? 0x00000040   : 0);
345           r |=      ((l &   CREAD) ? 0x00000080   : 0);
346           r |=      ((l &  PARENB) ? 0x00000100   : 0);
347           r |=      ((l &  PARODD) ? 0x00000200   : 0);
348           r |=      ((l &   HUPCL) ? 0x00000400   : 0);
349           r |=      ((l &  CLOCAL) ? 0x00000800   : 0);
350           /*        ((l &   LOBLK) ? 0x00001000   : 0) */
351           r |=      ((l & (CRTS_IFLOW|CCTS_OFLOW)) ? 0x80000000 : 0);
352           st->c_cflag = r;
353 
354           l = bt->c_lflag;
355           r =       ((l &    ISIG) ? 0x00000001   : 0);
356           r |=      ((l &  ICANON) ? 0x00000002   : 0);
357           /*        ((l &   XCASE) ? 0x00000004   : 0) */
358           r |=      ((l &    ECHO) ? 0x00000008   : 0);
359           r |=      ((l &   ECHOE) ? 0x00000010   : 0);
360           r |=      ((l &   ECHOK) ? 0x00000020   : 0);
361           r |=      ((l &  ECHONL) ? 0x00000040   : 0);
362           r |=      ((l &  NOFLSH) ? 0x00000080   : 0);
363           r |=      ((l &  TOSTOP) ? 0x00000100   : 0);
364           r |=      ((l & ECHOCTL) ? 0x00000200   : 0);
365           r |=      ((l & ECHOPRT) ? 0x00000400   : 0);
366           r |=      ((l &  ECHOKE) ? 0x00000800   : 0);
367           /*        ((l & DEFECHO) ? 0x00001000   : 0) */
368           r |=      ((l &  FLUSHO) ? 0x00002000   : 0);
369           r |=      ((l &  PENDIN) ? 0x00004000   : 0);
370           st->c_lflag = r;
371 
372           speed = ttspeedtab(bt->c_ospeed, sptab);
373           if (speed != -1)
374               st->c_cflag |= speed;
375 
376           st->c_cc[0] = NATIVE_TO_EMUL_CC(bt->c_cc[VINTR]);
377           st->c_cc[1] = NATIVE_TO_EMUL_CC(bt->c_cc[VQUIT]);
378           st->c_cc[2] = NATIVE_TO_EMUL_CC(bt->c_cc[VERASE]);
379           st->c_cc[3] = NATIVE_TO_EMUL_CC(bt->c_cc[VKILL]);
380           st->c_cc[4] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOF]);
381           st->c_cc[5] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOL]);
382           st->c_cc[6] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOL2]);
383 
384           /* XXX ultrix has a VSWTCH.  NetBSD does not. */
385 #ifdef notdef
386           st->c_cc[7] = NATIVE_TO_EMUL_CC(bt->c_cc[VSWTCH]);
387 #else
388           st->c_cc[7] = 0;
389 #endif
390           st->c_cc[10] = NATIVE_TO_EMUL_CC(bt->c_cc[VSTART]);
391           st->c_cc[11] = NATIVE_TO_EMUL_CC(bt->c_cc[VSTOP]);
392           st->c_cc[12]= NATIVE_TO_EMUL_CC(bt->c_cc[VSUSP]);
393           st->c_cc[13]= NATIVE_TO_EMUL_CC(bt->c_cc[VDSUSP]);
394           st->c_cc[14]= NATIVE_TO_EMUL_CC(bt->c_cc[VREPRINT]);
395           st->c_cc[15]= NATIVE_TO_EMUL_CC(bt->c_cc[VDISCARD]);
396           st->c_cc[16]= NATIVE_TO_EMUL_CC(bt->c_cc[VWERASE]);
397           st->c_cc[17]= NATIVE_TO_EMUL_CC(bt->c_cc[VLNEXT]);
398           st->c_cc[18]= NATIVE_TO_EMUL_CC(bt->c_cc[VSTATUS]);
399 
400 #ifdef COMPAT_ULTRIX
401           st->c_cc[8]= NATIVE_TO_EMUL_CC(bt->c_cc[VMIN]);
402           st->c_cc[9]= NATIVE_TO_EMUL_CC(bt->c_cc[VTIME]);
403 #else
404           if (!(bt->c_lflag & ICANON)) {
405                     /* SunOS stores VMIN/VTIME in VEOF/VEOL (if ICANON is off) */
406                     st->c_cc[4] = bt->c_cc[VMIN];
407                     st->c_cc[5] = bt->c_cc[VTIME];
408           }
409 #endif
410 
411 #ifdef COMPAT_SUNOS
412           st->c_line = 0;     /* 4.3bsd "old" line discipline */
413 #else
414           st->c_line = 2;     /* 4.3bsd "new" line discipline, Ultrix default. */
415 #endif
416 }
417 
418 #define TERMIO_NCC 10         /* ultrix termio NCC is 10 */
419 
420 /*
421  * Convert emulated struct termios to termio(?)
422  */
423 static void
stios2stio(struct emul_termios * ts,struct emul_termio * t)424 stios2stio(struct emul_termios *ts, struct emul_termio *t)
425 {
426 
427           memset(t, 0, sizeof(*t));
428           t->c_iflag = ts->c_iflag;
429           t->c_oflag = ts->c_oflag;
430           t->c_cflag = ts->c_cflag;
431           t->c_lflag = ts->c_lflag;
432           t->c_line  = ts->c_line;
433           memcpy(t->c_cc, ts->c_cc, TERMIO_NCC);
434 }
435 
436 /*
437  * Convert the other way
438  */
439 static void
stio2stios(struct emul_termio * t,struct emul_termios * ts)440 stio2stios(struct emul_termio *t, struct emul_termios *ts)
441 {
442 
443           memset(ts, 0, sizeof(*t));
444           ts->c_iflag = t->c_iflag;
445           ts->c_oflag = t->c_oflag;
446           ts->c_cflag = t->c_cflag;
447           ts->c_lflag = t->c_lflag;
448           ts->c_line  = t->c_line;
449 
450           /* don't touch the upper fields! */
451           memcpy(ts->c_cc, t->c_cc, TERMIO_NCC);
452 }
453 
454 static int
ultrix_do_ioctl(int fd,int cmd,void * arg,struct lwp * l)455 ultrix_do_ioctl(int fd, int cmd, void *arg, struct lwp *l)
456 {
457           file_t *fp;
458           int error;
459 
460           if ((fp = fd_getfile(fd)) == NULL)
461                     return EBADF;
462 
463           if ((fp->f_flag & (FREAD|FWRITE)) == 0)
464                     error = EBADF;
465           else
466                     error = fp->f_ops->fo_ioctl(fp, cmd, arg);
467           fd_putfile(fd);
468           return error;
469 }
470 
471 int
ultrix_sys_ioctl(struct lwp * l,const struct ultrix_sys_ioctl_args * uap,register_t * retval)472 ultrix_sys_ioctl(struct lwp *l, const struct ultrix_sys_ioctl_args *uap,
473     register_t *retval)
474 {
475           struct sys_ioctl_args ap;
476           int error;
477 
478           SCARG(&ap, fd) = SCARG(uap, fd);
479           SCARG(&ap, data) = SCARG(uap, data);
480           SCARG(&ap, com) = SCARG(uap, com);
481           switch (SCARG(&ap, com)) {
482           case _IOR('t', 0, int):
483                     SCARG(&ap, com) = TIOCGETD;
484                     break;
485           case _IOW('t', 1, int):
486               {
487                     int disc;
488 
489                     error = copyin(SCARG(&ap, data), &disc, sizeof disc);
490                     if (error != 0)
491                               return error;
492 
493                     /* map SunOS NTTYDISC into our termios discipline */
494                     if (disc == 2)
495                               disc = 0;
496                     /* all other disciplines are not supported by NetBSD */
497                     if (disc)
498                               return ENXIO;
499 
500                     return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSETD, &disc, l);
501               }
502           case _IOW('t', 101, int):     /* sun SUNOS_TIOCSSOFTCAR */
503               {
504                     int x;    /* unused */
505 
506                     return copyin(SCARG(&ap, data), &x, sizeof x);
507               }
508           case _IOR('t', 100, int):     /* sun SUNOS_TIOCSSOFTCAR */
509               {
510                     int x = 0;
511 
512                     return copyout(&x, SCARG(&ap, data), sizeof x);
513               }
514           case _IO('t', 36):            /* sun TIOCCONS, no parameters */
515               {
516                     int on = 1;
517                     return ultrix_do_ioctl(SCARG(&ap, fd), TIOCCONS, &on, l);
518               }
519           case _IOW('t', 37, struct sunos_ttysize):
520               {
521                     struct winsize ws;
522                     struct sunos_ttysize ss;
523 
524                     error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGWINSZ, &ws, l);
525                     if (error != 0)
526                               return error;
527 
528                     if ((error = copyin(SCARG(&ap, data), &ss, sizeof(ss))) != 0)
529                               return error;
530 
531                     ws.ws_row = ss.ts_row;
532                     ws.ws_col = ss.ts_col;
533 
534                     return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSWINSZ, &ws, l);
535               }
536           case _IOW('t', 38, struct sunos_ttysize):
537               {
538                     struct winsize ws;
539                     struct sunos_ttysize ss;
540 
541                     error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGWINSZ, &ws, l);
542                     if (error != 0)
543                               return error;
544 
545                     memset(&ss, 0, sizeof(ss));
546                     ss.ts_row = ws.ws_row;
547                     ss.ts_col = ws.ws_col;
548 
549                     return copyout(&ss, SCARG(&ap, data), sizeof(ss));
550               }
551           case _IOW('t', 118, int):
552                     SCARG(&ap, com) = TIOCSPGRP;
553                     break;
554           case _IOR('t', 119, int):
555                     SCARG(&ap, com) = TIOCGPGRP;
556                     break;
557 
558           /* Emulate termio or termios tcget() */
559           case ULTRIX_TCGETA:
560           case ULTRIX_TCGETS:
561               {
562                     struct termios bts;
563                     struct ultrix_termios sts;
564                     struct ultrix_termio st;
565 
566                     error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGETA, &bts, l);
567                     if (error != 0)
568                               return error;
569 
570                     btios2stios (&bts, &sts);
571                     if (SCARG(&ap, com) == ULTRIX_TCGETA) {
572                               stios2stio (&sts, &st);
573                               return copyout(&st, SCARG(&ap, data), sizeof(st));
574                     } else
575                               return copyout(&sts, SCARG(&ap, data), sizeof(sts));
576                     /*NOTREACHED*/
577               }
578           /* Emulate termio tcset() */
579           case ULTRIX_TCSETA:
580           case ULTRIX_TCSETAW:
581           case ULTRIX_TCSETAF:
582               {
583                     struct termios bts;
584                     struct ultrix_termios sts;
585                     struct ultrix_termio st;
586                     int result;
587 
588                     if ((error = copyin(SCARG(&ap, data), &st, sizeof(st))) != 0)
589                               return error;
590 
591                     /* get full BSD termios so we don't lose information */
592                     error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGETA, &bts, l);
593                     if (error != 0)
594                               return error;
595 
596                     /*
597                      * convert to sun termios, copy in information from
598                      * termio, and convert back, then set new values.
599                      */
600                     btios2stios(&bts, &sts);
601                     stio2stios(&st, &sts);
602                     stios2btios(&sts, &bts);
603 
604                     /*
605                      * map ioctl code: ultrix tcsets are numbered in reverse order
606                      */
607 #ifdef notyet
608                     return ultrix_do_ioctl(SCARG(&ap, fd),
609                         ULTRIX_TCSETA - SCARG(&ap, com) + TIOCSETA, &bts, l);
610 #else
611                     result = ultrix_do_ioctl(SCARG(&ap, fd),
612                         ULTRIX_TCSETA - SCARG(&ap, com) + TIOCSETA, &bts, l);
613                     printf("ultrix TCSETA %lx returns %d\n",
614                         ULTRIX_TCSETA - SCARG(&ap, com), result);
615                     return result;
616 #endif
617 
618               }
619           /* Emulate termios tcset() */
620           case ULTRIX_TCSETS:
621           case ULTRIX_TCSETSW:
622           case ULTRIX_TCSETSF:
623               {
624                     struct termios bts;
625                     struct ultrix_termios sts;
626 
627                     error = copyin(SCARG(&ap, data), &sts, sizeof(sts));
628                     if (error != 0)
629                               return error;
630                     stios2btios (&sts, &bts);
631                     return ultrix_do_ioctl(SCARG(&ap, fd),
632                         ULTRIX_TCSETS - SCARG(&ap, com) + TIOCSETA, &bts, l);
633               }
634 /*
635  * Pseudo-tty ioctl translations.
636  */
637           case _IOW('t', 32, int): {    /* TIOCTCNTL */
638                     int on;
639 
640                     error = copyin(SCARG(&ap, data), &on, sizeof(on));
641                     if (error != 0)
642                               return error;
643                     return ultrix_do_ioctl(SCARG(&ap, fd), TIOCUCNTL, &on, l);
644           }
645           case _IOW('t', 33, int): {    /* TIOCSIGNAL */
646                     int sig;
647 
648                     error = copyin(SCARG(&ap, data), &sig, sizeof(sig));
649                     if (error != 0)
650                               return error;
651                     return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSIG, &sig, l);
652           }
653 
654 /*
655  * Socket ioctl translations.
656  */
657 #define IN_TYPE(a, type_t) { \
658           type_t localbuf; \
659           if ((error = copyin(SCARG(&ap, data), \
660                                         &localbuf, sizeof(type_t))) != 0) \
661                     return error; \
662           return ultrix_do_ioctl(SCARG(&ap, fd), a, &localbuf, l); \
663 }
664 
665 #define INOUT_TYPE(a, type_t) { \
666           type_t localbuf; \
667           if ((error = copyin(SCARG(&ap, data), &localbuf,  \
668                                    sizeof(type_t))) != 0) \
669                     return error; \
670           if ((error = ultrix_do_ioctl(SCARG(&ap, fd), a, &localbuf, l)) != 0) \
671                     return error; \
672           return copyout(&localbuf, SCARG(&ap, data), sizeof(type_t)); \
673 }
674 
675 
676 #define IFREQ_IN(a) { \
677           struct oifreq ifreq; \
678           if ((error = copyin(SCARG(&ap, data), &ifreq, sizeof(ifreq))) != 0) \
679                     return error; \
680           return ultrix_do_ioctl(SCARG(&ap, fd), a, &ifreq, l); \
681 }
682 
683 #define IFREQ_INOUT(a) { \
684           struct oifreq ifreq; \
685           if ((error = copyin(SCARG(&ap, data), &ifreq, sizeof(ifreq))) != 0) \
686                     return error; \
687           if ((error = ultrix_do_ioctl(SCARG(&ap, fd), a, &ifreq, l)) != 0) \
688                     return error; \
689           return copyout(&ifreq, SCARG(&ap, data), sizeof(ifreq)); \
690 }
691 
692           case _IOW('i', 12, struct oifreq):
693                     /* SIOCSIFADDR */
694                     break;
695 
696           case _IOWR('i', 13, struct oifreq):
697                     IFREQ_INOUT(OOSIOCGIFADDR);
698 
699           case _IOW('i', 14, struct oifreq):
700                     /* SIOCSIFDSTADDR */
701                     break;
702 
703           case _IOWR('i', 15, struct oifreq):
704                     IFREQ_INOUT(OOSIOCGIFDSTADDR);
705 
706           case _IOW('i', 16, struct oifreq):
707                     /* SIOCSIFFLAGS */
708                     break;
709 
710           case _IOWR('i', 17, struct oifreq):
711                     /* SIOCGIFFLAGS */
712                     break;
713 
714           case _IOWR('i', 18, struct oifreq):
715                     IFREQ_INOUT(SIOCGIFBRDADDR);
716 
717           case _IOWR('i', 19, struct oifreq):
718                     IFREQ_INOUT(SIOCSIFBRDADDR);
719 
720           case _IOWR('i', 20, struct ifconf):     /* SIOCGIFCONF */
721               {
722                     struct ifconf ifconfarg;
723 
724                     /*
725                      * XXX: two more problems
726                      * 1. Our sockaddr's are variable length, not always
727                      *    sizeof(sockaddr)
728                      * 2. This returns a name per protocol, ie. it returns two
729                      *    "lo0"'s
730                      */
731                     error = copyin(SCARG(&ap, data), &ifconfarg,
732                         sizeof(ifconfarg));
733                     if (error)
734                               return error;
735 
736                     error = ultrix_do_ioctl(SCARG(&ap, fd), OSIOCGIFCONF,
737                         &ifconfarg, l);
738                     if (error)
739                               return error;
740 
741                     return copyout(&ifconfarg, SCARG(&ap, data),
742                         sizeof(ifconfarg));
743               }
744 
745 
746           case _IOWR('i', 21, struct oifreq):
747                     IFREQ_INOUT(OOSIOCGIFNETMASK);
748 
749           case _IOW('i', 22, struct oifreq):
750                     IFREQ_IN(SIOCSIFNETMASK);
751 
752           /* 23: _IOWR('i', 23, struct oifreq):  Ultrix SIOCSPHYADDR */
753           /* 24: _IOWR('i', 24, struct oifreq):  Ultrix SIOCSADDMULTI */
754           /* 25: _IOWR('i', 25, struct oifreq):  Ultrix SIOCSDELMULTI */
755 
756           case _IOW('i',  26, struct oifreq):     /* SIOCSIFRDCTRS? */
757           case _IOWR('i', 27, struct oifreq):     /* SIOCGIFZCTRS? */
758           case _IOWR('i', 28, struct oifreq):     /* read physaddr ? */
759                     return EOPNOTSUPP;
760 
761 
762           case _IOW('i', 30, struct arpreq):
763                     /* SIOCSARP */
764                     break;
765 
766           case _IOWR('i', 31, struct arpreq):
767                     /* SIOCGARP */
768                     break;
769 
770           case _IOW('i', 32, struct arpreq):
771                     /* SIOCDARP */
772                     break;
773 
774           case _IOW('i', 40, struct oifreq):      /* SIOCARPREQ */
775                     return EOPNOTSUPP;
776 
777           case _IOWR('i', 41, struct oifreq):
778                     IFREQ_INOUT(SIOCGIFMETRIC);
779 
780           case _IOWR('i', 42, struct oifreq):
781                     IFREQ_IN(SIOCSIFMETRIC);
782 
783           case _IOW('i', 44, struct oifreq):      /* SIOCSETSYNC */
784           case _IOWR('i', 45, struct oifreq):     /* SIOCGETSYNC */
785           case _IOWR('i', 46, struct oifreq):     /* SIOCSDSTATS */
786           case _IOWR('i', 47, struct oifreq):     /* SIOCSESTATS */
787           case _IOW('i', 48, int):                /* SIOCSPROMISC */
788                     return EOPNOTSUPP;
789 
790           /* emulate for vat, vic tools */
791           case _IOW('i', 49, struct oifreq):      /* SIOCADDMULTI */
792           case _IOW('i', 50, struct oifreq):      /* SIOCDELMULTI */
793                     return EOPNOTSUPP;
794 
795           }
796           return sys_ioctl(l, &ap, retval);
797 }
798