freebsd-nq/sys/i386/ibcs2/ibcs2_socksys.c
1995-05-30 08:16:23 +00:00

1394 lines
31 KiB
C

/*-
* Copyright (c) 1994 Mostyn Lewis
* All rights reserved.
*
* This software is based on code which is:
* Copyright (c) 1994 Mike Jagdis (jaggy@purplet.demon.co.uk)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ibcs2_socksys.c,v 1.2 1994/10/17 22:13:08 sos Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/filedesc.h>
#include <sys/file.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <sys/proc.h>
#include <sys/exec.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
#include <sys/malloc.h>
#include <sys/un.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <vm/vm.h>
#include <i386/ibcs2/ibcs2.h>
#include <i386/ibcs2/ibcs2_socksys.h>
/* Socksys pseudo driver entry points */
int sockopen (dev_t dev, int mode, int devtype, struct proc *p);
int sockioctl(dev_t dev, int cmd, caddr_t arg, int fflag, struct proc *p);
int sockclose(dev_t dev, int flag, int mode, struct proc *p);
/* Socksys internal functions */
static void put_socket_fops(struct proc *p, int fd);
static int ss_fop_close(struct file *fp, struct proc *p);
static int ss_fop_ioctl(struct file*fp, int cmd, caddr_t arg, struct proc *p);
static int ss_syscall(caddr_t arg, struct proc *p);
/*
* This structure is setup on first usage. Its address is planted
* into a socket's file structure fileops pointer after a successful
* socket creation or accept.
*/
static struct fileops ss_socket_fops = {
NULL, /* normal socket read */
NULL, /* normal socket write */
NULL, /* socksys ioctl */
NULL, /* normal socket select */
NULL, /* socksys close */
};
static int (*close_s)__P((struct file *fp, struct proc *p));
static int (*ioctl_s)__P((struct file *fp, int cmd, caddr_t data, struct proc *p));
int ss_debug = 10;
static int
ss_syscall(arg, p)
caddr_t arg;
struct proc *p;
{
int cmd;
int error;
int retval[2];
retval[0] = retval[1] = 0;
cmd = ((struct ss_call *)arg)->arg[0];
if(ss_debug) {
static char *ss_syscall_strings[] = {
"0?", "accept", "bind", "connect", "getpeername",
"getsockname", "getsockopt", "listen", "recv(from)",
"recvfrom", "send(to)", "sendto", "setsockopt", "shutdown",
"socket", "select", "getipdomain", "setipdomain",
"adjtime", "setreuid", "setregid", "gettimeofday",
"settimeofday", "getitimer", "setitimer",
};
printf("ss_syscall: [%d] ",p->p_pid);
if(cmd < 0 || (cmd > CMD_SO_SETITIMER && cmd != CMD_SO_SS_DEBUG) )
printf("? ");
else {
if(cmd == CMD_SO_SS_DEBUG)
printf("%s ","ss_debug");
else
printf("%s ",ss_syscall_strings[cmd]);
}
printf("(%d) <0x%x,0x%x,0x%x,0x%x,0x%x,0x%x>\n",
cmd,
((struct ss_call *)arg)->arg[1],
((struct ss_call *)arg)->arg[2],
((struct ss_call *)arg)->arg[3],
((struct ss_call *)arg)->arg[4],
((struct ss_call *)arg)->arg[5],
((struct ss_call *)arg)->arg[6]);
}
error = 0;
switch (cmd) {
case CMD_SO_SS_DEBUG:
/* ss_debug = ((struct ss_call *)arg)->arg[1]; */
break;
case CMD_SO_SOCKET: { /* NO CONV */
if(ss_debug > 1)
printf("SO_SOCKET af in %d\n",
((struct ss_call *)arg)->arg[1]);
((struct ss_call *)arg)->arg[1] = ss_convert(
af_whatevers,
&(((struct ss_call *)arg)->arg[1]),
0);
if(ss_debug > 1) {
printf("SO_SOCKET af out %d\n",
((struct ss_call *)arg)->arg[1]);
printf("SO_SOCKET type in %d\n",
((struct ss_call *)arg)->arg[2]);
}
((struct ss_call *)arg)->arg[2] = ss_convert(
type_whatevers,
&(((struct ss_call *)arg)->arg[2]),
0);
if(ss_debug > 1)
printf("SO_SOCKET type out %d\n",
((struct ss_call *)arg)->arg[2]);
SYSCALL(SYS_socket, 0, 0);
if(ss_debug)
printf("ss_syscall: [%d] socket fd=%d\n",
p->p_pid, retval[0]);
put_socket_fops(p,retval[0]);
break;
}
case CMD_SO_ACCEPT: { /* CONVERSION in arg 2 */
SYSCALL(SYS_accept, 2, SS_STRUCT_SOCKADDR);
if(ss_debug)
printf("ss_syscall: [%d] accept fd=%d\n",
p->p_pid, retval[0]);
put_socket_fops(p,retval[0]);
break;
}
case CMD_SO_BIND:
SYSCALL(SYS_bind, 2, SS_STRUCT_SOCKADDR);
break;
case CMD_SO_CONNECT: {
struct alien_sockaddr *sa;
unsigned short family;
/* Remap any INADDR_ANY (0.0.0.0) to localhost */
sa = (struct alien_sockaddr *)((struct ss_call *)arg)->arg[1];
if(error = copyin((caddr_t)&sa->sa_family,
(caddr_t)&family, sizeof(short)))
return(error);
if (family == AF_INET) {
unsigned long *addr;
unsigned long saddr;
addr = &(((struct alien_sockaddr_in *)sa)->sin_addr.s_addr);
if(error = copyin((caddr_t)addr, (caddr_t)&saddr, sizeof(long)))
return(error);
if (saddr == INADDR_ANY) {
/* 0x0100007f is 127.0.0.1 reversed */
saddr = 0x0100007f;
if(error = copyout((caddr_t)&saddr,
(caddr_t)addr, sizeof(long)))
return(error);
if (ss_debug)
printf("ss_syscall: remapped INADDR_ANY to localhost\n");
}
}
SYSCALL(SYS_connect, 2, SS_STRUCT_SOCKADDR);
break;
}
case CMD_SO_GETPEERNAME:
SYSCALL(SYS_getpeername, 2, SS_STRUCT_SOCKADDR);
break;
case CMD_SO_GETSOCKNAME:
SYSCALL(SYS_getsockname, 2, SS_STRUCT_SOCKADDR);
break;
case CMD_SO_GETSOCKOPT:
if(error = ss_getsockopt((caddr_t)(((int *)arg) + 1),retval,p))
return(error);
break;
case CMD_SO_LISTEN:
SYSCALL(SYS_listen, 0, 0);
break;
case CMD_SO_RECV:
((struct ss_call *)arg)->arg[5] = (int)((struct sockaddr *)NULL);
((struct ss_call *)arg)->arg[6] = 0;
SYSCALL(SYS_recvfrom, 0, 0);
break;
case CMD_SO_RECVFROM:
SYSCALL(SYS_recvfrom, 5, SS_STRUCT_SOCKADDR);
break;
case CMD_SO_SEND:
((struct ss_call *)arg)->arg[5] = (int)((struct sockaddr *)NULL);
((struct ss_call *)arg)->arg[6] = 0;
SYSCALL(SYS_sendto, 0, 0);
break;
case CMD_SO_SENDTO:
SYSCALL(SYS_sendto, 5, SS_STRUCT_SOCKADDR);
break;
case CMD_SO_SETSOCKOPT:
if(error = ss_setsockopt((caddr_t)(((int *)arg) + 1),retval,p))
return(error);
case CMD_SO_SHUTDOWN:
SYSCALL(SYS_shutdown, 0, 0);
break;
case CMD_SO_GETIPDOMAIN:
SYSCALL(SYS_getdomainname, 0, 0);
break;
case CMD_SO_SETIPDOMAIN: /* Note check on BSD utsname no change? */
SYSCALL(SYS_setdomainname, 0, 0);
break;
case CMD_SO_SETREUID:
SYSCALL(126/*SYS_setreuid*/, 0, 0);
break;
case CMD_SO_SETREGID:
SYSCALL(127/*SYS_setregid*/, 0, 0);
break;
case CMD_SO_GETTIME:
SYSCALL(SYS_gettimeofday, 0, 0);
break;
case CMD_SO_SETTIME:
SYSCALL(SYS_settimeofday, 0, 0);
break;
case CMD_SO_GETITIMER:
SYSCALL(SYS_getitimer, 0, 0);
break;
case CMD_SO_SETITIMER:
SYSCALL(SYS_setitimer, 0, 0);
break;
case CMD_SO_SELECT:
SYSCALL(SYS_select, 0, 0);
break;
case CMD_SO_ADJTIME:
SYSCALL(SYS_adjtime, 0, 0);
break;
default:
printf("ss_syscall: default 0x%x\n",cmd);
return (EINVAL);
}
IBCS2_MAGIC_RETURN(arg);
}
static int
ss_fop_ioctl(fp, cmd, arg, p)
struct file *fp;
int cmd;
caddr_t arg;
struct proc *p;
{
int error;
int retval[2];
if(ss_debug) {
static char **ioctl_strings;
int fd;
struct filedesc *fdp;
unsigned int ioctl_type;
unsigned int ioctl_len;
char cmd_type;
int cmd_ordinal;
static char *ioctl_type_strings[] = {
"0?", "SS_IO", "SS_IOR", "3?", "SS_IOW", "5?", "SS_IOWR"
};
static char *ioctl_S_strings[] = {
"0?", "SIOCSHIWAT", "SIOCGHIWAT", "SIOCSLOWAT", "SIOCGLOWAT",
"SIOCATMARK", "SIOCSPGRP", "SIOCGPGRP", "FIONREAD",
"FIONBIO", "FIOASYNC", "SIOCPROTO", "SIOCGETNAME",
"SIOCGETPEER", "IF_UNITSEL", "SIOCXPROTO"
};
static char *ioctl_R_strings[] = {
"0?", "1?", "2?", "3?", "4?", "5?", "6?", "7?", "8?",
"SIOCADDRT", "SIOCDELRT"
};
static char *ioctl_I_strings[] = {
"0?", "1?", "2?", "3?", "4?", "5?", "6?", "7?", "8?",
"9?", "10?", "SIOCSIFADDR", "SIOCGIFADDR", "SIOCSIFDSTADDR",
"SIOCGIFDSTADDR", "SIOCSIFFLAGS", "SIOCGIFFLAGS",
"SIOCGIFCONF", "18?", "19?", "20?", "SIOCSIFMTU",
"SIOCGIFMTU", "23?", "24?", "25?", "SIOCIFDETACH",
"SIOCGENPSTATS", "28?", "SIOCX25XMT", "SS_SIOCX25RCV",
"SS_SIOCX25TBL", "SIOCGIFBRDADDR" ,"SIOCSIFBRDADDR",
"SIOCGIFNETMASK", "SIOCSIFNETMASK", "SIOCGIFMETRIC",
"SIOCSIFMETRIC", "SIOCSARP", "SIOCGARP", "SIOCDARP",
"SIOCSIFNAME", "SIOCGIFONEP", "SIOCSIFONEP ",
"44?", "45?", "46?", "47?", "48?", "49?", "50?", "51?",
"52?", "53?", "54?", "55?", "56?", "57?", "58?", "59?",
"60?", "61?", "62?", "63?", "64?", "SIOCGENADDR",
"SIOCSOCKSYS"
};
cmd_type = (cmd >> 8) & 0xff;
cmd_ordinal = cmd & 0xff;
switch (cmd_type) {
case 'S':
ioctl_strings = ioctl_S_strings;
if (cmd_ordinal > 15)
cmd_ordinal = -1;
break;
case 'R':
ioctl_strings = ioctl_R_strings;
if (cmd_ordinal > 10)
cmd_ordinal = -1;
break;
case 'I':
ioctl_strings = ioctl_I_strings;
if (cmd_ordinal > 66)
cmd_ordinal = -1;
break;
default:
cmd_type = '?';
break;
}
fdp = p->p_fd;
fd = -1;
while(++fd < NOFILE)
if ( fp == fdp->fd_ofiles[fd] )
break;
ioctl_type = (0xe0000000 & cmd) >> 29;
ioctl_len = (cmd >> 16) & SS_IOCPARM_MASK;
printf("ss_fop_ioctl: [%d] fd=%d ",p->p_pid, fd);
if(cmd_type != '?'){
if(cmd_ordinal != -1)
printf("%s %s('%c',%d,l=%d) ",ioctl_strings[cmd_ordinal],
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
else {
cmd_ordinal = cmd & 0xff;
printf("[unknown ordinal %d] %s('%c',%d,l=%d) ",cmd_ordinal,
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
}
}
else {
printf("? %s('%c',%d,l=%d) ",
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
}
printf("0x%x (0x%x) <0x%x>\n",
fp, cmd, arg);
}
/* No dogs allowed */
if(*(((int *)arg) - 3) != IBCS2_MAGIC_IN){
printf("ss_fop_ioctl: bad magic (sys_generic.c has no socksys mods?)\n");
return(EINVAL);
}
if(fp->f_type != DTYPE_SOCKET)
return (ENOTSOCK);
retval[0] = retval[1] = 0;
error = 0;
switch (cmd) {
case SS_SIOCSOCKSYS: /* ss syscall */
return ss_syscall(arg, p);
case SS_SIOCSHIWAT: /* set high watermark */
case SS_SIOCSLOWAT: /* set low watermark */
break; /* return value of 0 and no error */
case SS_SIOCGHIWAT: /* get high watermark */
case SS_SIOCGLOWAT: /* get low watermark */
break; /* return value of 0 and no error */
case SS_SIOCATMARK: /* at oob mark */
IOCTL(SIOCATMARK);
break;
case SS_SIOCSPGRP: /* set process group */
IOCTL(SIOCSPGRP);
break;
case SS_SIOCGPGRP: /* get process group */
IOCTL(SIOCGPGRP);
break;
case FIONREAD:
case SS_FIONREAD: /* get # bytes to read */
IOCTL(FIONREAD);
break;
case SS_FIONBIO: /* set/clear non-blocking i/o */
IOCTL(FIONBIO);
break;
case SS_FIOASYNC: /* set/clear async i/o */
IOCTL(FIOASYNC);
break;
case SS_SIOCADDRT: /* add route - uses struct ortentry */
IOCTL(SIOCADDRT);
break;
case SS_SIOCDELRT: /* delete route - uses struct ortentry */
IOCTL(SIOCDELRT);
break;
case SS_SIOCSIFADDR: /* set ifnet address */
IOCTL(SIOCSIFADDR);
break;
case SS_SIOCGIFADDR: /* get ifnet address */
IOCTL(SIOCGIFADDR);
break;
case SS_SIOCSIFDSTADDR: /* set p-p address */
IOCTL(SIOCSIFDSTADDR);
break;
case SS_SIOCGIFDSTADDR: /* get p-p address */
IOCTL(SIOCGIFDSTADDR);
break;
case SS_SIOCSIFFLAGS: /* set ifnet flags */
IOCTL(SIOCSIFFLAGS);
break;
case SS_SIOCGIFFLAGS: /* get ifnet flags */
IOCTL(SIOCGIFFLAGS);
break;
case SS_SIOCGIFCONF: /* get ifnet ltst */
IOCTL(SIOCGIFCONF);
break;
case SS_SIOCGIFBRDADDR: /* get broadcast addr */
IOCTL(SIOCGIFBRDADDR);
break;
case SS_SIOCSIFBRDADDR: /* set broadcast addr */
IOCTL(SIOCSIFBRDADDR);
break;
case SS_SIOCGIFNETMASK: /* get net addr mask */
IOCTL(SIOCGIFNETMASK);
break;
case SS_SIOCSIFNETMASK: /* set net addr mask */
IOCTL(SIOCSIFNETMASK);
break;
case SS_SIOCGIFMETRIC: /* get IF metric */
IOCTL(SIOCGIFMETRIC);
break;
case SS_SIOCSIFMETRIC: /* set IF metric */
IOCTL(SIOCSIFMETRIC);
break;
/* FreeBSD 2.0 does not have socket ARPs */
#ifdef SIOCSARP
case SS_SIOCSARP: /* set arp entry */
IOCTL(SIOCSARP);
break;
case SS_SIOCGARP: /* get arp entry */
IOCTL(SIOCGARP);
break;
case SS_SIOCDARP: /* delete arp entry */
IOCTL(SIOCDARP);
break;
#else /* SIOCSARP */
case SS_SIOCSARP: /* set arp entry */
return(EINVAL);
case SS_SIOCGARP: /* get arp entry */
return(EINVAL);
case SS_SIOCDARP: /* delete arp entry */
return(EINVAL);
#endif /* SIOCSARP */
case SS_SIOCGENADDR: /* Get ethernet addr XXX */
return (EINVAL);
/* return (error = ioctl_s(fp, SIOCGIFHWADDR, arg, p)); */
case SS_SIOCSIFMTU: /* get if_mtu */
IOCTL(SIOCSIFMTU);
break;
case SS_SIOCGIFMTU: /* set if_mtu */
IOCTL(SIOCGIFMTU);
break;
case SS_SIOCGETNAME: /* getsockname XXX */
return (EINVAL);
/* return (ioctl_s(fp, SIOCGIFNAME, arg, p)); MMM */
case SS_SIOCGETPEER: { /* getpeername */
struct moose {
int fd;
caddr_t asa;
int *alen;
int compat_43;
} args;
struct alien_sockaddr uaddr;
struct sockaddr nuaddr;
int nuaddr_len = sizeof(struct sockaddr);
struct filedesc *fdp;
if(fp->f_type != DTYPE_SOCKET)
return (ENOTSOCK);
bzero((caddr_t)&nuaddr, sizeof(struct sockaddr));
fdp = p->p_fd;
args.fd = -1;
while(++args.fd < NOFILE)
if ( fp == fdp->fd_ofiles[args.fd] )
break;
if(args.fd == NOFILE){
printf("ss_fop_ioctl: [%d] SS_SIOCGETPEER args.fd > NOFILE\n", p->p_pid);
return(EBADF);
}
args.asa = (caddr_t)&nuaddr;
args.alen = &nuaddr_len;
args.compat_43 = 0;
error = SYSCALLX(SYS_getpeername, &args);
if(error)
return(error);
bzero((caddr_t)&uaddr, sizeof(struct alien_sockaddr));
uaddr.sa_family = (unsigned short)nuaddr.sa_family;
bcopy(&nuaddr.sa_data, &uaddr.sa_data, __ALIEN_SOCK_SIZE__ - sizeof(unsigned short));
error = copyout((caddr_t)&uaddr, (caddr_t)arg, sizeof(struct alien_sockaddr));
return error;
}
default:
printf("ss_fop_ioctl: [%d] %lx unknown ioctl 0x%x, 0x%lx\n",
p->p_pid, (unsigned long)fp,
cmd, (unsigned long)arg);
return (EINVAL);
}
IBCS2_MAGIC_RETURN(arg);
}
int
sockioctl(dev, cmd, arg, fflag, p)
dev_t dev;
int cmd;
caddr_t arg;
int fflag;
struct proc *p;
{
int error;
int retval[2];
if(ss_debug) {
char cmd_type;
int cmd_ordinal;
static char **ioctl_strings;
unsigned int ioctl_type;
unsigned int ioctl_len;
static char *ioctl_type_strings[] = {
"NIOCxx", "SS_IO", "SS_IOR", "3?", "SS_IOW", "5?", "SS_IOWR"
};
static char *ioctl_S_strings[] = {
"0?", "SIOCSHIWAT", "SIOCGHIWAT", "SIOCSLOWAT", "SIOCGLOWAT",
"SIOCATMARK", "SIOCSPGRP", "SIOCGPGRP", "FIONREAD",
"FIONBIO", "FIOASYNC", "SIOCPROTO", "SIOCGETNAME",
"SIOCGETPEER", "IF_UNITSEL", "SIOCXPROTO"
};
static char *ioctl_R_strings[] = {
"0?", "1?", "2?", "3?", "4?", "5?", "6?", "7?", "8?",
"SIOCADDRT", "SIOCDELRT"
};
static char *ioctl_I_strings[] = {
"0?", "1?", "2?", "3?", "4?", "5?", "6?", "7?", "8?",
"9?", "10?", "SIOCSIFADDR", "SIOCGIFADDR", "SIOCSIFDSTADDR",
"SIOCGIFDSTADDR", "SIOCSIFFLAGS", "SIOCGIFFLAGS",
"SIOCGIFCONF", "18?", "19?", "20?", "SIOCSIFMTU",
"SIOCGIFMTU", "23?", "24?", "25?", "SIOCIFDETACH",
"SIOCGENPSTATS", "28?", "SIOCX25XMT", "SS_SIOCX25RCV",
"SS_SIOCX25TBL", "SIOCGIFBRDADDR" ,"SIOCSIFBRDADDR",
"SIOCGIFNETMASK", "SIOCSIFNETMASK", "SIOCGIFMETRIC",
"SIOCSIFMETRIC", "SIOCSARP", "SIOCGARP", "SIOCDARP",
"SIOCSIFNAME", "SIOCGIFONEP", "SIOCSIFONEP ",
"44?", "45?", "46?", "47?", "48?", "49?", "50?", "51?",
"52?", "53?", "54?", "55?", "56?", "57?", "58?", "59?",
"60?", "61?", "62?", "63?", "64?", "SIOCGENADDR",
"SIOCSOCKSYS"
};
static char *ioctl_NIOC_strings[] = {
"0?", "NIOCNFSD", "NIOCOLDGETFH", "NIOCASYNCD",
"NIOCSETDOMNAM", "NIOCGETDOMNAM", "NIOCCLNTHAND",
"NIOCEXPORTFS", "NIOCGETFH", "NIOCLSTAT"
};
cmd_ordinal = cmd & 0xff;
cmd_type = (cmd >> 8) & 0xff;
switch (cmd_type) {
case 0:
ioctl_strings = ioctl_NIOC_strings;
cmd_type = ' ';
if (cmd_ordinal > 9)
cmd_ordinal = -1;
break;
case 'S':
ioctl_strings = ioctl_S_strings;
if (cmd_ordinal > 15)
cmd_ordinal = -1;
break;
case 'R':
ioctl_strings = ioctl_R_strings;
if (cmd_ordinal > 10)
cmd_ordinal = -1;
break;
case 'I':
ioctl_strings = ioctl_I_strings;
if (cmd_ordinal > 66)
cmd_ordinal = -1;
break;
default:
cmd_type = '?';
break;
}
ioctl_type = (0xe0000000 & cmd) >> 29;
ioctl_len = (cmd >> 16) & SS_IOCPARM_MASK;
printf("sockioctl: [%d] ",p->p_pid);
if(cmd_type != '?'){
if(cmd_ordinal != -1)
printf("%s %s('%c',%d,l=%d) ",ioctl_strings[cmd_ordinal],
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
else {
cmd_ordinal = cmd & 0xff;
printf("[unknown ordinal %d] %s('%c',%d,l=%d) ",cmd_ordinal,
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
}
}
else {
printf("? %s('%c',%d,l=%d) ",
ioctl_type_strings[ioctl_type],
cmd_type,
cmd_ordinal,
ioctl_len);
}
printf("0x%x (0x%x) <0x%x>\n",
dev, cmd, arg);
}
if(*(((int *)arg) - 3) != IBCS2_MAGIC_IN){
printf("sockioctl: bad magic (sys_generic.c has no socksys mods?)\n");
return(EINVAL);
}
switch (cmd) {
case SS_SIOCSOCKSYS: /* ss syscall */
return ss_syscall(arg, p);
/* NIOCxx: These ioctls are really just integers
* (no other information to go on).
*/
case NIOCSETDOMNAM: {
struct sgdomarg domargs;
if(error = copyin((caddr_t)*((caddr_t *)arg), (caddr_t)&domargs, sizeof(struct sgdomarg)))
return(error);
arg = (caddr_t)&domargs;
SYSCALL_N(SYS_setdomainname, 0, 0);
break;
}
case NIOCGETDOMNAM: {
struct sgdomarg domargs;
if(error = copyin((caddr_t)*((caddr_t *)arg), (caddr_t)&domargs, sizeof(struct sgdomarg)))
return(error);
arg = (caddr_t)&domargs;
SYSCALL_N(SYS_getdomainname, 0, 0);
break;
}
case NIOCLSTAT: {
struct lstatarg st;
if(error = copyin((caddr_t)*((caddr_t *)arg), (caddr_t)&st, sizeof(struct lstatarg)))
return(error);
/* DO WE HAVE A FOREIGN LSTAT */
/* return mumbo_lstat(st.fname, st.statb); */
return (EINVAL);
}
case NIOCNFSD:
case NIOCOLDGETFH:
case NIOCASYNCD:
case NIOCCLNTHAND:
case NIOCEXPORTFS:
case NIOCGETFH:
return (EINVAL);
case SS_IF_UNITSEL: /* set unit number */
case SS_SIOCXPROTO: /* empty proto table */
case SS_SIOCIFDETACH: /* detach interface */
case SS_SIOCGENPSTATS: /* get ENP stats */
case SS_SIOCSIFNAME: /* set interface name */
case SS_SIOCGIFONEP: /* get one-packet params */
case SS_SIOCSIFONEP: /* set one-packet params */
case SS_SIOCPROTO: /* link proto */
case SS_SIOCX25XMT:
case SS_SIOCX25RCV:
case SS_SIOCX25TBL:
printf("sockioctl: [%d] unsupported ioctl 0x%x , 0x%lx\n",
p->p_pid,
cmd, (unsigned long)arg);
return (EINVAL);
default:
printf("sockioctl: [%d] unknown ioctl 0x%x , 0x%lx\n",
p->p_pid,
cmd, (unsigned long)arg);
return (EINVAL);
}
IBCS2_MAGIC_RETURN(arg);
}
int sockopen(dev, mode, devtype, p)
dev_t dev;
int mode;
int devtype;
struct proc *p;
{
if(ss_debug)
printf("sockopen: [%d] 0x%x\n", p->p_pid, dev);
/* minor = 0 is the socksys device itself. No special handling
* will be needed as it is controlled by the application
* via ioctls.
*/
if (minor(dev) == 0)
return 0;
/* minor = 1 is the spx device. This is the client side of a
* streams pipe to the X server. Under SCO and friends
* the library code messes around setting the connection
* up itself. We do it ourselves - this means we don't
* need to worry about the implementation of the server
* side (/dev/X0R - which must exist but can be a link
* to /dev/null) nor do we need to actually implement
* getmsg/putmsg.
*/
{ /* SPX */
int fd, error, args[3];
int retval[2];
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) + 1
struct sockaddr_un *Xaddr = (struct sockaddr_un *)UA_ALLOC();
retval[0] = retval[1] = 0;
if(ss_debug)
printf("sockopen: SPX: [%d] opening\n", p->p_pid);
/* Grab a socket. */
if(ss_debug)
printf("sockopen: SPX: [%d] get a unix domain socket\n",
p->p_pid);
args[0] = AF_UNIX;
args[1] = SOCK_STREAM;
args[2] = 0;
error = SYSCALLX(SYS_socket, args);
if (error)
return error;
fd = retval[0];
if(fd < 1) {
printf("sockopen: SPX: [%d] unexpected fd of %d\n",
p->p_pid, fd);
return(EOPNOTSUPP); /* MRL whatever */
}
/* Connect the socket to X. */
if(ss_debug)
printf("sockopen: SPX: [%d] connect to /tmp/X11-unix/X0\n",
p->p_pid);
args[0] = fd;
Xaddr->sun_family = AF_UNIX;
copyout("/tmp/.X11-unix/X0", Xaddr->sun_path, 18);
Xaddr->sun_len = SUN_LEN(Xaddr);
args[1] = (int)Xaddr;
args[2] = sizeof(struct sockaddr_un);
error = SYSCALLX(SYS_connect, args);
if (error) {
(void)SYSCALLX(SYS_close, &fd);
return error;
}
put_socket_fops(p,fd);
return 0;
} /* SPX */
}
int sockclose(dev, flag, mode, p)
dev_t dev;
int flag;
int mode;
struct proc *p;
{
if(ss_debug)
printf("sockclose: [%d] 0x%x\n", p->p_pid, dev);
return(0);
}
static
int ss_fop_close(struct file *fp, struct proc *p)
{
int fd;
struct filedesc *fdp;
if(ss_debug){
fdp = p->p_fd;
fd = -1;
while(++fd < NOFILE)
if ( fp == fdp->fd_ofiles[fd] )
break;
printf("ss_fop_close: [%d] fd=%d ", p->p_pid, fd);
}
if(fp->f_type == DTYPE_SOCKET) {
if(ss_debug)
printf("is a socket\n");
return(close_s(fp, p));
}
else {
if(ss_debug)
printf("is not a socket\n");
return(ENOTSOCK);
}
}
void put_socket_fops(struct proc *p, int fd)
{
struct filedesc *fdp;
struct file *fp;
fdp = p->p_fd;
fp = fdp->fd_ofiles[fd];
if (ss_socket_fops.fo_ioctl != fp->f_ops->fo_ioctl) {
bcopy(fp->f_ops, &ss_socket_fops, sizeof(struct fileops));
ioctl_s = ss_socket_fops.fo_ioctl; /* save standard ioctl */
close_s = ss_socket_fops.fo_close; /* save standard close */
ss_socket_fops.fo_ioctl = ss_fop_ioctl;
ss_socket_fops.fo_close = ss_fop_close;
}
fp->f_ops = &ss_socket_fops;
return;
}
int ss_SYSCALL(n,convert_arg,indicator,arg,p,retval)
int n; /* syscall ordinal */
int convert_arg; /* if not 0, argument to convert */
int indicator; /* type of argument to convert */
int *arg; /* address of alien arg */
struct proc *p;
int *retval;
{
int error;
int rc;
if(convert_arg){
if(rc = ss_convert_struct( (caddr_t)*(arg + convert_arg),
indicator,
SS_ALIEN_TO_NATIVE))
return(rc);
error = (*sysent[n].sy_call)(p, arg + 1, retval);
rc = ss_convert_struct( (caddr_t)*(arg + convert_arg),
indicator,
SS_NATIVE_TO_ALIEN);
if(ss_debug)
printf("ss_SYSCALL: [%d] error=%d, rc=%d\n",
p->p_pid, error, rc);
}
else {
rc = 0;
error = (*sysent[n].sy_call)(p, arg + 1, retval);
if(ss_debug)
printf("ss_SYSCALL: [%d] error=%d\n",p->p_pid, error);
}
return(error ? error : rc);
}
int ss_IOCTL(fp, cmd, arg, p)
struct file *fp;
int cmd;
int *arg; /* address of alien arg */
struct proc *p;
{
int error, rc;
int these[2];
char cmd_type;
int cmd_ordinal;
int indicator;
cmd_type = (cmd >> 8) & 0xff;
cmd_ordinal = cmd & 0xff;
these[0] = cmd_type;
these[1] = cmd_ordinal;
if(ss_debug > 1)
printf("ss_IOCTL: calling ss_convert with %d(%c) %d\n",
these[0],these[0],these[1]);
indicator = ss_convert( struct_whatevers, these, 0);
if(ss_debug > 1)
printf("ss_IOCTL: ss_convert returns indicator %d\n",indicator);
if(indicator){
error = ss_convert_struct((caddr_t)*(arg + 2),
indicator,
SS_ALIEN_TO_NATIVE);
if(ss_debug > 1)
printf("ss_IOCTL: ss_convert_struct returns %d\n",error);
if(error)
return(error);
/* change len in ioctl now - in the general case */
error = ioctl_s(fp, cmd, (caddr_t)arg, p);
rc = ss_convert_struct( (caddr_t)*(arg + 2),
indicator,
SS_NATIVE_TO_ALIEN);
if(ss_debug)
printf("ss_IOCTL: [%d] error=%d, rc=%d\n",p->p_pid,
error, rc);
}
else {
rc = 0;
error = ioctl_s(fp, cmd, (caddr_t)arg, p);
if(ss_debug)
printf("ss_IOCTL: [%d] error=%d\n",p->p_pid, error);
}
return(error ? error : rc);
}
struct ss_socketopt_args {
int s;
int level;
int name;
caddr_t val;
int valsize;
};
int
ss_setsockopt(arg, ret, p)
struct ss_socketopt_args *arg;
int *ret;
struct proc *p;
{
int error, optname;
int retval[2];
if (arg->level != 0xffff) /* FreeBSD, SCO and ? */
return (ENOPROTOOPT);
optname = ss_convert(sopt_whatevers, &arg->name, 0);
switch (optname) {
case SO_ACCEPTCONN:
case SO_BROADCAST:
case SO_DEBUG:
case SO_DONTROUTE:
case SO_LINGER:
case SO_KEEPALIVE:
case SO_OOBINLINE:
case SO_RCVBUF:
case SO_RCVLOWAT:
case SO_RCVTIMEO:
case SO_REUSEADDR:
case SO_SNDBUF:
case SO_SNDLOWAT:
case SO_SNDTIMEO:
case SO_USELOOPBACK:
error = SYSCALLX(SYS_setsockopt, arg);
*ret = retval[0];
*(ret + 1) = retval[1];
return(error);
case SO_ERROR:
case SO_IMASOCKET:
case SO_NO_CHECK:
case SO_ORDREL:
case SO_PRIORITY:
case SO_PROTOTYPE:
case SO_TYPE:
return (ENOPROTOOPT);
}
return (ENOPROTOOPT);
}
int
ss_getsockopt(arg, ret, p)
struct ss_socketopt_args *arg;
int *ret;
struct proc *p;
{
int error, optname;
int retval[2];
if (arg->level != 0xffff) /* FreeBSD, SCO and ? */
return (ENOPROTOOPT);
optname = ss_convert(sopt_whatevers, &arg->name, 0);
switch (optname) {
case SO_ACCEPTCONN:
case SO_BROADCAST:
case SO_DEBUG:
case SO_DONTROUTE:
case SO_ERROR:
case SO_KEEPALIVE:
case SO_LINGER:
case SO_OOBINLINE:
case SO_RCVBUF:
case SO_RCVLOWAT:
case SO_RCVTIMEO:
case SO_REUSEADDR:
case SO_SNDBUF:
case SO_SNDLOWAT:
case SO_SNDTIMEO:
case SO_TYPE:
case SO_USELOOPBACK:
error = SYSCALLX(SYS_getsockopt, arg);
*ret = retval[0];
*(ret + 1) = retval[1];
return(error);
case SO_PROTOTYPE: {
int value = 0;
error = copyout((caddr_t)&value, (caddr_t)arg->s, sizeof(int));
return(error);
}
case SO_IMASOCKET: {
int value = 1;
error = copyout((caddr_t)&value, (caddr_t)arg->s, sizeof(int));
return(error);
}
case SO_NO_CHECK:
case SO_ORDREL:
case SO_PRIORITY:
return (ENOPROTOOPT);
}
return (ENOPROTOOPT);
}
#define SS_CONVERT
int system_type = SS_FREEBSD; /* FreeBSD */
int
ss_convert(what, this, otherwise)
struct whatever **what;
int *this;
int otherwise;
{
struct whatever *specific;
if(!(specific = what[system_type]))
return *this;
for (; specific->from != -1; specific++)
if(specific->from <= *this && *this <= specific->to)
if(specific->from == specific->to){
if(specific->more){
specific = specific->more;
this++;
continue;
}
else {
return((int)specific->conversion);
}
}
else {
return(specific->conversion ? (
specific->all_the_same ? (int)specific->conversion : specific->conversion[*this - specific->from] ) : *this);
}
return otherwise;
}
/* Returns 0 - no conversion, no pointer modification
1 - converted, relevant pointer modification
-1 - error
*/
int
ss_convert_struct(alien, indicator, direction)
char *alien;
int indicator;
int direction;
{
int error, len;
switch (system_type) {
case SS_FREEBSD:
return(0);
case SS_SYSVR4:
case SS_SYSVR3:
case SS_SCO_32:
case SS_WYSE_321:
case SS_ISC:
case SS_LINUX:
switch(direction){
case SS_ALIEN_TO_NATIVE:
error = ss_atn(alien, indicator);
if(ss_debug > 1)
printf("ss_convert: ATN ss_atn error %d\n",error);
return(error);
case SS_NATIVE_TO_ALIEN:
error = ss_nta(alien, indicator);
if(ss_debug > 1)
printf("ss_convert: NTA ss_nta error %d\n",error);
return(error);
}
default:
printf("ss_convert_struct: not expecting system_type %d\n", system_type);
break;
}
return(EINVAL);
}
/* note sockaddr_un linux unsigned short fam, 108 path
BSD uchar , uchar 104 */
int
ss_atn(alien, indicator)
char *alien;
int indicator;
{
int error;
switch (indicator) {
case SS_STRUCT_ARPREQ:
/* compatible */
return(0);
case SS_STRUCT_IFCONF:
/* compatible */
return(0);
case SS_STRUCT_IFREQ:
/* length OK - more unions - function dependent */
return(0);
case SS_STRUCT_ORTENTRY:
/* compatible */
return(0);
case SS_STRUCT_SOCKADDR:{
struct native_hdr {
u_char len;
u_char family;
};
union hdr_part {
struct native_hdr native;
u_short alien_family;
} hdr;
if(error = copyin((caddr_t)alien,(caddr_t)&hdr,sizeof(hdr)))
return(error);
if(ss_debug > 1)
printf("ss_atn:copyin 0x%x\n",hdr.alien_family);
if( hdr.alien_family < AF_MAX){
hdr.native.family = hdr.alien_family >> 8; /* 386 endianess */
/* OR LEN FOM A PARAM ? */
hdr.native.len = sizeof(struct sockaddr);
if(ss_debug > 1)
printf("ss_atn:copyout 0x%x\n",hdr.alien_family);
error = copyout((caddr_t)&hdr,(caddr_t)alien,sizeof(hdr));
return(error);
}
else {
printf("ss_atn: sa_family = %d\n", hdr.alien_family);
return(EINVAL);
}
}
case SS_STRUCT_SOCKNEWPROTO:
/* don't have */
printf("ss_atn: not expecting SS_STRUCT_SOCKNEWPROTO\n");
return(EINVAL);
default:
printf("ss_atn: not expecting case %d\n",indicator);
return(EINVAL);
}
}
/* note sockaddr_un linux unsigned short fam, 108 path
BSD uchar , uchar 104 */
int
ss_nta(alien, indicator)
char *alien;
int indicator;
{
int error;
switch (indicator) {
case SS_STRUCT_ARPREQ:
/* compatible */
return(0);
case SS_STRUCT_IFCONF:
/* compatible */
return(0);
case SS_STRUCT_IFREQ:
/* length OK - more unions - function dependent */
return(0);
case SS_STRUCT_ORTENTRY:
/* compatible */
return(0);
case SS_STRUCT_SOCKADDR:{
struct native_hdr {
u_char len;
u_char family;
};
union hdr_part {
struct native_hdr native;
u_short alien_family;
} hdr;
if(error = copyin((caddr_t)alien,(caddr_t)&hdr,sizeof(hdr)))
return(error);
if(ss_debug > 1)
printf("ss_nta:copyin 0x%x\n",hdr.alien_family);
hdr.alien_family = hdr.native.family;
if(ss_debug > 1)
printf("ss_nta:copyout 0x%x\n",hdr.alien_family);
error = copyout((caddr_t)&hdr,(caddr_t)alien,sizeof(hdr));
return(error);
}
case SS_STRUCT_SOCKNEWPROTO:
/* don't have */
printf("ss_nta: not expecting SS_STRUCT_SOCKNEWPROTO\n");
return(EINVAL);
default:
printf("ss_nta: not expecting case %d\n",indicator);
return(EINVAL);
}
}