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