patch-2.1.97 linux/arch/sparc64/solaris/ioctl.c
Next file: linux/arch/sparc64/solaris/misc.c
Previous file: linux/arch/sparc64/solaris/fs.c
Back to the patch index
Back to the overall index
- Lines: 434
- Date:
Tue Apr 14 17:44:21 1998
- Orig file:
v2.1.96/linux/arch/sparc64/solaris/ioctl.c
- Orig date:
Mon Jan 12 15:15:44 1998
diff -u --recursive --new-file v2.1.96/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c
@@ -1,7 +1,8 @@
-/* $Id: ioctl.c,v 1.4 1997/09/18 10:38:24 rth Exp $
+/* $Id: ioctl.c,v 1.10 1998/03/29 10:11:00 davem Exp $
* ioctl.c: Solaris ioctl emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
*
* Streams & timod emulation based on code
* Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
@@ -15,14 +16,16 @@
#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/netdevice.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
#include "conv.h"
+#include "socksys.h"
-extern char * getname32(u32 filename);
+extern char *getname32(u32 filename);
#define putname32 putname
extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
@@ -31,6 +34,11 @@
u32 arg);
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+extern int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
+ char *data_buf, int data_len, int flags);
+extern int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, int *ctl_len,
+ char *data_buf, int data_maxlen, int *data_len, int *flags);
+
/* termio* stuff {{{ */
struct solaris_termios {
@@ -231,31 +239,303 @@
u32 data;
};
+struct solaris_si_sockparams {
+ int sp_family;
+ int sp_type;
+ int sp_protocol;
+};
+
+struct solaris_o_si_udata {
+ int tidusize;
+ int addrsize;
+ int optsize;
+ int etsdusize;
+ int servtype;
+ int so_state;
+ int so_options;
+ int tsdusize;
+};
+
+struct solaris_si_udata {
+ int tidusize;
+ int addrsize;
+ int optsize;
+ int etsdusize;
+ int servtype;
+ int so_state;
+ int so_options;
+ int tsdusize;
+ struct solaris_si_sockparams sockparams;
+};
+
+#define SOLARIS_MODULE_TIMOD 0
+#define SOLARIS_MODULE_SOCKMOD 1
+#define SOLARIS_MODULE_MAX 2
+
+static struct module_info {
+ const char *name;
+ /* can be expanded further if needed */
+} module_table[ SOLARIS_MODULE_MAX + 1 ] = {
+ /* the ordering here must match the module numbers above! */
+ { "timod" },
+ { "sockmod" },
+ { NULL }
+};
+
+static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct inode *ino;
+ /* I wonder which of these tests are superfluous... --patrik */
+ if (! current->files->fd[fd] ||
+ ! current->files->fd[fd]->f_dentry ||
+ ! (ino = current->files->fd[fd]->f_dentry->d_inode) ||
+ ! ino->i_sock)
+ return TBADF;
+
+ switch (cmd & 0xff) {
+ case 109: /* SI_SOCKPARAMS */
+ {
+ struct solaris_si_sockparams si;
+ if (copy_from_user (&si, (struct solaris_si_sockparams *) A(arg), sizeof(si)))
+ return (EFAULT << 8) | TSYSERR;
+
+ /* Should we modify socket ino->socket_i.ops and type? */
+ return 0;
+ }
+ case 110: /* SI_GETUDATA */
+ {
+ int etsdusize, servtype;
+ switch (ino->u.socket_i.type) {
+ case SOCK_STREAM:
+ etsdusize = 1;
+ servtype = 2;
+ break;
+ default:
+ etsdusize = -2;
+ servtype = 3;
+ break;
+ }
+ if (put_user(16384, &((struct solaris_si_udata *)A(arg))->tidusize) ||
+ __put_user(sizeof(struct sockaddr), &((struct solaris_si_udata *)A(arg))->addrsize) ||
+ __put_user(-1, &((struct solaris_si_udata *)A(arg))->optsize) ||
+ __put_user(etsdusize, &((struct solaris_si_udata *)A(arg))->etsdusize) ||
+ __put_user(servtype, &((struct solaris_si_udata *)A(arg))->servtype) ||
+ __put_user(0, &((struct solaris_si_udata *)A(arg))->so_state) ||
+ __put_user(0, &((struct solaris_si_udata *)A(arg))->so_options) ||
+ __put_user(16384, &((struct solaris_si_udata *)A(arg))->tsdusize) ||
+ __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_family) ||
+ __put_user(ino->u.socket_i.type, &((struct solaris_si_udata *)A(arg))->sockparams.sp_type) ||
+ __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_protocol))
+ return (EFAULT << 8) | TSYSERR;
+ return 0;
+ }
+ case 101: /* O_SI_GETUDATA */
+ {
+ int etsdusize, servtype;
+ switch (ino->u.socket_i.type) {
+ case SOCK_STREAM:
+ etsdusize = 1;
+ servtype = 2;
+ break;
+ default:
+ etsdusize = -2;
+ servtype = 3;
+ break;
+ }
+ if (put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tidusize) ||
+ __put_user(sizeof(struct sockaddr), &((struct solaris_o_si_udata *)A(arg))->addrsize) ||
+ __put_user(-1, &((struct solaris_o_si_udata *)A(arg))->optsize) ||
+ __put_user(etsdusize, &((struct solaris_o_si_udata *)A(arg))->etsdusize) ||
+ __put_user(servtype, &((struct solaris_o_si_udata *)A(arg))->servtype) ||
+ __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_state) ||
+ __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_options) ||
+ __put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tsdusize))
+ return (EFAULT << 8) | TSYSERR;
+ return 0;
+ }
+ case 102: /* SI_SHUTDOWN */
+ case 103: /* SI_LISTEN */
+ case 104: /* SI_SETMYNAME */
+ case 105: /* SI_SETPEERNAME */
+ case 106: /* SI_GETINTRANSIT */
+ case 107: /* SI_TCL_LINK */
+ case 108: /* SI_TCL_UNLINK */
+ }
+ return TNOTSUPPORT;
+}
+
+static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
+ int len, int *len_p)
+{
+ struct file *filp;
+ struct inode *ino;
+ int ret;
+
+ filp = current->files->fd[fd];
+ if (! filp ||
+ ! (ino = filp->f_dentry->d_inode) ||
+ ! ino->i_sock)
+ return TBADF;
+
+ switch (cmd & 0xff) {
+ case 141: /* TI_OPTMGMT */
+ {
+ int i;
+ u32 prim;
+ SOLD("TI_OPMGMT entry");
+ ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
+ SOLD("timod_putmsg() returned");
+ if (ret)
+ return (-ret << 8) | TSYSERR;
+ i = MSG_HIPRI;
+ SOLD("calling timod_getmsg()");
+ ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+ SOLD("timod_getmsg() returned");
+ if (ret)
+ return (-ret << 8) | TSYSERR;
+ SOLD("ret ok");
+ if (get_user(prim, (u32 *)A(arg)))
+ return (EFAULT << 8) | TSYSERR;
+ SOLD("got prim");
+ if (prim == T_ERROR_ACK) {
+ u32 tmp, tmp2;
+ SOLD("prim is T_ERROR_ACK");
+ if (get_user(tmp, (u32 *)A(arg)+3) ||
+ get_user(tmp2, (u32 *)A(arg)+2))
+ return (EFAULT << 8) | TSYSERR;
+ return (tmp2 << 8) | tmp;
+ }
+ SOLD("TI_OPMGMT return 0");
+ return 0;
+ }
+ case 142: /* TI_BIND */
+ {
+ int i;
+ u32 prim;
+ SOLD("TI_BIND entry");
+ ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
+ SOLD("timod_putmsg() returned");
+ if (ret)
+ return (-ret << 8) | TSYSERR;
+ len = 1024; /* Solaris allows arbitrary return size */
+ i = MSG_HIPRI;
+ SOLD("calling timod_getmsg()");
+ ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+ SOLD("timod_getmsg() returned");
+ if (ret)
+ return (-ret << 8) | TSYSERR;
+ SOLD("ret ok");
+ if (get_user(prim, (u32 *)A(arg)))
+ return (EFAULT << 8) | TSYSERR;
+ SOLD("got prim");
+ if (prim == T_ERROR_ACK) {
+ u32 tmp, tmp2;
+ SOLD("prim is T_ERROR_ACK");
+ if (get_user(tmp, (u32 *)A(arg)+3) ||
+ get_user(tmp2, (u32 *)A(arg)+2))
+ return (EFAULT << 8) | TSYSERR;
+ return (tmp2 << 8) | tmp;
+ }
+ SOLD("no ERROR_ACK requested");
+ if (prim != T_OK_ACK)
+ return TBADSEQ;
+ SOLD("OK_ACK requested");
+ i = MSG_HIPRI;
+ SOLD("calling timod_getmsg()");
+ ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+ SOLD("timod_getmsg() returned");
+ if (ret)
+ return (-ret << 8) | TSYSERR;
+ SOLD("TI_BIND return ok");
+ return 0;
+ }
+ case 140: /* TI_GETINFO */
+ case 143: /* TI_UNBIND */
+ case 144: /* TI_GETMYNAME */
+ case 145: /* TI_GETPEERNAME */
+ case 146: /* TI_SETMYNAME */
+ case 147: /* TI_SETPEERNAME */
+ }
+ return TNOTSUPPORT;
+}
+
static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
{
char *p;
int ret;
mm_segment_t old_fs;
struct strioctl si;
-
+ struct inode *ino;
+ struct file *filp;
+ struct sol_socket_struct *sock;
+ struct module_info *mi;
+
+ filp = current->files->fd[fd];
+ if (! filp ||
+ ! (ino = filp->f_dentry->d_inode) ||
+ ! ino->i_sock)
+ return -EBADF;
+ sock = filp->private_data;
+ if (! sock) {
+ printk("solaris_S: NULL private_data\n");
+ return -EBADF;
+ }
+ if (sock->magic != SOLARIS_SOCKET_MAGIC) {
+ printk("solaris_S: invalid magic\n");
+ return -EBADF;
+ }
+
+
switch (cmd & 0xff) {
case 1: /* I_NREAD */
return -ENOSYS;
case 2: /* I_PUSH */
+ {
p = getname32 (arg);
if (IS_ERR (p))
return PTR_ERR(p);
+ ret = -EINVAL;
+ for (mi = module_table; mi->name; mi++) {
+ if (strcmp(mi->name, p) == 0) {
+ sol_module m;
+ if (sock->modcount >= MAX_NR_STREAM_MODULES) {
+ ret = -ENXIO;
+ break;
+ }
+ m = (sol_module) (mi - module_table);
+ sock->module[sock->modcount++] = m;
+ ret = 0;
+ break;
+ }
+ }
putname32 (p);
- return 0;
+ return ret;
+ }
case 3: /* I_POP */
+ if (sock->modcount <= 0) return -EINVAL;
+ sock->modcount--;
return 0;
+ case 4: /* I_LOOK */
+ {
+ const char *p;
+ if (sock->modcount <= 0) return -EINVAL;
+ p = module_table[(unsigned)sock->module[sock->modcount]].name;
+ if (copy_to_user ((char *)A(arg), p, strlen(p)))
+ return -EFAULT;
+ return 0;
+ }
case 5: /* I_FLUSH */
return 0;
case 8: /* I_STR */
- if (copy_from_user (&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
+ if (copy_from_user(&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
return -EFAULT;
+ /* We ignore what module is actually at the top of stack. */
switch ((si.cmd >> 8) & 0xff) {
+ case 'I':
+ return solaris_sockmod(fd, si.cmd, si.data);
case 'T':
+ return solaris_timod(fd, si.cmd, si.data, si.len,
+ &((struct strioctl*)A(arg))->len);
default:
return solaris_ioctl(fd, si.cmd, si.data);
}
@@ -269,12 +549,25 @@
if (ret == current->pid) return 0x3ff;
else return -EINVAL;
case 11: /* I_FIND */
+ {
+ int i;
p = getname32 (arg);
if (IS_ERR (p))
return PTR_ERR(p);
- ret = !strcmp(p, "timod");
+ ret = 0;
+ for (i = 0; i < sock->modcount; i++) {
+ unsigned m = sock->module[i];
+ if (strcmp(module_table[m].name, p) == 0) {
+ ret = 1;
+ break;
+ }
+ }
putname32 (p);
return ret;
+ }
+ case 19: /* I_SWROPT */
+ case 32: /* I_SETCLTIME */
+ return 0; /* Lie */
}
return -ENOSYS;
}
@@ -287,7 +580,8 @@
return 0; /* We don't support them */
case 1: /* SIOCGHIWAT */
case 3: /* SIOCGLOWAT */
- put_user_ret (0, (u32 *)A(arg), -EFAULT);
+ if (put_user (0, (u32 *)A(arg)))
+ return -EFAULT;
return 0; /* Lie */
case 7: /* SIOCATMARK */
return sys_ioctl(fd, SIOCATMARK, arg);
@@ -368,8 +662,10 @@
ret = sys_socketcall(((cmd & 0xff) == 52) ? SYS_GETSOCKNAME : SYS_GETPEERNAME,
args);
set_fs(old_fs);
- if (ret >= 0)
- copy_to_user_ret((char *)A(arg), &uaddr, uaddr_len, -EFAULT);
+ if (ret >= 0) {
+ if (copy_to_user((char *)A(arg), &uaddr, uaddr_len))
+ return -EFAULT;
+ }
return ret;
}
#if 0
@@ -382,7 +678,8 @@
int i = 0;
for (d = dev_base; d; d = d->next) i++;
- put_user_ret (i, (int *)A(arg), -EFAULT);
+ if (put_user (i, (int *)A(arg)))
+ return -EFAULT;
return 0;
}
}
@@ -393,14 +690,13 @@
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
- struct file * filp;
+ struct file *filp;
int error = -EBADF;
lock_kernel();
- if(fd >= NR_OPEN) goto out;
-
- filp = current->files->fd[fd];
- if(!filp) goto out;
+ filp = fcheck(fd);
+ if (!filp)
+ goto out;
error = -EFAULT;
switch ((cmd >> 8) & 0xff) {
@@ -410,6 +706,7 @@
case 'r': error = solaris_r(fd, cmd, arg); break;
case 's': error = solaris_s(fd, cmd, arg); break;
case 't': error = solaris_t(fd, cmd, arg); break;
+ case 'f': error = sys_ioctl(fd, cmd, arg); break;
default:
error = -ENOSYS;
break;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov