1 /* $Id: ioctl.c,v 1.11 1999/05/27 00:36:25 davem Exp $
2 * ioctl.c: Solaris ioctl emulation.
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
7 * Streams & timod emulation based on code
8 * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/ioctl.h>
19 #include <linux/file.h>
20 #include <linux/netdevice.h>
22 #include <asm/uaccess.h>
23 #include <asm/termios.h>
28 extern char *getname32(u32 filename
);
29 #define putname32 putname
31 extern asmlinkage
int sys_ioctl(unsigned int fd
, unsigned int cmd
,
33 extern asmlinkage
int sys32_ioctl(unsigned int fd
, unsigned int cmd
,
35 asmlinkage
int solaris_ioctl(unsigned int fd
, unsigned int cmd
, u32 arg
);
37 extern int timod_putmsg(unsigned int fd
, char *ctl_buf
, int ctl_len
,
38 char *data_buf
, int data_len
, int flags
);
39 extern int timod_getmsg(unsigned int fd
, char *ctl_buf
, int ctl_maxlen
, int *ctl_len
,
40 char *data_buf
, int data_maxlen
, int *data_len
, int *flags
);
42 /* termio* stuff {{{ */
44 struct solaris_termios
{
52 struct solaris_termio
{
61 struct solaris_termiox
{
68 static u32
solaris_to_linux_cflag(u32 cflag
)
71 if (cflag
& 0x200000) {
72 int baud
= cflag
& 0xf;
75 case 0: baud
= B57600
; break;
76 case 1: baud
= B76800
; break;
77 case 2: baud
= B115200
; break;
78 case 3: baud
= B153600
; break;
79 case 4: baud
= B230400
; break;
80 case 5: baud
= B307200
; break;
81 case 6: baud
= B460800
; break;
83 cflag
|= CBAUDEX
| baud
;
88 static u32
linux_to_solaris_cflag(u32 cflag
)
90 cflag
&= ~(CMSPAR
| CIBAUD
);
91 if (cflag
& CBAUDEX
) {
92 int baud
= cflag
& CBAUD
;
95 case B57600
: baud
= 0; break;
96 case B76800
: baud
= 1; break;
97 case B115200
: baud
= 2; break;
98 case B153600
: baud
= 3; break;
99 case B230400
: baud
= 4; break;
100 case B307200
: baud
= 5; break;
101 case B460800
: baud
= 6; break;
102 case B614400
: baud
= 7; break;
103 case B921600
: baud
= 8; break;
105 case B1843200
: baud
= 9; break;
108 cflag
|= 0x200000 | baud
;
113 static inline int linux_to_solaris_termio(unsigned int fd
, unsigned int cmd
, u32 arg
)
117 ret
= sys_ioctl(fd
, cmd
, A(arg
));
121 if (__get_user (cflag
, &((struct solaris_termio
*)A(arg
))->c_cflag
))
123 cflag
= linux_to_solaris_cflag(cflag
);
124 if (__put_user (cflag
, &((struct solaris_termio
*)A(arg
))->c_cflag
))
130 static int solaris_to_linux_termio(unsigned int fd
, unsigned int cmd
, u32 arg
)
133 struct solaris_termio s
;
134 mm_segment_t old_fs
= get_fs();
136 if (copy_from_user (&s
, (struct solaris_termio
*)A(arg
), sizeof(struct solaris_termio
)))
138 s
.c_cflag
= solaris_to_linux_cflag(s
.c_cflag
);
140 ret
= sys_ioctl(fd
, cmd
, (unsigned long)&s
);
145 static inline int linux_to_solaris_termios(unsigned int fd
, unsigned int cmd
, u32 arg
)
148 struct solaris_termios s
;
149 mm_segment_t old_fs
= get_fs();
152 ret
= sys_ioctl(fd
, cmd
, (unsigned long)&s
);
155 if (put_user (s
.c_iflag
, &((struct solaris_termios
*)A(arg
))->c_iflag
) ||
156 __put_user (s
.c_oflag
, &((struct solaris_termios
*)A(arg
))->c_oflag
) ||
157 __put_user (linux_to_solaris_cflag(s
.c_cflag
), &((struct solaris_termios
*)A(arg
))->c_cflag
) ||
158 __put_user (s
.c_lflag
, &((struct solaris_termios
*)A(arg
))->c_lflag
) ||
159 __copy_to_user (((struct solaris_termios
*)A(arg
))->c_cc
, s
.c_cc
, 16) ||
160 __clear_user (((struct solaris_termios
*)A(arg
))->c_cc
+ 16, 2))
166 static int solaris_to_linux_termios(unsigned int fd
, unsigned int cmd
, u32 arg
)
169 struct solaris_termios s
;
170 mm_segment_t old_fs
= get_fs();
173 ret
= sys_ioctl(fd
, TCGETS
, (unsigned long)&s
);
176 if (put_user (s
.c_iflag
, &((struct solaris_termios
*)A(arg
))->c_iflag
) ||
177 __put_user (s
.c_oflag
, &((struct solaris_termios
*)A(arg
))->c_oflag
) ||
178 __put_user (s
.c_cflag
, &((struct solaris_termios
*)A(arg
))->c_cflag
) ||
179 __put_user (s
.c_lflag
, &((struct solaris_termios
*)A(arg
))->c_lflag
) ||
180 __copy_from_user (s
.c_cc
, ((struct solaris_termios
*)A(arg
))->c_cc
, 16))
182 s
.c_cflag
= solaris_to_linux_cflag(s
.c_cflag
);
184 ret
= sys_ioctl(fd
, cmd
, (unsigned long)&s
);
189 static inline int solaris_T(unsigned int fd
, unsigned int cmd
, u32 arg
)
191 switch (cmd
& 0xff) {
193 return linux_to_solaris_termio(fd
, TCGETA
, arg
);
195 return solaris_to_linux_termio(fd
, TCSETA
, arg
);
196 case 3: /* TCSETAW */
197 return solaris_to_linux_termio(fd
, TCSETAW
, arg
);
198 case 4: /* TCSETAF */
199 return solaris_to_linux_termio(fd
, TCSETAF
, arg
);
201 return sys_ioctl(fd
, TCSBRK
, arg
);
203 return sys_ioctl(fd
, TCXONC
, arg
);
205 return sys_ioctl(fd
, TCFLSH
, arg
);
206 case 13: /* TCGETS */
207 return linux_to_solaris_termios(fd
, TCGETS
, arg
);
208 case 14: /* TCSETS */
209 return solaris_to_linux_termios(fd
, TCSETS
, arg
);
210 case 15: /* TCSETSW */
211 return solaris_to_linux_termios(fd
, TCSETSW
, arg
);
212 case 16: /* TCSETSF */
213 return solaris_to_linux_termios(fd
, TCSETSF
, arg
);
214 case 103: /* TIOCSWINSZ */
215 return sys_ioctl(fd
, TIOCSWINSZ
, arg
);
216 case 104: /* TIOCGWINSZ */
217 return sys_ioctl(fd
, TIOCGWINSZ
, arg
);
222 static inline int solaris_t(unsigned int fd
, unsigned int cmd
, u32 arg
)
224 switch (cmd
& 0xff) {
225 case 20: /* TIOCGPGRP */
226 return sys_ioctl(fd
, TIOCGPGRP
, arg
);
227 case 21: /* TIOCSPGRP */
228 return sys_ioctl(fd
, TIOCSPGRP
, arg
);
235 /* A pseudo STREAMS support {{{ */
238 int cmd
, timeout
, len
;
242 struct solaris_si_sockparams
{
248 struct solaris_o_si_udata
{
259 struct solaris_si_udata
{
268 struct solaris_si_sockparams sockparams
;
271 #define SOLARIS_MODULE_TIMOD 0
272 #define SOLARIS_MODULE_SOCKMOD 1
273 #define SOLARIS_MODULE_MAX 2
275 static struct module_info
{
277 /* can be expanded further if needed */
278 } module_table
[ SOLARIS_MODULE_MAX
+ 1 ] = {
279 /* the ordering here must match the module numbers above! */
285 static inline int solaris_sockmod(unsigned int fd
, unsigned int cmd
, u32 arg
)
288 /* I wonder which of these tests are superfluous... --patrik */
289 if (! current
->files
->fd
[fd
] ||
290 ! current
->files
->fd
[fd
]->f_dentry
||
291 ! (ino
= current
->files
->fd
[fd
]->f_dentry
->d_inode
) ||
295 switch (cmd
& 0xff) {
296 case 109: /* SI_SOCKPARAMS */
298 struct solaris_si_sockparams si
;
299 if (copy_from_user (&si
, (struct solaris_si_sockparams
*) A(arg
), sizeof(si
)))
300 return (EFAULT
<< 8) | TSYSERR
;
302 /* Should we modify socket ino->socket_i.ops and type? */
305 case 110: /* SI_GETUDATA */
307 int etsdusize
, servtype
;
308 switch (ino
->u
.socket_i
.type
) {
318 if (put_user(16384, &((struct solaris_si_udata
*)A(arg
))->tidusize
) ||
319 __put_user(sizeof(struct sockaddr
), &((struct solaris_si_udata
*)A(arg
))->addrsize
) ||
320 __put_user(-1, &((struct solaris_si_udata
*)A(arg
))->optsize
) ||
321 __put_user(etsdusize
, &((struct solaris_si_udata
*)A(arg
))->etsdusize
) ||
322 __put_user(servtype
, &((struct solaris_si_udata
*)A(arg
))->servtype
) ||
323 __put_user(0, &((struct solaris_si_udata
*)A(arg
))->so_state
) ||
324 __put_user(0, &((struct solaris_si_udata
*)A(arg
))->so_options
) ||
325 __put_user(16384, &((struct solaris_si_udata
*)A(arg
))->tsdusize
) ||
326 __put_user(ino
->u
.socket_i
.ops
->family
, &((struct solaris_si_udata
*)A(arg
))->sockparams
.sp_family
) ||
327 __put_user(ino
->u
.socket_i
.type
, &((struct solaris_si_udata
*)A(arg
))->sockparams
.sp_type
) ||
328 __put_user(ino
->u
.socket_i
.ops
->family
, &((struct solaris_si_udata
*)A(arg
))->sockparams
.sp_protocol
))
329 return (EFAULT
<< 8) | TSYSERR
;
332 case 101: /* O_SI_GETUDATA */
334 int etsdusize
, servtype
;
335 switch (ino
->u
.socket_i
.type
) {
345 if (put_user(16384, &((struct solaris_o_si_udata
*)A(arg
))->tidusize
) ||
346 __put_user(sizeof(struct sockaddr
), &((struct solaris_o_si_udata
*)A(arg
))->addrsize
) ||
347 __put_user(-1, &((struct solaris_o_si_udata
*)A(arg
))->optsize
) ||
348 __put_user(etsdusize
, &((struct solaris_o_si_udata
*)A(arg
))->etsdusize
) ||
349 __put_user(servtype
, &((struct solaris_o_si_udata
*)A(arg
))->servtype
) ||
350 __put_user(0, &((struct solaris_o_si_udata
*)A(arg
))->so_state
) ||
351 __put_user(0, &((struct solaris_o_si_udata
*)A(arg
))->so_options
) ||
352 __put_user(16384, &((struct solaris_o_si_udata
*)A(arg
))->tsdusize
))
353 return (EFAULT
<< 8) | TSYSERR
;
356 case 102: /* SI_SHUTDOWN */
357 case 103: /* SI_LISTEN */
358 case 104: /* SI_SETMYNAME */
359 case 105: /* SI_SETPEERNAME */
360 case 106: /* SI_GETINTRANSIT */
361 case 107: /* SI_TCL_LINK */
362 case 108: /* SI_TCL_UNLINK */
367 static inline int solaris_timod(unsigned int fd
, unsigned int cmd
, u32 arg
,
374 filp
= current
->files
->fd
[fd
];
376 ! (ino
= filp
->f_dentry
->d_inode
) ||
380 switch (cmd
& 0xff) {
381 case 141: /* TI_OPTMGMT */
385 SOLD("TI_OPMGMT entry");
386 ret
= timod_putmsg(fd
, (char *)A(arg
), len
, NULL
, -1, 0);
387 SOLD("timod_putmsg() returned");
389 return (-ret
<< 8) | TSYSERR
;
391 SOLD("calling timod_getmsg()");
392 ret
= timod_getmsg(fd
, (char *)A(arg
), len
, len_p
, NULL
, -1, NULL
, &i
);
393 SOLD("timod_getmsg() returned");
395 return (-ret
<< 8) | TSYSERR
;
397 if (get_user(prim
, (u32
*)A(arg
)))
398 return (EFAULT
<< 8) | TSYSERR
;
400 if (prim
== T_ERROR_ACK
) {
402 SOLD("prim is T_ERROR_ACK");
403 if (get_user(tmp
, (u32
*)A(arg
)+3) ||
404 get_user(tmp2
, (u32
*)A(arg
)+2))
405 return (EFAULT
<< 8) | TSYSERR
;
406 return (tmp2
<< 8) | tmp
;
408 SOLD("TI_OPMGMT return 0");
411 case 142: /* TI_BIND */
415 SOLD("TI_BIND entry");
416 ret
= timod_putmsg(fd
, (char *)A(arg
), len
, NULL
, -1, 0);
417 SOLD("timod_putmsg() returned");
419 return (-ret
<< 8) | TSYSERR
;
420 len
= 1024; /* Solaris allows arbitrary return size */
422 SOLD("calling timod_getmsg()");
423 ret
= timod_getmsg(fd
, (char *)A(arg
), len
, len_p
, NULL
, -1, NULL
, &i
);
424 SOLD("timod_getmsg() returned");
426 return (-ret
<< 8) | TSYSERR
;
428 if (get_user(prim
, (u32
*)A(arg
)))
429 return (EFAULT
<< 8) | TSYSERR
;
431 if (prim
== T_ERROR_ACK
) {
433 SOLD("prim is T_ERROR_ACK");
434 if (get_user(tmp
, (u32
*)A(arg
)+3) ||
435 get_user(tmp2
, (u32
*)A(arg
)+2))
436 return (EFAULT
<< 8) | TSYSERR
;
437 return (tmp2
<< 8) | tmp
;
439 SOLD("no ERROR_ACK requested");
440 if (prim
!= T_OK_ACK
)
442 SOLD("OK_ACK requested");
444 SOLD("calling timod_getmsg()");
445 ret
= timod_getmsg(fd
, (char *)A(arg
), len
, len_p
, NULL
, -1, NULL
, &i
);
446 SOLD("timod_getmsg() returned");
448 return (-ret
<< 8) | TSYSERR
;
449 SOLD("TI_BIND return ok");
452 case 140: /* TI_GETINFO */
453 case 143: /* TI_UNBIND */
454 case 144: /* TI_GETMYNAME */
455 case 145: /* TI_GETPEERNAME */
456 case 146: /* TI_SETMYNAME */
457 case 147: /* TI_SETPEERNAME */
462 static inline int solaris_S(unsigned int fd
, unsigned int cmd
, u32 arg
)
470 struct sol_socket_struct
*sock
;
471 struct module_info
*mi
;
473 filp
= current
->files
->fd
[fd
];
475 ! (ino
= filp
->f_dentry
->d_inode
) ||
478 sock
= filp
->private_data
;
480 printk("solaris_S: NULL private_data\n");
483 if (sock
->magic
!= SOLARIS_SOCKET_MAGIC
) {
484 printk("solaris_S: invalid magic\n");
489 switch (cmd
& 0xff) {
490 case 1: /* I_NREAD */
498 for (mi
= module_table
; mi
->name
; mi
++) {
499 if (strcmp(mi
->name
, p
) == 0) {
501 if (sock
->modcount
>= MAX_NR_STREAM_MODULES
) {
505 m
= (sol_module
) (mi
- module_table
);
506 sock
->module
[sock
->modcount
++] = m
;
515 if (sock
->modcount
<= 0) return -EINVAL
;
521 if (sock
->modcount
<= 0) return -EINVAL
;
522 p
= module_table
[(unsigned)sock
->module
[sock
->modcount
]].name
;
523 if (copy_to_user ((char *)A(arg
), p
, strlen(p
)))
527 case 5: /* I_FLUSH */
530 if (copy_from_user(&si
, (struct strioctl
*)A(arg
), sizeof(struct strioctl
)))
532 /* We ignore what module is actually at the top of stack. */
533 switch ((si
.cmd
>> 8) & 0xff) {
535 return solaris_sockmod(fd
, si
.cmd
, si
.data
);
537 return solaris_timod(fd
, si
.cmd
, si
.data
, si
.len
,
538 &((struct strioctl
*)A(arg
))->len
);
540 return solaris_ioctl(fd
, si
.cmd
, si
.data
);
542 case 9: /* I_SETSIG */
543 return sys_ioctl(fd
, FIOSETOWN
, current
->pid
);
544 case 10: /* I_GETSIG */
547 sys_ioctl(fd
, FIOGETOWN
, (unsigned long)&ret
);
549 if (ret
== current
->pid
) return 0x3ff;
551 case 11: /* I_FIND */
558 for (i
= 0; i
< sock
->modcount
; i
++) {
559 unsigned m
= sock
->module
[i
];
560 if (strcmp(module_table
[m
].name
, p
) == 0) {
568 case 19: /* I_SWROPT */
569 case 32: /* I_SETCLTIME */
575 static inline int solaris_s(unsigned int fd
, unsigned int cmd
, u32 arg
)
577 switch (cmd
& 0xff) {
578 case 0: /* SIOCSHIWAT */
579 case 2: /* SIOCSLOWAT */
580 return 0; /* We don't support them */
581 case 1: /* SIOCGHIWAT */
582 case 3: /* SIOCGLOWAT */
583 if (put_user (0, (u32
*)A(arg
)))
586 case 7: /* SIOCATMARK */
587 return sys_ioctl(fd
, SIOCATMARK
, arg
);
588 case 8: /* SIOCSPGRP */
589 return sys_ioctl(fd
, SIOCSPGRP
, arg
);
590 case 9: /* SIOCGPGRP */
591 return sys_ioctl(fd
, SIOCGPGRP
, arg
);
596 static inline int solaris_r(unsigned int fd
, unsigned int cmd
, u32 arg
)
598 switch (cmd
& 0xff) {
599 case 10: /* SIOCADDRT */
600 return sys32_ioctl(fd
, SIOCADDRT
, arg
);
601 case 11: /* SIOCDELRT */
602 return sys32_ioctl(fd
, SIOCDELRT
, arg
);
607 static inline int solaris_i(unsigned int fd
, unsigned int cmd
, u32 arg
)
609 switch (cmd
& 0xff) {
610 case 12: /* SIOCSIFADDR */
611 return sys32_ioctl(fd
, SIOCSIFADDR
, arg
);
612 case 13: /* SIOCGIFADDR */
613 return sys32_ioctl(fd
, SIOCGIFADDR
, arg
);
614 case 14: /* SIOCSIFDSTADDR */
615 return sys32_ioctl(fd
, SIOCSIFDSTADDR
, arg
);
616 case 15: /* SIOCGIFDSTADDR */
617 return sys32_ioctl(fd
, SIOCGIFDSTADDR
, arg
);
618 case 16: /* SIOCSIFFLAGS */
619 return sys32_ioctl(fd
, SIOCSIFFLAGS
, arg
);
620 case 17: /* SIOCGIFFLAGS */
621 return sys32_ioctl(fd
, SIOCGIFFLAGS
, arg
);
622 case 18: /* SIOCSIFMEM */
623 return sys32_ioctl(fd
, SIOCSIFMEM
, arg
);
624 case 19: /* SIOCGIFMEM */
625 return sys32_ioctl(fd
, SIOCGIFMEM
, arg
);
626 case 20: /* SIOCGIFCONF */
627 return sys32_ioctl(fd
, SIOCGIFCONF
, arg
);
628 case 21: /* SIOCSIFMTU */
629 return sys32_ioctl(fd
, SIOCSIFMTU
, arg
);
630 case 22: /* SIOCGIFMTU */
631 return sys32_ioctl(fd
, SIOCGIFMTU
, arg
);
632 case 23: /* SIOCGIFBRDADDR */
633 return sys32_ioctl(fd
, SIOCGIFBRDADDR
, arg
);
634 case 24: /* SIOCSIFBRDADDR */
635 return sys32_ioctl(fd
, SIOCSIFBRDADDR
, arg
);
636 case 25: /* SIOCGIFNETMASK */
637 return sys32_ioctl(fd
, SIOCGIFNETMASK
, arg
);
638 case 26: /* SIOCSIFNETMASK */
639 return sys32_ioctl(fd
, SIOCSIFNETMASK
, arg
);
640 case 27: /* SIOCGIFMETRIC */
641 return sys32_ioctl(fd
, SIOCGIFMETRIC
, arg
);
642 case 28: /* SIOCSIFMETRIC */
643 return sys32_ioctl(fd
, SIOCSIFMETRIC
, arg
);
644 case 30: /* SIOCSARP */
645 return sys32_ioctl(fd
, SIOCSARP
, arg
);
646 case 31: /* SIOCGARP */
647 return sys32_ioctl(fd
, SIOCGARP
, arg
);
648 case 32: /* SIOCDARP */
649 return sys32_ioctl(fd
, SIOCDARP
, arg
);
650 case 52: /* SIOCGETNAME */
651 case 53: /* SIOCGETPEER */
653 struct sockaddr uaddr
;
654 int uaddr_len
= sizeof(struct sockaddr
), ret
;
656 mm_segment_t old_fs
= get_fs();
657 int (*sys_socketcall
)(int, unsigned long *) =
658 (int (*)(int, unsigned long *))SYS(socketcall
);
660 args
[0] = fd
; args
[1] = (long)&uaddr
; args
[2] = (long)&uaddr_len
;
662 ret
= sys_socketcall(((cmd
& 0xff) == 52) ? SYS_GETSOCKNAME
: SYS_GETPEERNAME
,
666 if (copy_to_user((char *)A(arg
), &uaddr
, uaddr_len
))
672 case 86: /* SIOCSOCKSYS */
673 return socksys_syscall(fd
, arg
);
675 case 87: /* SIOCGIFNUM */
680 read_lock_bh(&dev_base_lock
);
681 for (d
= dev_base
; d
; d
= d
->next
) i
++;
682 read_unlock_bh(&dev_base_lock
);
684 if (put_user (i
, (int *)A(arg
)))
694 asmlinkage
int solaris_ioctl(unsigned int fd
, unsigned int cmd
, u32 arg
)
705 switch ((cmd
>> 8) & 0xff) {
706 case 'S': error
= solaris_S(fd
, cmd
, arg
); break;
707 case 'T': error
= solaris_T(fd
, cmd
, arg
); break;
708 case 'i': error
= solaris_i(fd
, cmd
, arg
); break;
709 case 'r': error
= solaris_r(fd
, cmd
, arg
); break;
710 case 's': error
= solaris_s(fd
, cmd
, arg
); break;
711 case 't': error
= solaris_t(fd
, cmd
, arg
); break;
712 case 'f': error
= sys_ioctl(fd
, cmd
, arg
); break;
718 if (error
== -ENOSYS
) {
719 unsigned char c
= cmd
>>8;
721 if (c
< ' ' || c
> 126) c
= '.';
722 printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n",
723 (int)fd
, (unsigned int)cmd
, c
, (unsigned int)arg
);