ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / sparc64 / solaris / ioctl.c
1 /* $Id: ioctl.c,v 1.17 2002/02/08 03:57:14 davem Exp $
2  * ioctl.c: Solaris ioctl emulation.
3  *
4  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  * Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
6  *
7  * Streams & timod emulation based on code
8  * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
9  *
10  * 1999-08-19 Implemented solaris 'm' (mag tape) and
11  *            'O' (openprom) ioctls, by Jason Rappleye
12  *             (rappleye@ccr.buffalo.edu)
13  */
14
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/smp.h>
19 #include <linux/smp_lock.h>
20 #include <linux/syscalls.h>
21 #include <linux/ioctl.h>
22 #include <linux/fs.h>
23 #include <linux/file.h>
24 #include <linux/netdevice.h>
25 #include <linux/mtio.h>
26 #include <linux/time.h>
27 #include <linux/compat.h>
28
29 #include <net/sock.h>
30
31 #include <asm/uaccess.h>
32 #include <asm/termios.h>
33 #include <asm/openpromio.h>
34
35 #include "conv.h"
36 #include "socksys.h"
37
38 extern asmlinkage int compat_sys_ioctl(unsigned int fd, unsigned int cmd,
39         u32 arg);
40 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
41
42 extern int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
43                         char *data_buf, int data_len, int flags);
44 extern int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, int *ctl_len,
45                         char *data_buf, int data_maxlen, int *data_len, int *flags);
46
47 /* termio* stuff {{{ */
48
49 struct solaris_termios {
50         u32     c_iflag;
51         u32     c_oflag;
52         u32     c_cflag;
53         u32     c_lflag;
54         u8      c_cc[19];
55 };
56
57 struct solaris_termio {
58         u16     c_iflag;
59         u16     c_oflag;
60         u16     c_cflag;
61         u16     c_lflag;
62         s8      c_line;
63         u8      c_cc[8];
64 };
65
66 struct solaris_termiox {
67         u16     x_hflag;
68         u16     x_cflag;
69         u16     x_rflag[5];
70         u16     x_sflag;
71 };
72
73 static u32 solaris_to_linux_cflag(u32 cflag)
74 {
75         cflag &= 0x7fdff000;
76         if (cflag & 0x200000) {
77                 int baud = cflag & 0xf;
78                 cflag &= ~0x20000f;
79                 switch (baud) {
80                 case 0: baud = B57600; break;
81                 case 1: baud = B76800; break;
82                 case 2: baud = B115200; break;
83                 case 3: baud = B153600; break;
84                 case 4: baud = B230400; break;
85                 case 5: baud = B307200; break;
86                 case 6: baud = B460800; break;
87                 }
88                 cflag |= CBAUDEX | baud;
89         }
90         return cflag;
91 }
92
93 static u32 linux_to_solaris_cflag(u32 cflag)
94 {
95         cflag &= ~(CMSPAR | CIBAUD);
96         if (cflag & CBAUDEX) {
97                 int baud = cflag & CBAUD;
98                 cflag &= ~CBAUD;
99                 switch (baud) {
100                 case B57600: baud = 0; break;
101                 case B76800: baud = 1; break;
102                 case B115200: baud = 2; break;
103                 case B153600: baud = 3; break;
104                 case B230400: baud = 4; break;
105                 case B307200: baud = 5; break;
106                 case B460800: baud = 6; break;
107                 case B614400: baud = 7; break;
108                 case B921600: baud = 8; break;
109 #if 0           
110                 case B1843200: baud = 9; break;
111 #endif
112                 }
113                 cflag |= 0x200000 | baud;
114         }
115         return cflag;
116 }
117
118 static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg)
119 {
120         int ret;
121         
122         ret = sys_ioctl(fd, cmd, A(arg));
123         if (!ret) {
124                 u32 cflag;
125                 
126                 if (__get_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
127                         return -EFAULT;
128                 cflag = linux_to_solaris_cflag(cflag);
129                 if (__put_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
130                         return -EFAULT;
131         }
132         return ret;
133 }
134
135 static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg)
136 {
137         int ret;
138         struct solaris_termio s;
139         mm_segment_t old_fs = get_fs();
140         
141         if (copy_from_user (&s, (struct solaris_termio *)A(arg), sizeof(struct solaris_termio)))
142                 return -EFAULT;
143         s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
144         set_fs(KERNEL_DS);
145         ret = sys_ioctl(fd, cmd, (unsigned long)&s);
146         set_fs(old_fs);
147         return ret;
148 }
149
150 static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg)
151 {
152         int ret;
153         struct solaris_termios s;
154         mm_segment_t old_fs = get_fs();
155
156         set_fs(KERNEL_DS);      
157         ret = sys_ioctl(fd, cmd, (unsigned long)&s);
158         set_fs(old_fs);
159         if (!ret) {
160                 if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
161                     __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
162                     __put_user (linux_to_solaris_cflag(s.c_cflag), &((struct solaris_termios *)A(arg))->c_cflag) ||
163                     __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
164                     __copy_to_user (((struct solaris_termios *)A(arg))->c_cc, s.c_cc, 16) ||
165                     __clear_user (((struct solaris_termios *)A(arg))->c_cc + 16, 2))
166                         return -EFAULT;
167         }
168         return ret;
169 }
170
171 static int solaris_to_linux_termios(unsigned int fd, unsigned int cmd, u32 arg)
172 {
173         int ret;
174         struct solaris_termios s;
175         mm_segment_t old_fs = get_fs();
176
177         set_fs(KERNEL_DS);
178         ret = sys_ioctl(fd, TCGETS, (unsigned long)&s);
179         set_fs(old_fs);
180         if (ret) return ret;
181         if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
182             __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
183             __put_user (s.c_cflag, &((struct solaris_termios *)A(arg))->c_cflag) ||
184             __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
185             __copy_from_user (s.c_cc, ((struct solaris_termios *)A(arg))->c_cc, 16))
186                 return -EFAULT;
187         s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
188         set_fs(KERNEL_DS);
189         ret = sys_ioctl(fd, cmd, (unsigned long)&s);
190         set_fs(old_fs);
191         return ret;
192 }
193
194 static inline int solaris_T(unsigned int fd, unsigned int cmd, u32 arg)
195 {
196         switch (cmd & 0xff) {
197         case 1: /* TCGETA */
198                 return linux_to_solaris_termio(fd, TCGETA, arg);
199         case 2: /* TCSETA */
200                 return solaris_to_linux_termio(fd, TCSETA, arg);
201         case 3: /* TCSETAW */
202                 return solaris_to_linux_termio(fd, TCSETAW, arg);
203         case 4: /* TCSETAF */
204                 return solaris_to_linux_termio(fd, TCSETAF, arg);
205         case 5: /* TCSBRK */
206                 return sys_ioctl(fd, TCSBRK, arg);
207         case 6: /* TCXONC */
208                 return sys_ioctl(fd, TCXONC, arg);
209         case 7: /* TCFLSH */
210                 return sys_ioctl(fd, TCFLSH, arg);
211         case 13: /* TCGETS */
212                 return linux_to_solaris_termios(fd, TCGETS, arg);
213         case 14: /* TCSETS */
214                 return solaris_to_linux_termios(fd, TCSETS, arg);
215         case 15: /* TCSETSW */
216                 return solaris_to_linux_termios(fd, TCSETSW, arg);
217         case 16: /* TCSETSF */
218                 return solaris_to_linux_termios(fd, TCSETSF, arg);
219         case 103: /* TIOCSWINSZ */
220                 return sys_ioctl(fd, TIOCSWINSZ, arg);
221         case 104: /* TIOCGWINSZ */
222                 return sys_ioctl(fd, TIOCGWINSZ, arg);
223         }
224         return -ENOSYS;
225 }
226
227 static inline int solaris_t(unsigned int fd, unsigned int cmd, u32 arg)
228 {
229         switch (cmd & 0xff) {
230         case 20: /* TIOCGPGRP */
231                 return sys_ioctl(fd, TIOCGPGRP, arg);
232         case 21: /* TIOCSPGRP */
233                 return sys_ioctl(fd, TIOCSPGRP, arg);
234         }
235         return -ENOSYS;
236 }
237
238 /* }}} */
239
240 /* A pseudo STREAMS support {{{ */
241
242 struct strioctl {
243         int cmd, timeout, len;
244         u32 data;
245 };
246
247 struct solaris_si_sockparams {
248         int sp_family;
249         int sp_type;
250         int sp_protocol;
251 };
252
253 struct solaris_o_si_udata {
254         int tidusize;
255         int addrsize;
256         int optsize;
257         int etsdusize;
258         int servtype;
259         int so_state;
260         int so_options;
261         int tsdusize;
262 };
263
264 struct solaris_si_udata {
265         int tidusize;
266         int addrsize;
267         int optsize;
268         int etsdusize;
269         int servtype;
270         int so_state;
271         int so_options;
272         int tsdusize;
273         struct solaris_si_sockparams sockparams;
274 };
275
276 #define SOLARIS_MODULE_TIMOD    0
277 #define SOLARIS_MODULE_SOCKMOD  1
278 #define SOLARIS_MODULE_MAX      2
279
280 static struct module_info {
281         const char *name;
282         /* can be expanded further if needed */
283 } module_table[ SOLARIS_MODULE_MAX + 1 ] = {
284         /* the ordering here must match the module numbers above! */
285         { "timod" },
286         { "sockmod" },
287         { NULL }
288 };
289
290 static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
291 {
292         struct inode *ino;
293         /* I wonder which of these tests are superfluous... --patrik */
294         spin_lock(&current->files->file_lock);
295         if (! current->files->fd[fd] ||
296             ! current->files->fd[fd]->f_dentry ||
297             ! (ino = current->files->fd[fd]->f_dentry->d_inode) ||
298             ! ino->i_sock) {
299                 spin_unlock(&current->files->file_lock);
300                 return TBADF;
301         }
302         spin_unlock(&current->files->file_lock);
303         
304         switch (cmd & 0xff) {
305         case 109: /* SI_SOCKPARAMS */
306         {
307                 struct solaris_si_sockparams si;
308                 if (copy_from_user (&si, (struct solaris_si_sockparams *) A(arg), sizeof(si)))
309                         return (EFAULT << 8) | TSYSERR;
310
311                 /* Should we modify socket ino->socket_i.ops and type? */
312                 return 0;
313         }
314         case 110: /* SI_GETUDATA */
315         {
316                 int etsdusize, servtype;
317                 switch (SOCKET_I(ino)->type) {
318                 case SOCK_STREAM:
319                         etsdusize = 1;
320                         servtype = 2;
321                         break;
322                 default:
323                         etsdusize = -2;
324                         servtype = 3;
325                         break;
326                 }
327                 if (put_user(16384, &((struct solaris_si_udata *)A(arg))->tidusize) ||
328                     __put_user(sizeof(struct sockaddr), &((struct solaris_si_udata *)A(arg))->addrsize) ||
329                     __put_user(-1, &((struct solaris_si_udata *)A(arg))->optsize) ||
330                     __put_user(etsdusize, &((struct solaris_si_udata *)A(arg))->etsdusize) ||
331                     __put_user(servtype, &((struct solaris_si_udata *)A(arg))->servtype) ||
332                     __put_user(0, &((struct solaris_si_udata *)A(arg))->so_state) ||
333                     __put_user(0, &((struct solaris_si_udata *)A(arg))->so_options) ||
334                     __put_user(16384, &((struct solaris_si_udata *)A(arg))->tsdusize) ||
335                     __put_user(SOCKET_I(ino)->ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_family) ||
336                     __put_user(SOCKET_I(ino)->type, &((struct solaris_si_udata *)A(arg))->sockparams.sp_type) ||
337                     __put_user(SOCKET_I(ino)->ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_protocol))
338                         return (EFAULT << 8) | TSYSERR;
339                 return 0;
340         }
341         case 101: /* O_SI_GETUDATA */
342         {
343                 int etsdusize, servtype;
344                 switch (SOCKET_I(ino)->type) {
345                 case SOCK_STREAM:
346                         etsdusize = 1;
347                         servtype = 2;
348                         break;
349                 default:
350                         etsdusize = -2;
351                         servtype = 3;
352                         break;
353                 }
354                 if (put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tidusize) ||
355                     __put_user(sizeof(struct sockaddr), &((struct solaris_o_si_udata *)A(arg))->addrsize) ||
356                     __put_user(-1, &((struct solaris_o_si_udata *)A(arg))->optsize) ||
357                     __put_user(etsdusize, &((struct solaris_o_si_udata *)A(arg))->etsdusize) ||
358                     __put_user(servtype, &((struct solaris_o_si_udata *)A(arg))->servtype) ||
359                     __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_state) ||
360                     __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_options) ||
361                     __put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tsdusize))
362                         return (EFAULT << 8) | TSYSERR;
363                 return 0;
364         }
365         case 102: /* SI_SHUTDOWN */
366         case 103: /* SI_LISTEN */
367         case 104: /* SI_SETMYNAME */
368         case 105: /* SI_SETPEERNAME */
369         case 106: /* SI_GETINTRANSIT */
370         case 107: /* SI_TCL_LINK */
371         case 108: /* SI_TCL_UNLINK */
372                 ;
373         }
374         return TNOTSUPPORT;
375 }
376
377 static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
378                                     int len, int *len_p)
379 {
380         int ret;
381                 
382         switch (cmd & 0xff) {
383         case 141: /* TI_OPTMGMT */
384         {
385                 int i;
386                 u32 prim;
387                 SOLD("TI_OPMGMT entry");
388                 ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
389                 SOLD("timod_putmsg() returned");
390                 if (ret)
391                         return (-ret << 8) | TSYSERR;
392                 i = MSG_HIPRI;
393                 SOLD("calling timod_getmsg()");
394                 ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
395                 SOLD("timod_getmsg() returned");
396                 if (ret)
397                         return (-ret << 8) | TSYSERR;
398                 SOLD("ret ok");
399                 if (get_user(prim, (u32 *)A(arg)))
400                         return (EFAULT << 8) | TSYSERR;
401                 SOLD("got prim");
402                 if (prim == T_ERROR_ACK) {
403                         u32 tmp, tmp2;
404                         SOLD("prim is T_ERROR_ACK");
405                         if (get_user(tmp, (u32 *)A(arg)+3) ||
406                             get_user(tmp2, (u32 *)A(arg)+2))
407                                 return (EFAULT << 8) | TSYSERR;
408                         return (tmp2 << 8) | tmp;
409                 }
410                 SOLD("TI_OPMGMT return 0");
411                 return 0;
412         }
413         case 142: /* TI_BIND */
414         {
415                 int i;
416                 u32 prim;
417                 SOLD("TI_BIND entry");
418                 ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
419                 SOLD("timod_putmsg() returned");
420                 if (ret)
421                         return (-ret << 8) | TSYSERR;
422                 len = 1024; /* Solaris allows arbitrary return size */
423                 i = MSG_HIPRI;
424                 SOLD("calling timod_getmsg()");
425                 ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
426                 SOLD("timod_getmsg() returned");
427                 if (ret)
428                         return (-ret << 8) | TSYSERR;
429                 SOLD("ret ok");
430                 if (get_user(prim, (u32 *)A(arg)))
431                         return (EFAULT << 8) | TSYSERR;
432                 SOLD("got prim");
433                 if (prim == T_ERROR_ACK) {
434                         u32 tmp, tmp2;
435                         SOLD("prim is T_ERROR_ACK");
436                         if (get_user(tmp, (u32 *)A(arg)+3) ||
437                             get_user(tmp2, (u32 *)A(arg)+2))
438                                 return (EFAULT << 8) | TSYSERR;
439                         return (tmp2 << 8) | tmp;
440                 }
441                 SOLD("no ERROR_ACK requested");
442                 if (prim != T_OK_ACK)
443                         return TBADSEQ;
444                 SOLD("OK_ACK requested");
445                 i = MSG_HIPRI;
446                 SOLD("calling timod_getmsg()");
447                 ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
448                 SOLD("timod_getmsg() returned");
449                 if (ret)
450                         return (-ret << 8) | TSYSERR;
451                 SOLD("TI_BIND return ok");
452                 return 0;
453         }
454         case 140: /* TI_GETINFO */
455         case 143: /* TI_UNBIND */
456         case 144: /* TI_GETMYNAME */
457         case 145: /* TI_GETPEERNAME */
458         case 146: /* TI_SETMYNAME */
459         case 147: /* TI_SETPEERNAME */
460                 ;
461         }
462         return TNOTSUPPORT;
463 }
464
465 static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd, u32 arg)
466 {
467         char *p;
468         int ret;
469         mm_segment_t old_fs;
470         struct strioctl si;
471         struct inode *ino;
472         struct sol_socket_struct *sock;
473         struct module_info *mi;
474
475         ino = filp->f_dentry->d_inode;
476         if (! ino->i_sock)
477                 return -EBADF;
478         sock = filp->private_data;
479         if (! sock) {
480                 printk("solaris_S: NULL private_data\n");
481                 return -EBADF;
482         }
483         if (sock->magic != SOLARIS_SOCKET_MAGIC) {
484                 printk("solaris_S: invalid magic\n");
485                 return -EBADF;
486         }
487         
488
489         switch (cmd & 0xff) {
490         case 1: /* I_NREAD */
491                 return -ENOSYS;
492         case 2: /* I_PUSH */
493         {
494                 p = getname ((char *)A(arg));
495                 if (IS_ERR (p))
496                         return PTR_ERR(p);
497                 ret = -EINVAL;
498                 for (mi = module_table; mi->name; mi++) {
499                         if (strcmp(mi->name, p) == 0) {
500                                 sol_module m;
501                                 if (sock->modcount >= MAX_NR_STREAM_MODULES) {
502                                         ret = -ENXIO;
503                                         break;
504                                 }
505                                 m = (sol_module) (mi - module_table);
506                                 sock->module[sock->modcount++] = m;
507                                 ret = 0;
508                                 break;
509                         }
510                 }
511                 putname (p);
512                 return ret;
513         }
514         case 3: /* I_POP */
515                 if (sock->modcount <= 0) return -EINVAL;
516                 sock->modcount--;
517                 return 0;
518         case 4: /* I_LOOK */
519         {
520                 const char *p;
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)))
524                         return -EFAULT;
525                 return 0;
526         }
527         case 5: /* I_FLUSH */
528                 return 0;
529         case 8: /* I_STR */
530                 if (copy_from_user(&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
531                         return -EFAULT;
532                 /* We ignore what module is actually at the top of stack. */
533                 switch ((si.cmd >> 8) & 0xff) {
534                 case 'I':
535                         return solaris_sockmod(fd, si.cmd, si.data);
536                 case 'T':
537                         return solaris_timod(fd, si.cmd, si.data, si.len,
538                                                 &((struct strioctl*)A(arg))->len);
539                 default:
540                         return solaris_ioctl(fd, si.cmd, si.data);
541                 }
542         case 9: /* I_SETSIG */
543                 return sys_ioctl(fd, FIOSETOWN, current->pid);
544         case 10: /* I_GETSIG */
545                 old_fs = get_fs();
546                 set_fs(KERNEL_DS);
547                 sys_ioctl(fd, FIOGETOWN, (unsigned long)&ret);
548                 set_fs(old_fs);
549                 if (ret == current->pid) return 0x3ff;
550                 else return -EINVAL;
551         case 11: /* I_FIND */
552         {
553                 int i;
554                 p = getname ((char *)A(arg));
555                 if (IS_ERR (p))
556                         return PTR_ERR(p);
557                 ret = 0;
558                 for (i = 0; i < sock->modcount; i++) {
559                         unsigned m = sock->module[i];
560                         if (strcmp(module_table[m].name, p) == 0) {
561                                 ret = 1;
562                                 break;
563                         } 
564                 }
565                 putname (p);
566                 return ret;
567         }
568         case 19: /* I_SWROPT */
569         case 32: /* I_SETCLTIME */
570                 return 0;       /* Lie */
571         }
572         return -ENOSYS;
573 }
574
575 static inline int solaris_s(unsigned int fd, unsigned int cmd, u32 arg)
576 {
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)))
584                         return -EFAULT;
585                 return 0; /* Lie */
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);
592         }
593         return -ENOSYS;
594 }
595
596 static inline int solaris_r(unsigned int fd, unsigned int cmd, u32 arg)
597 {
598         switch (cmd & 0xff) {
599         case 10: /* SIOCADDRT */
600                 return compat_sys_ioctl(fd, SIOCADDRT, arg);
601         case 11: /* SIOCDELRT */
602                 return compat_sys_ioctl(fd, SIOCDELRT, arg);
603         }
604         return -ENOSYS;
605 }
606
607 static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
608 {
609         switch (cmd & 0xff) {
610         case 12: /* SIOCSIFADDR */
611                 return compat_sys_ioctl(fd, SIOCSIFADDR, arg);
612         case 13: /* SIOCGIFADDR */
613                 return compat_sys_ioctl(fd, SIOCGIFADDR, arg);
614         case 14: /* SIOCSIFDSTADDR */
615                 return compat_sys_ioctl(fd, SIOCSIFDSTADDR, arg);
616         case 15: /* SIOCGIFDSTADDR */
617                 return compat_sys_ioctl(fd, SIOCGIFDSTADDR, arg);
618         case 16: /* SIOCSIFFLAGS */
619                 return compat_sys_ioctl(fd, SIOCSIFFLAGS, arg);
620         case 17: /* SIOCGIFFLAGS */
621                 return compat_sys_ioctl(fd, SIOCGIFFLAGS, arg);
622         case 18: /* SIOCSIFMEM */
623                 return compat_sys_ioctl(fd, SIOCSIFMEM, arg);
624         case 19: /* SIOCGIFMEM */
625                 return compat_sys_ioctl(fd, SIOCGIFMEM, arg);
626         case 20: /* SIOCGIFCONF */
627                 return compat_sys_ioctl(fd, SIOCGIFCONF, arg);
628         case 21: /* SIOCSIFMTU */
629                 return compat_sys_ioctl(fd, SIOCSIFMTU, arg);
630         case 22: /* SIOCGIFMTU */
631                 return compat_sys_ioctl(fd, SIOCGIFMTU, arg);
632         case 23: /* SIOCGIFBRDADDR */
633                 return compat_sys_ioctl(fd, SIOCGIFBRDADDR, arg);
634         case 24: /* SIOCSIFBRDADDR */
635                 return compat_sys_ioctl(fd, SIOCSIFBRDADDR, arg);
636         case 25: /* SIOCGIFNETMASK */
637                 return compat_sys_ioctl(fd, SIOCGIFNETMASK, arg);
638         case 26: /* SIOCSIFNETMASK */
639                 return compat_sys_ioctl(fd, SIOCSIFNETMASK, arg);
640         case 27: /* SIOCGIFMETRIC */
641                 return compat_sys_ioctl(fd, SIOCGIFMETRIC, arg);
642         case 28: /* SIOCSIFMETRIC */
643                 return compat_sys_ioctl(fd, SIOCSIFMETRIC, arg);
644         case 30: /* SIOCSARP */
645                 return compat_sys_ioctl(fd, SIOCSARP, arg);
646         case 31: /* SIOCGARP */
647                 return compat_sys_ioctl(fd, SIOCGARP, arg);
648         case 32: /* SIOCDARP */
649                 return compat_sys_ioctl(fd, SIOCDARP, arg);
650         case 52: /* SIOCGETNAME */
651         case 53: /* SIOCGETPEER */
652                 {
653                         struct sockaddr uaddr;
654                         int uaddr_len = sizeof(struct sockaddr), ret;
655                         long args[3];
656                         mm_segment_t old_fs = get_fs();
657                         int (*sys_socketcall)(int, unsigned long *) =
658                                 (int (*)(int, unsigned long *))SYS(socketcall);
659                         
660                         args[0] = fd; args[1] = (long)&uaddr; args[2] = (long)&uaddr_len;
661                         set_fs(KERNEL_DS);
662                         ret = sys_socketcall(((cmd & 0xff) == 52) ? SYS_GETSOCKNAME : SYS_GETPEERNAME,
663                                         args);
664                         set_fs(old_fs);
665                         if (ret >= 0) {
666                                 if (copy_to_user((char *)A(arg), &uaddr, uaddr_len))
667                                         return -EFAULT;
668                         }
669                         return ret;
670                 }
671 #if 0           
672         case 86: /* SIOCSOCKSYS */
673                 return socksys_syscall(fd, arg);
674 #endif          
675         case 87: /* SIOCGIFNUM */
676                 {
677                         struct net_device *d;
678                         int i = 0;
679                         
680                         read_lock_bh(&dev_base_lock);
681                         for (d = dev_base; d; d = d->next) i++;
682                         read_unlock_bh(&dev_base_lock);
683
684                         if (put_user (i, (int *)A(arg)))
685                                 return -EFAULT;
686                         return 0;
687                 }
688         }
689         return -ENOSYS;
690 }
691
692 static int solaris_m(unsigned int fd, unsigned int cmd, u32 arg)
693 {
694         int ret;
695
696         switch (cmd & 0xff) {
697         case 1: /* MTIOCTOP */
698                 ret = sys_ioctl(fd, MTIOCTOP, (unsigned long)&arg);
699                 break;
700         case 2: /* MTIOCGET */
701                 ret = sys_ioctl(fd, MTIOCGET, (unsigned long)&arg);
702                 break;
703         case 3: /* MTIOCGETDRIVETYPE */
704         case 4: /* MTIOCPERSISTENT */
705         case 5: /* MTIOCPERSISTENTSTATUS */
706         case 6: /* MTIOCLRERR */
707         case 7: /* MTIOCGUARANTEEDORDER */
708         case 8: /* MTIOCRESERVE */
709         case 9: /* MTIOCRELEASE */
710         case 10: /* MTIOCFORCERESERVE */
711         case 13: /* MTIOCSTATE */
712         case 14: /* MTIOCREADIGNOREILI */
713         case 15: /* MTIOCREADIGNOREEOFS */
714         case 16: /* MTIOCSHORTFMK */
715         default:
716                 ret = -ENOSYS; /* linux doesn't support these */
717                 break;
718         };
719
720         return ret;
721 }
722
723 static int solaris_O(unsigned int fd, unsigned int cmd, u32 arg)
724 {
725         int ret = -EINVAL;
726
727         switch (cmd & 0xff) {
728         case 1: /* OPROMGETOPT */
729                 ret = sys_ioctl(fd, OPROMGETOPT, arg);
730                 break;
731         case 2: /* OPROMSETOPT */
732                 ret = sys_ioctl(fd, OPROMSETOPT, arg);
733                 break;
734         case 3: /* OPROMNXTOPT */
735                 ret = sys_ioctl(fd, OPROMNXTOPT, arg);
736                 break;
737         case 4: /* OPROMSETOPT2 */
738                 ret = sys_ioctl(fd, OPROMSETOPT2, arg);
739                 break;
740         case 5: /* OPROMNEXT */
741                 ret = sys_ioctl(fd, OPROMNEXT, arg);
742                 break;
743         case 6: /* OPROMCHILD */
744                 ret = sys_ioctl(fd, OPROMCHILD, arg);
745                 break;
746         case 7: /* OPROMGETPROP */
747                 ret = sys_ioctl(fd, OPROMGETPROP, arg);
748                 break;
749         case 8: /* OPROMNXTPROP */
750                 ret = sys_ioctl(fd, OPROMNXTPROP, arg);
751                 break;
752         case 9: /* OPROMU2P */
753                 ret = sys_ioctl(fd, OPROMU2P, arg);
754                 break;
755         case 10: /* OPROMGETCONS */
756                 ret = sys_ioctl(fd, OPROMGETCONS, arg);
757                 break;
758         case 11: /* OPROMGETFBNAME */
759                 ret = sys_ioctl(fd, OPROMGETFBNAME, arg);
760                 break;
761         case 12: /* OPROMGETBOOTARGS */
762                 ret = sys_ioctl(fd, OPROMGETBOOTARGS, arg);
763                 break;
764         case 13: /* OPROMGETVERSION */
765         case 14: /* OPROMPATH2DRV */
766         case 15: /* OPROMDEV2PROMNAME */
767         case 16: /* OPROMPROM2DEVNAME */
768         case 17: /* OPROMGETPROPLEN */
769         default:
770                 ret = -EINVAL;
771                 break;
772         };
773         return ret;
774 }
775
776 /* }}} */
777
778 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
779 {
780         struct file *filp;
781         int error = -EBADF;
782
783         filp = fget(fd);
784         if (!filp)
785                 goto out;
786
787         lock_kernel();
788         error = -EFAULT;
789         switch ((cmd >> 8) & 0xff) {
790         case 'S': error = solaris_S(filp, fd, cmd, arg); break;
791         case 'T': error = solaris_T(fd, cmd, arg); break;
792         case 'i': error = solaris_i(fd, cmd, arg); break;
793         case 'r': error = solaris_r(fd, cmd, arg); break;
794         case 's': error = solaris_s(fd, cmd, arg); break;
795         case 't': error = solaris_t(fd, cmd, arg); break;
796         case 'f': error = sys_ioctl(fd, cmd, arg); break;
797         case 'm': error = solaris_m(fd, cmd, arg); break;
798         case 'O': error = solaris_O(fd, cmd, arg); break;
799         default:
800                 error = -ENOSYS;
801                 break;
802         }
803         unlock_kernel();
804         fput(filp);
805 out:
806         if (error == -ENOSYS) {
807                 unsigned char c = cmd>>8;
808                 
809                 if (c < ' ' || c > 126) c = '.';
810                 printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n",
811                        (int)fd, (unsigned int)cmd, c, (unsigned int)arg);
812                 error = -EINVAL;
813         }
814         return error;
815 }