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