Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
b835996f | 27 | #include <linux/rcupdate.h> |
1da177e4 LT |
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; | |
badf1662 | 297 | struct fdtable *fdt; |
1da177e4 | 298 | /* I wonder which of these tests are superfluous... --patrik */ |
b835996f | 299 | rcu_read_lock(); |
badf1662 DS |
300 | fdt = files_fdtable(current->files); |
301 | if (! fdt->fd[fd] || | |
1250ca4c JS |
302 | ! fdt->fd[fd]->f_path.dentry || |
303 | ! (ino = fdt->fd[fd]->f_path.dentry->d_inode) || | |
1da177e4 | 304 | ! S_ISSOCK(ino->i_mode)) { |
b835996f | 305 | rcu_read_unlock(); |
1da177e4 LT |
306 | return TBADF; |
307 | } | |
b835996f | 308 | rcu_read_unlock(); |
1da177e4 LT |
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 | ||
1250ca4c | 483 | ino = filp->f_path.dentry->d_inode; |
1da177e4 LT |
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); | |
7562f876 PE |
689 | for_each_netdev(d) |
690 | i++; | |
1da177e4 LT |
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 | } |