NetBSD/sys/compat/svr4_32/svr4_32_stream.c
thorpej 80cc38a1af Fix a partial construction problem that can cause race conditions
between creation of a file descriptor and close(2) when using kernel
assisted threads.  What we do is stick descriptors in the table, but
mark them as "larval".  This causes essentially everything to treat
it as a non-existent descriptor, except for fdalloc(), which sees a
filled slot so that it won't (incorrectly) allocate it again.  When
a descriptor is fully constructed, the code that has constructed it
marks it as "mature" (which actually clears the "larval" flag), and
things continue to work as normal.

While here, gather all the code that gets a descriptor from the table
into a fd_getfile() function, and call it, rather than having the
same (sometimes incorrect) code copied all over the place.
2001-06-14 20:32:41 +00:00

2001 lines
42 KiB
C

/* $NetBSD: svr4_32_stream.c,v 1.4 2001/06/14 20:32:46 thorpej Exp $ */
/*-
* Copyright (c) 1994 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Pretend that we have streams...
* Yes, this is gross.
*
* ToDo: The state machine for getmsg needs re-thinking
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/un.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/device.h>
#include <sys/stat.h>
#include <sys/syscallargs.h>
#include <compat/svr4_32/svr4_32_types.h>
#include <compat/svr4_32/svr4_32_util.h>
#include <compat/svr4_32/svr4_32_signal.h>
#include <compat/svr4_32/svr4_32_lwp.h>
#include <compat/svr4_32/svr4_32_ucontext.h>
#include <compat/svr4_32/svr4_32_syscallargs.h>
#include <compat/svr4_32/svr4_32_stropts.h>
#include <compat/svr4_32/svr4_32_timod.h>
#include <compat/svr4/svr4_sockmod.h>
#include <compat/svr4_32/svr4_32_ioctl.h>
#include <compat/svr4_32/svr4_32_socket.h>
/* Utils */
static int clean_pipe __P((struct proc *, const char *));
static void getparm __P((struct file *, struct svr4_si_sockparms *));
/* Address Conversions */
static void sockaddr_to_netaddr_in __P((struct svr4_32_strmcmd *,
const struct sockaddr_in *));
static void sockaddr_to_netaddr_un __P((struct svr4_32_strmcmd *,
const struct sockaddr_un *));
static void netaddr_to_sockaddr_in __P((struct sockaddr_in *,
const struct svr4_32_strmcmd *));
static void netaddr_to_sockaddr_un __P((struct sockaddr_un *,
const struct svr4_32_strmcmd *));
/* stream ioctls */
static int i_nread __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int i_fdinsert __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int i_str __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int i_setsig __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int i_getsig __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int _i_bind_rsvd __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
static int _i_rele_rsvd __P((struct file *, struct proc *, register_t *, int,
u_long, caddr_t));
/* i_str sockmod calls */
static int sockmod __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int si_listen __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int si_ogetudata __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int si_sockparams __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int si_shutdown __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int si_getudata __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
/* i_str timod calls */
static int timod __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int ti_getinfo __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
static int ti_bind __P((struct file *, int, struct svr4_32_strioctl *,
struct proc *));
#ifdef DEBUG_SVR4
static void bufprint __P((u_char *, size_t));
static int show_ioc __P((const char *, struct svr4_32_strioctl *));
static int show_strbuf __P((struct svr4_32_strbuf *));
static void show_msg __P((const char *, int, struct svr4_32_strbuf *,
struct svr4_32_strbuf *, int));
static void
bufprint(buf, len)
u_char *buf;
size_t len;
{
size_t i;
uprintf("\n\t");
for (i = 0; i < len; i++) {
uprintf("%x ", buf[i]);
if (i && (i % 16) == 0)
uprintf("\n\t");
}
}
static int
show_ioc(str, ioc)
const char *str;
struct svr4_32_strioctl *ioc;
{
u_char *ptr;
int error;
len = ioc->len;
if (len > 1024)
len = 1024;
ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK);
uprintf("%s cmd = %ld, timeout = %d, len = %d, buf = %p { ",
str, ioc->cmd, ioc->timeout, ioc->len, ioc->buf);
if ((error = copyin(ioc->buf, ptr, len)) != 0) {
free((char *) ptr, M_TEMP);
return error;
}
bufprint(ptr, len);
uprintf("}\n");
free((char *) ptr, M_TEMP);
return 0;
}
static int
show_strbuf(str)
struct svr4_32_strbuf *str;
{
int error;
u_char *ptr = NULL;
int maxlen = str->maxlen;
int len = str->len;
if (maxlen > 8192)
maxlen = 8192;
if (maxlen < 0)
maxlen = 0;
if (len >= maxlen)
len = maxlen;
if (len > 0) {
ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK);
if ((error = copyin(str->buf, ptr, len)) != 0) {
free((char *) ptr, M_TEMP);
return error;
}
}
uprintf(", { %d, %d, %p=[ ", str->maxlen, str->len, str->buf);
if (ptr)
bufprint(ptr, len);
uprintf("]}");
if (ptr)
free((char *) ptr, M_TEMP);
return 0;
}
static void
show_msg(str, fd, ctl, dat, flags)
const char *str;
int fd;
struct svr4_32_strbuf *ctl;
struct svr4_32_strbuf *dat;
int flags;
{
struct svr4_32_strbuf buf;
int error;
uprintf("%s(%d", str, fd);
if (ctl != NULL) {
if ((error = copyin(ctl, &buf, sizeof(buf))) != 0)
return;
show_strbuf(&buf);
}
else
uprintf(", NULL");
if (dat != NULL) {
if ((error = copyin(dat, &buf, sizeof(buf))) != 0)
return;
show_strbuf(&buf);
}
else
uprintf(", NULL");
uprintf(", %x);\n", flags);
}
#endif /* DEBUG_SVR4 */
/*
* We are faced with an interesting situation. On svr4 unix sockets
* are really pipes. But we really have sockets, and we might as
* well use them. At the point where svr4 calls TI_BIND, it has
* already created a named pipe for the socket using mknod(2).
* We need to create a socket with the same name when we bind,
* so we need to remove the pipe before, otherwise we'll get address
* already in use. So we *carefully* remove the pipe, to avoid
* using this as a random file removal tool. We use system calls
* to avoid code duplication.
*/
static int
clean_pipe(p, path)
struct proc *p;
const char *path;
{
struct sys___lstat13_args la;
struct sys_unlink_args ua;
register_t retval;
struct stat st;
int error;
caddr_t sg = stackgap_init(p->p_emul);
size_t l = strlen(path) + 1;
void *tpath;
tpath = stackgap_alloc(&sg, l);
SCARG(&la, ub) = stackgap_alloc(&sg, sizeof(struct stat));
if ((error = copyout(path, tpath, l)) != 0)
return error;
SCARG(&la, path) = tpath;
if ((error = sys___lstat13(p, &la, &retval)) != 0)
return 0;
if ((error = copyin(SCARG(&la, ub), &st, sizeof(st))) != 0)
return 0;
/*
* Make sure we are dealing with a mode 0 named pipe.
*/
if ((st.st_mode & S_IFMT) != S_IFIFO)
return 0;
if ((st.st_mode & ALLPERMS) != 0)
return 0;
SCARG(&ua, path) = SCARG(&la, path);
if ((error = sys_unlink(p, &ua, &retval)) != 0) {
DPRINTF(("clean_pipe: unlink failed %d\n", error));
return error;
}
return 0;
}
static void
sockaddr_to_netaddr_in(sc, sain)
struct svr4_32_strmcmd *sc;
const struct sockaddr_in *sain;
{
struct svr4_32_netaddr_in *na;
na = SVR4_ADDROF(sc);
na->family = sain->sin_family;
na->port = sain->sin_port;
na->addr = sain->sin_addr.s_addr;
DPRINTF(("sockaddr_in -> netaddr %d %d %lx\n", na->family, na->port,
na->addr));
}
static void
sockaddr_to_netaddr_un(sc, saun)
struct svr4_32_strmcmd *sc;
const struct sockaddr_un *saun;
{
struct svr4_32_netaddr_un *na;
char *dst, *edst = ((char *) sc) + sc->offs + sizeof(na->family) + 1 -
sizeof(*sc);
const char *src;
na = SVR4_ADDROF(sc);
na->family = saun->sun_family;
for (src = saun->sun_path, dst = na->path; (*dst++ = *src++) != '\0'; )
if (dst == edst)
break;
DPRINTF(("sockaddr_un -> netaddr %d %s\n", na->family, na->path));
}
static void
netaddr_to_sockaddr_in(sain, sc)
struct sockaddr_in *sain;
const struct svr4_32_strmcmd *sc;
{
const struct svr4_32_netaddr_in *na;
na = SVR4_C_ADDROF(sc);
memset(sain, 0, sizeof(*sain));
sain->sin_len = sizeof(*sain);
sain->sin_family = na->family;
sain->sin_port = na->port;
sain->sin_addr.s_addr = na->addr;
DPRINTF(("netaddr -> sockaddr_in %d %d %x\n", sain->sin_family,
sain->sin_port, sain->sin_addr.s_addr));
}
static void
netaddr_to_sockaddr_un(saun, sc)
struct sockaddr_un *saun;
const struct svr4_32_strmcmd *sc;
{
const struct svr4_32_netaddr_un *na;
char *dst, *edst = &saun->sun_path[sizeof(saun->sun_path) - 1];
const char *src;
na = SVR4_C_ADDROF(sc);
memset(saun, 0, sizeof(*saun));
saun->sun_family = na->family;
for (src = na->path, dst = saun->sun_path; (*dst++ = *src++) != '\0'; )
if (dst == edst)
break;
saun->sun_len = dst - saun->sun_path;
DPRINTF(("netaddr -> sockaddr_un %d %s\n", saun->sun_family,
saun->sun_path));
}
static void
getparm(fp, pa)
struct file *fp;
struct svr4_si_sockparms *pa;
{
struct svr4_strm *st = svr4_32_stream_get(fp);
struct socket *so = (struct socket *) fp->f_data;
if (st == NULL)
return;
pa->family = st->s_family;
switch (so->so_type) {
case SOCK_DGRAM:
pa->type = SVR4_T_CLTS;
pa->protocol = IPPROTO_UDP;
DPRINTF(("getparm(dgram)\n"));
return;
case SOCK_STREAM:
pa->type = SVR4_T_COTS; /* What about T_COTS_ORD? XXX */
pa->protocol = IPPROTO_IP;
DPRINTF(("getparm(stream)\n"));
return;
case SOCK_RAW:
pa->type = SVR4_T_CLTS;
pa->protocol = IPPROTO_RAW;
DPRINTF(("getparm(raw)\n"));
return;
default:
pa->type = 0;
pa->protocol = 0;
DPRINTF(("getparm(type %d?)\n", so->so_type));
return;
}
}
static int
si_ogetudata(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct svr4_si_oudata ud;
struct svr4_si_sockparms pa;
if (ioc->len != sizeof(ud) && ioc->len != sizeof(ud) - sizeof(int)) {
DPRINTF(("SI_OGETUDATA: Wrong size %ld != %d\n",
(unsigned long)sizeof(ud), ioc->len));
return EINVAL;
}
if ((error = copyin((caddr_t)(u_long)ioc->buf, &ud, sizeof(ud))) != 0)
return error;
getparm(fp, &pa);
switch (pa.family) {
case AF_INET:
ud.tidusize = 16384;
ud.addrsize = sizeof(struct sockaddr_in);
if (pa.type == SVR4_SOCK_STREAM)
ud.etsdusize = 1;
else
ud.etsdusize = 0;
break;
case AF_LOCAL:
ud.tidusize = 65536;
ud.addrsize = 128;
ud.etsdusize = 128;
break;
default:
DPRINTF(("SI_OGETUDATA: Unsupported address family %d\n",
pa.family));
return ENOSYS;
}
/* I have no idea what these should be! */
ud.optsize = 128;
ud.tsdusize = 128;
ud.servtype = pa.type;
/* XXX: Fixme */
ud.so_state = 0;
ud.so_options = 0;
return copyout(&ud, (caddr_t)(u_long)ioc->buf, ioc->len);
}
static int
si_sockparams(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
struct svr4_si_sockparms pa;
getparm(fp, &pa);
return copyout(&pa, (caddr_t)(u_long)ioc->buf, sizeof(pa));
}
static int
si_listen(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct svr4_strm *st = svr4_32_stream_get(fp);
register_t retval;
struct svr4_32_strmcmd lst;
struct sys_listen_args la;
if (st == NULL)
return EINVAL;
if (ioc->len > sizeof(lst))
return EINVAL;
if ((error = copyin((caddr_t)(u_long)ioc->buf, &lst, ioc->len)) != 0)
return error;
if (lst.cmd != SVR4_TI_OLD_BIND_REQUEST) {
DPRINTF(("si_listen: bad request %ld\n", lst.cmd));
return EINVAL;
}
/*
* We are making assumptions again...
*/
SCARG(&la, s) = fd;
DPRINTF(("SI_LISTEN: fileno %d backlog = %d\n", fd, 5));
SCARG(&la, backlog) = 5;
if ((error = sys_listen(p, &la, &retval)) != 0) {
DPRINTF(("SI_LISTEN: listen failed %d\n", error));
return error;
}
st->s_cmd = SVR4_TI__ACCEPT_WAIT;
lst.cmd = SVR4_TI_BIND_REPLY;
switch (st->s_family) {
case AF_INET:
/* XXX: Fill the length here */
break;
case AF_LOCAL:
lst.len = 140;
lst.pad[28] = 0x00000000; /* magic again */
lst.pad[29] = 0x00000800; /* magic again */
lst.pad[30] = 0x80001400; /* magic again */
break;
default:
DPRINTF(("SI_LISTEN: Unsupported address family %d\n",
st->s_family));
return ENOSYS;
}
if ((error = copyout(&lst, (caddr_t)(u_long)ioc->buf, ioc->len)) != 0)
return error;
return 0;
}
static int
si_getudata(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct svr4_si_udata ud;
if (sizeof(ud) != ioc->len) {
DPRINTF(("SI_GETUDATA: Wrong size %ld != %d\n",
(unsigned long)sizeof(ud), ioc->len));
return EINVAL;
}
if ((error = copyin((caddr_t)(u_long)ioc->buf, &ud, sizeof(ud))) != 0)
return error;
getparm(fp, &ud.sockparms);
switch (ud.sockparms.family) {
case AF_INET:
ud.tidusize = 16384;
ud.tsdusize = 16384;
ud.addrsize = sizeof(struct sockaddr_in);
if (ud.sockparms.type == SVR4_SOCK_STREAM)
ud.etsdusize = 1;
else
ud.etsdusize = 0;
ud.optsize = 0;
break;
case AF_LOCAL:
ud.tidusize = 65536;
ud.tsdusize = 128;
ud.addrsize = 128;
ud.etsdusize = 128;
ud.optsize = 128;
break;
default:
DPRINTF(("SI_GETUDATA: Unsupported address family %d\n",
ud.sockparms.family));
return ENOSYS;
}
ud.servtype = ud.sockparms.type;
/* XXX: Fixme */
ud.so_state = 0;
ud.so_options = 0;
return copyout(&ud, (caddr_t)(u_long)ioc->buf, sizeof(ud));
}
static int
si_shutdown(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct sys_shutdown_args ap;
register_t retval;
if (ioc->len != sizeof(SCARG(&ap, how))) {
DPRINTF(("SI_SHUTDOWN: Wrong size %ld != %d\n",
(unsigned long)sizeof(SCARG(&ap, how)), ioc->len));
return EINVAL;
}
if ((error = copyin((caddr_t)(u_long)ioc->buf, &SCARG(&ap, how), ioc->len)) != 0)
return error;
SCARG(&ap, s) = fd;
return sys_shutdown(p, &ap, &retval);
}
static int
sockmod(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
switch (ioc->cmd) {
case SVR4_SI_OGETUDATA:
DPRINTF(("SI_OGETUDATA\n"));
return si_ogetudata(fp, fd, ioc, p);
case SVR4_SI_SHUTDOWN:
DPRINTF(("SI_SHUTDOWN\n"));
return si_shutdown(fp, fd, ioc, p);
case SVR4_SI_LISTEN:
DPRINTF(("SI_LISTEN\n"));
return si_listen(fp, fd, ioc, p);
case SVR4_SI_SETMYNAME:
DPRINTF(("SI_SETMYNAME\n"));
return 0;
case SVR4_SI_SETPEERNAME:
DPRINTF(("SI_SETPEERNAME\n"));
return 0;
case SVR4_SI_GETINTRANSIT:
DPRINTF(("SI_GETINTRANSIT\n"));
return 0;
case SVR4_SI_TCL_LINK:
DPRINTF(("SI_TCL_LINK\n"));
return 0;
case SVR4_SI_TCL_UNLINK:
DPRINTF(("SI_TCL_UNLINK\n"));
return 0;
case SVR4_SI_SOCKPARAMS:
DPRINTF(("SI_SOCKPARAMS\n"));
return si_sockparams(fp, fd, ioc, p);
case SVR4_SI_GETUDATA:
DPRINTF(("SI_GETUDATA\n"));
return si_getudata(fp, fd, ioc, p);
default:
DPRINTF(("Unknown sockmod ioctl %lx\n", ioc->cmd));
return 0;
}
}
static int
ti_getinfo(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct svr4_32_infocmd info;
memset(&info, 0, sizeof(info));
if (ioc->len > sizeof(info))
return EINVAL;
if ((error = copyin((caddr_t)(u_long)ioc->buf, &info, ioc->len)) != 0)
return error;
if (info.cmd != SVR4_TI_INFO_REQUEST)
return EINVAL;
info.cmd = SVR4_TI_INFO_REPLY;
info.tsdu = 0;
info.etsdu = 1;
info.cdata = -2;
info.ddata = -2;
info.addr = 16;
info.opt = -1;
info.tidu = 16384;
info.serv = 2;
info.current = 0;
info.provider = 2;
ioc->len = sizeof(info);
if ((error = copyout(&info, (caddr_t)(u_long)ioc->buf, ioc->len)) != 0)
return error;
return 0;
}
static int
ti_bind(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
int error;
struct svr4_strm *st = svr4_32_stream_get(fp);
struct sockaddr_in sain;
struct sockaddr_un saun;
register_t retval;
caddr_t sg;
void *skp, *sup = NULL;
int sasize;
struct svr4_32_strmcmd bnd;
struct sys_bind_args ba;
if (st == NULL) {
DPRINTF(("ti_bind: bad file descriptor\n"));
return EINVAL;
}
if (ioc->len > sizeof(bnd))
return EINVAL;
if ((error = copyin((caddr_t)(u_long)ioc->buf, &bnd, ioc->len)) != 0)
return error;
if (bnd.cmd != SVR4_TI_OLD_BIND_REQUEST) {
DPRINTF(("ti_bind: bad request %ld\n", bnd.cmd));
return EINVAL;
}
switch (st->s_family) {
case AF_INET:
skp = &sain;
sasize = sizeof(sain);
if (bnd.offs == 0)
goto reply;
netaddr_to_sockaddr_in(&sain, &bnd);
DPRINTF(("TI_BIND: fam %d, port %d, addr %x\n",
sain.sin_family, sain.sin_port,
sain.sin_addr.s_addr));
break;
case AF_LOCAL:
skp = &saun;
sasize = sizeof(saun);
if (bnd.offs == 0)
goto reply;
netaddr_to_sockaddr_un(&saun, &bnd);
if (saun.sun_path[0] == '\0')
goto reply;
DPRINTF(("TI_BIND: fam %d, path %s\n",
saun.sun_family, saun.sun_path));
if ((error = clean_pipe(p, saun.sun_path)) != 0)
return error;
bnd.pad[28] = 0x00001000; /* magic again */
break;
default:
DPRINTF(("TI_BIND: Unsupported address family %d\n",
st->s_family));
return ENOSYS;
}
sg = stackgap_init(p->p_emul);
sup = stackgap_alloc(&sg, sasize);
if ((error = copyout(skp, sup, sasize)) != 0)
return error;
SCARG(&ba, s) = fd;
DPRINTF(("TI_BIND: fileno %d\n", fd));
SCARG(&ba, name) = (void *) sup;
SCARG(&ba, namelen) = sasize;
if ((error = sys_bind(p, &ba, &retval)) != 0) {
DPRINTF(("TI_BIND: bind failed %d\n", error));
return error;
}
reply:
if (sup == NULL) {
memset(&bnd, 0, sizeof(bnd));
bnd.len = sasize + 4;
bnd.offs = 0x10; /* XXX */
}
bnd.cmd = SVR4_TI_BIND_REPLY;
if ((error = copyout(&bnd, (caddr_t)(u_long)ioc->buf, ioc->len)) != 0)
return error;
return 0;
}
static int
timod(fp, fd, ioc, p)
struct file *fp;
int fd;
struct svr4_32_strioctl *ioc;
struct proc *p;
{
switch (ioc->cmd) {
case SVR4_TI_GETINFO:
DPRINTF(("TI_GETINFO\n"));
return ti_getinfo(fp, fd, ioc, p);
case SVR4_TI_OPTMGMT:
DPRINTF(("TI_OPTMGMT\n"));
return 0;
case SVR4_TI_BIND:
DPRINTF(("TI_BIND\n"));
return ti_bind(fp, fd, ioc, p);
case SVR4_TI_UNBIND:
DPRINTF(("TI_UNBIND\n"));
return 0;
default:
DPRINTF(("Unknown timod ioctl %lx\n", ioc->cmd));
return 0;
}
}
int
svr4_32_stream_ti_ioctl(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
struct svr4_32_strbuf skb, *sub = (struct svr4_32_strbuf *) dat;
struct svr4_strm *st = svr4_32_stream_get(fp);
int error;
void *skp, *sup;
struct sockaddr_in sain;
struct sockaddr_un saun;
struct svr4_32_strmcmd sc;
int sasize;
caddr_t sg;
int *lenp;
if (st == NULL)
return EINVAL;
sc.offs = 0x10;
if ((error = copyin(sub, &skb, sizeof(skb))) != 0) {
DPRINTF(("ti_ioctl: error copying in strbuf\n"));
return error;
}
switch (st->s_family) {
case AF_INET:
skp = &sain;
sasize = sizeof(sain);
break;
case AF_LOCAL:
skp = &saun;
sasize = sizeof(saun);
break;
default:
DPRINTF(("ti_ioctl: Unsupported address family %d\n",
st->s_family));
return ENOSYS;
}
sg = stackgap_init(p->p_emul);
sup = stackgap_alloc(&sg, sasize);
lenp = stackgap_alloc(&sg, sizeof(*lenp));
if ((error = copyout(&sasize, lenp, sizeof(*lenp))) != 0) {
DPRINTF(("ti_ioctl: error copying out lenp\n"));
return error;
}
switch (cmd) {
case SVR4_TI_GETMYNAME:
DPRINTF(("TI_GETMYNAME\n"));
{
struct sys_getsockname_args ap;
SCARG(&ap, fdes) = fd;
SCARG(&ap, asa) = sup;
SCARG(&ap, alen) = lenp;
if ((error = sys_getsockname(p, &ap, retval)) != 0) {
DPRINTF(("ti_ioctl: getsockname error\n"));
return error;
}
}
break;
case SVR4_TI_GETPEERNAME:
DPRINTF(("TI_GETPEERNAME\n"));
{
struct sys_getpeername_args ap;
SCARG(&ap, fdes) = fd;
SCARG(&ap, asa) = sup;
SCARG(&ap, alen) = lenp;
if ((error = sys_getpeername(p, &ap, retval)) != 0) {
DPRINTF(("ti_ioctl: getpeername error\n"));
return error;
}
}
break;
case SVR4_TI_SETMYNAME:
DPRINTF(("TI_SETMYNAME\n"));
return 0;
case SVR4_TI_SETPEERNAME:
DPRINTF(("TI_SETPEERNAME\n"));
return 0;
default:
DPRINTF(("ti_ioctl: Unknown ioctl %lx\n", cmd));
return ENOSYS;
}
if ((error = copyin(sup, skp, sasize)) != 0) {
DPRINTF(("ti_ioctl: error copying in socket data\n"));
return error;
}
if ((error = copyin(lenp, &sasize, sizeof(*lenp))) != 0) {
DPRINTF(("ti_ioctl: error copying in socket size\n"));
return error;
}
switch (st->s_family) {
case AF_INET:
sockaddr_to_netaddr_in(&sc, &sain);
skb.len = sasize;
break;
case AF_LOCAL:
sockaddr_to_netaddr_un(&sc, &saun);
skb.len = sasize + 4;
break;
default:
return ENOSYS;
}
if ((error = copyout(SVR4_ADDROF(&sc), (caddr_t)(u_long)skb.buf,
sasize)) != 0) {
DPRINTF(("ti_ioctl: error copying out socket data\n"));
return error;
}
if ((error = copyout(&skb, sub, sizeof(skb))) != 0) {
DPRINTF(("ti_ioctl: error copying out strbuf\n"));
return error;
}
return error;
}
static int
i_nread(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
int error;
int nread = 0;
/*
* We are supposed to return the message length in nread, and the
* number of messages in retval. We don't have the notion of number
* of stream messages, so we just find out if we have any bytes waiting
* for us, and if we do, then we assume that we have at least one
* message waiting for us.
*/
if ((error = (*fp->f_ops->fo_ioctl)(fp, FIONREAD,
(caddr_t) &nread, p)) != 0)
return error;
if (nread != 0)
*retval = 1;
else
*retval = 0;
return copyout(&nread, dat, sizeof(nread));
}
static int
i_fdinsert(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
/*
* Major hack again here. We assume that we are using this to
* implement accept(2). If that is the case, we have already
* called accept, and we have stored the file descriptor in
* afd. We find the file descriptor that the code wants to use
* in fd insert, and then we dup2() our accepted file descriptor
* to it.
*/
int error;
struct svr4_strm *st = svr4_32_stream_get(fp);
struct svr4_32_strfdinsert fdi;
struct sys_dup2_args d2p;
struct sys_close_args clp;
if (st == NULL) {
DPRINTF(("fdinsert: bad file type\n"));
return EINVAL;
}
if (st->s_afd == -1) {
DPRINTF(("fdinsert: accept fd not found\n"));
return ENOENT;
}
if ((error = copyin(dat, &fdi, sizeof(fdi))) != 0) {
DPRINTF(("fdinsert: copyin failed %d\n", error));
return error;
}
SCARG(&d2p, from) = st->s_afd;
SCARG(&d2p, to) = fdi.fd;
if ((error = sys_dup2(p, &d2p, retval)) != 0) {
DPRINTF(("fdinsert: dup2(%d, %d) failed %d\n",
st->s_afd, fdi.fd, error));
return error;
}
SCARG(&clp, fd) = st->s_afd;
if ((error = sys_close(p, &clp, retval)) != 0) {
DPRINTF(("fdinsert: close(%d) failed %d\n",
st->s_afd, error));
return error;
}
st->s_afd = -1;
*retval = 0;
return 0;
}
static int
_i_bind_rsvd(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
struct sys_mknod_args ap;
/*
* This is a supposed to be a kernel and library only ioctl.
* It gets called before ti_bind, when we have a unix
* socket, to physically create the socket transport and
* ``reserve'' it. I don't know how this get reserved inside
* the kernel, but we are going to create it nevertheless.
*/
SCARG(&ap, path) = dat;
SCARG(&ap, mode) = S_IFIFO;
return sys_mkfifo(p, &ap, retval);
}
static int
_i_rele_rsvd(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
struct sys_unlink_args ap;
/*
* This is a supposed to be a kernel and library only ioctl.
* I guess it is supposed to release the socket.
*/
SCARG(&ap, path) = dat;
return sys_unlink(p, &ap, retval);
}
static int
i_str(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
int error;
struct svr4_32_strioctl ioc;
/*
* Noop on non sockets
*/
if (fp->f_type != DTYPE_SOCKET)
return 0;
if ((error = copyin(dat, &ioc, sizeof(ioc))) != 0)
return error;
#ifdef DEBUG_SVR4
if ((error = show_ioc(">", &ioc)) != 0)
return error;
#endif /* DEBUG_SVR4 */
switch (ioc.cmd & 0xff00) {
case SVR4_SIMOD:
if ((error = sockmod(fp, fd, &ioc, p)) != 0)
return error;
break;
case SVR4_TIMOD:
if ((error = timod(fp, fd, &ioc, p)) != 0)
return error;
break;
default:
DPRINTF(("Unimplemented module %c %ld\n",
(char) (cmd >> 8), cmd & 0xff));
return 0;
}
#ifdef DEBUG_SVR4
if ((error = show_ioc("<", &ioc)) != 0)
return error;
#endif /* DEBUG_SVR4 */
return copyout(&ioc, dat, sizeof(ioc));
}
static int
i_setsig(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
/*
* This is the best we can do for now; we cannot generate
* signals only for specific events so the signal mask gets
* ignored; we save it just to pass it to a possible I_GETSIG...
*
* We alse have to fix the O_ASYNC fcntl bit, so the
* process will get SIGPOLLs.
*/
struct sys_fcntl_args fa;
int error;
register_t oflags, flags;
struct svr4_strm *st = svr4_32_stream_get(fp);
if (st == NULL) {
DPRINTF(("i_setsig: bad file descriptor\n"));
return EINVAL;
}
/* get old status flags */
SCARG(&fa, fd) = fd;
SCARG(&fa, cmd) = F_GETFL;
if ((error = sys_fcntl(p, &fa, &oflags)) != 0)
return error;
/* update the flags */
if (dat != NULL) {
int mask;
flags = oflags | O_ASYNC;
mask = (int)(u_long)dat;
if (mask & ~SVR4_S_ALLMASK) {
DPRINTF(("i_setsig: bad eventmask data %x\n", mask));
return EINVAL;
}
st->s_eventmask = mask;
}
else {
flags = oflags & ~O_ASYNC;
st->s_eventmask = 0;
}
/* set the new flags, if changed */
if (flags != oflags) {
SCARG(&fa, cmd) = F_SETFL;
SCARG(&fa, arg) = (void *) flags;
if ((error = sys_fcntl(p, &fa, &flags)) != 0)
return error;
}
/* set up SIGIO receiver if needed */
if (dat != NULL) {
SCARG(&fa, cmd) = F_SETOWN;
SCARG(&fa, arg) = (void *)(u_long)p->p_pid;
return sys_fcntl(p, &fa, &flags);
}
return 0;
}
static int
i_getsig(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
int error;
if (dat != NULL) {
struct svr4_strm *st = svr4_32_stream_get(fp);
if (st == NULL) {
DPRINTF(("i_getsig: bad file descriptor\n"));
return EINVAL;
}
if ((error = copyout(&st->s_eventmask, dat,
sizeof(st->s_eventmask))) != 0) {
DPRINTF(("i_getsig: bad eventmask pointer\n"));
return error;
}
}
return 0;
}
int
svr4_32_stream_ioctl(fp, p, retval, fd, cmd, dat)
struct file *fp;
struct proc *p;
register_t *retval;
int fd;
u_long cmd;
caddr_t dat;
{
*retval = 0;
/*
* All the following stuff assumes "sockmod" is pushed...
*/
switch (cmd) {
case SVR4_I_NREAD:
DPRINTF(("I_NREAD\n"));
return i_nread(fp, p, retval, fd, cmd, dat);
case SVR4_I_PUSH:
DPRINTF(("I_PUSH\n"));
return 0;
case SVR4_I_POP:
DPRINTF(("I_POP\n"));
return 0;
case SVR4_I_LOOK:
DPRINTF(("I_LOOK\n"));
return 0;
case SVR4_I_FLUSH:
DPRINTF(("I_FLUSH\n"));
return 0;
case SVR4_I_SRDOPT:
DPRINTF(("I_SRDOPT\n"));
return 0;
case SVR4_I_GRDOPT:
DPRINTF(("I_GRDOPT\n"));
return 0;
case SVR4_I_STR:
DPRINTF(("I_STR\n"));
return i_str(fp, p, retval, fd, cmd, dat);
case SVR4_I_SETSIG:
DPRINTF(("I_SETSIG\n"));
return i_setsig(fp, p, retval, fd, cmd, dat);
case SVR4_I_GETSIG:
DPRINTF(("I_GETSIG\n"));
return i_getsig(fp, p, retval, fd, cmd, dat);
case SVR4_I_FIND:
DPRINTF(("I_FIND\n"));
/*
* Here we are not pushing modules really, we just
* pretend all are present
*/
*retval = 1;
return 0;
case SVR4_I_LINK:
DPRINTF(("I_LINK\n"));
return 0;
case SVR4_I_UNLINK:
DPRINTF(("I_UNLINK\n"));
return 0;
case SVR4_I_ERECVFD:
DPRINTF(("I_ERECVFD\n"));
return 0;
case SVR4_I_PEEK:
DPRINTF(("I_PEEK\n"));
return 0;
case SVR4_I_FDINSERT:
DPRINTF(("I_FDINSERT\n"));
return i_fdinsert(fp, p, retval, fd, cmd, dat);
case SVR4_I_SENDFD:
DPRINTF(("I_SENDFD\n"));
return 0;
case SVR4_I_RECVFD:
DPRINTF(("I_RECVFD\n"));
return 0;
case SVR4_I_SWROPT:
DPRINTF(("I_SWROPT\n"));
return 0;
case SVR4_I_GWROPT:
DPRINTF(("I_GWROPT\n"));
return 0;
case SVR4_I_LIST:
DPRINTF(("I_LIST\n"));
return 0;
case SVR4_I_PLINK:
DPRINTF(("I_PLINK\n"));
return 0;
case SVR4_I_PUNLINK:
DPRINTF(("I_PUNLINK\n"));
return 0;
case SVR4_I_SETEV:
DPRINTF(("I_SETEV\n"));
return 0;
case SVR4_I_GETEV:
DPRINTF(("I_GETEV\n"));
return 0;
case SVR4_I_STREV:
DPRINTF(("I_STREV\n"));
return 0;
case SVR4_I_UNSTREV:
DPRINTF(("I_UNSTREV\n"));
return 0;
case SVR4_I_FLUSHBAND:
DPRINTF(("I_FLUSHBAND\n"));
return 0;
case SVR4_I_CKBAND:
DPRINTF(("I_CKBAND\n"));
return 0;
case SVR4_I_GETBAND:
DPRINTF(("I_GETBANK\n"));
return 0;
case SVR4_I_ATMARK:
DPRINTF(("I_ATMARK\n"));
return 0;
case SVR4_I_SETCLTIME:
DPRINTF(("I_SETCLTIME\n"));
return 0;
case SVR4_I_GETCLTIME:
DPRINTF(("I_GETCLTIME\n"));
return 0;
case SVR4_I_CANPUT:
DPRINTF(("I_CANPUT\n"));
return 0;
case SVR4__I_BIND_RSVD:
DPRINTF(("_I_BIND_RSVD\n"));
return _i_bind_rsvd(fp, p, retval, fd, cmd, dat);
case SVR4__I_RELE_RSVD:
DPRINTF(("_I_RELE_RSVD\n"));
return _i_rele_rsvd(fp, p, retval, fd, cmd, dat);
default:
DPRINTF(("unimpl cmd = %lx\n", cmd));
break;
}
return 0;
}
int
svr4_32_sys_putmsg(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct svr4_32_sys_putmsg_args *uap = v;
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct svr4_32_strbuf dat, ctl;
struct svr4_32_strmcmd sc;
struct sockaddr_in sain;
struct sockaddr_un saun;
void *skp, *sup;
int sasize;
struct svr4_strm *st;
int error;
caddr_t sg;
#ifdef DEBUG_SVR4
show_msg(">putmsg", SCARG(uap, fd), SCARG(uap, ctl),
SCARG(uap, dat), SCARG(uap, flags));
#endif /* DEBUG_SVR4 */
if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
return EBADF;
if (SCARG(uap, ctl) != NULL) {
if ((error = copyin((caddr_t)(u_long)SCARG(uap, ctl),
&ctl, sizeof(ctl))) != 0)
return error;
}
else
ctl.len = -1;
if (SCARG(uap, dat) != NULL) {
if ((error = copyin((caddr_t)(u_long)SCARG(uap, dat),
&dat, sizeof(dat))) != 0)
return error;
}
else
dat.len = -1;
/*
* Only for sockets for now.
*/
if ((st = svr4_32_stream_get(fp)) == NULL) {
DPRINTF(("putmsg: bad file type\n"));
return EINVAL;
}
if (ctl.len > sizeof(sc)) {
DPRINTF(("putmsg: Bad control size %ld != %d\n",
(unsigned long)sizeof(struct svr4_32_strmcmd), ctl.len));
return EINVAL;
}
if ((error = copyin((caddr_t)(u_long)ctl.buf, &sc, ctl.len)) != 0)
return error;
switch (st->s_family) {
case AF_INET:
if (sc.len != sizeof(sain)) {
#ifdef notyet
if (sc.cmd == SVR4_TI_DATA_REQUEST) {
struct sys_write_args wa;
/* Solaris seems to use sc.cmd = 3 to
* send "expedited" data. telnet uses
* this for options processing, sending EOF,
* etc. I'm sure other things use it too.
* I don't have any documentation
* on it, so I'm making a guess that this
* is how it works. newton@atdot.dotat.org XXX
*
* Hmm, expedited data seems to be sc.cmd = 4.
* I think 3 is normal data. (christos)
*/
DPRINTF(("sending expedited data (?)\n"));
SCARG(&wa, fd) = SCARG(uap, fd);
SCARG(&wa, buf) = dat.buf;
SCARG(&wa, nbyte) = dat.len;
return sys_write(p, &wa, retval);
}
#endif
DPRINTF(("putmsg: Invalid inet length %ld\n", sc.len));
return EINVAL;
}
netaddr_to_sockaddr_in(&sain, &sc);
skp = &sain;
sasize = sizeof(sain);
error = sain.sin_family != st->s_family;
break;
case AF_LOCAL:
if (ctl.len == 8) {
/* We are doing an accept; succeed */
DPRINTF(("putmsg: Do nothing\n"));
*retval = 0;
return 0;
}
else {
/* Maybe we've been given a device/inode pair */
dev_t *dev = SVR4_ADDROF(&sc);
ino_t *ino = (ino_t *) &dev[1];
skp = svr4_find_socket(p, fp, *dev, *ino);
if (skp == NULL) {
skp = &saun;
/* I guess we have it by name */
netaddr_to_sockaddr_un(skp, &sc);
}
sasize = sizeof(saun);
}
break;
default:
DPRINTF(("putmsg: Unsupported address family %d\n",
st->s_family));
return ENOSYS;
}
sg = stackgap_init(p->p_emul);
sup = stackgap_alloc(&sg, sasize);
if ((error = copyout(skp, sup, sasize)) != 0)
return error;
switch (st->s_cmd = sc.cmd) {
case SVR4_TI_CONNECT_REQUEST: /* connect */
{
struct sys_connect_args co;
SCARG(&co, s) = SCARG(uap, fd);
SCARG(&co, name) = (void *) sup;
SCARG(&co, namelen) = (int) sasize;
return sys_connect(p, &co, retval);
}
case SVR4_TI_SENDTO_REQUEST: /* sendto */
{
struct msghdr msg;
struct iovec aiov;
msg.msg_name = (caddr_t) sup;
msg.msg_namelen = sasize;
msg.msg_iov = &aiov;
msg.msg_iovlen = 1;
msg.msg_control = 0;
msg.msg_flags = 0;
aiov.iov_base = (caddr_t)(u_long)dat.buf;
aiov.iov_len = dat.len;
error = sendit(p, SCARG(uap, fd), &msg,
SCARG(uap, flags), retval);
*retval = 0;
return error;
}
default:
DPRINTF(("putmsg: Unimplemented command %lx\n", sc.cmd));
return ENOSYS;
}
}
int
svr4_32_sys_getmsg(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct svr4_32_sys_getmsg_args *uap = v;
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct sys_getpeername_args ga;
struct sys_accept_args aa;
struct svr4_32_strbuf dat, ctl;
struct svr4_32_strmcmd sc;
int error;
struct msghdr msg;
struct iovec aiov;
struct sockaddr_in sain;
struct sockaddr_un saun;
void *skp, *sup;
int sasize;
struct svr4_strm *st;
int *flen;
int fl;
caddr_t sg;
memset(&sc, 0, sizeof(sc));
#ifdef DEBUG_SVR4
show_msg(">getmsg", SCARG(uap, fd), SCARG(uap, ctl),
SCARG(uap, dat), 0);
#endif /* DEBUG_SVR4 */
if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
return EBADF;
if (SCARG(uap, ctl) != NULL) {
if ((error = copyin((caddr_t)(u_long)SCARG(uap, ctl),
&ctl, sizeof(ctl))) != 0)
return error;
}
else {
ctl.len = -1;
ctl.maxlen = 0;
}
if (SCARG(uap, dat) != NULL) {
if ((error = copyin((caddr_t)(u_long)SCARG(uap, dat),
&dat, sizeof(dat))) != 0)
return error;
}
else {
dat.len = -1;
dat.maxlen = 0;
}
/*
* Only for sockets for now.
*/
if ((st = svr4_32_stream_get(fp)) == NULL) {
DPRINTF(("getmsg: bad file type\n"));
return EINVAL;
}
if (ctl.maxlen == -1 || dat.maxlen == -1) {
DPRINTF(("getmsg: Cannot handle -1 maxlen (yet)\n"));
return ENOSYS;
}
switch (st->s_family) {
case AF_INET:
skp = &sain;
sasize = sizeof(sain);
break;
case AF_LOCAL:
skp = &saun;
sasize = sizeof(saun);
break;
default:
DPRINTF(("getmsg: Unsupported address family %d\n",
st->s_family));
return ENOSYS;
}
sg = stackgap_init(p->p_emul);
sup = stackgap_alloc(&sg, sasize);
flen = (int *) stackgap_alloc(&sg, sizeof(*flen));
fl = sasize;
if ((error = copyout(&fl, flen, sizeof(fl))) != 0)
return error;
switch (st->s_cmd) {
case SVR4_TI_CONNECT_REQUEST:
DPRINTF(("getmsg: TI_CONNECT_REQUEST\n"));
/*
* We do the connect in one step, so the putmsg should
* have gotten the error.
*/
sc.cmd = SVR4_TI_OK_REPLY;
sc.len = 0;
ctl.len = 8;
dat.len = -1;
fl = 1;
st->s_cmd = sc.cmd;
break;
case SVR4_TI_OK_REPLY:
DPRINTF(("getmsg: TI_OK_REPLY\n"));
/*
* We are immediately after a connect reply, so we send
* a connect verification.
*/
SCARG(&ga, fdes) = SCARG(uap, fd);
SCARG(&ga, asa) = (void *) sup;
SCARG(&ga, alen) = flen;
if ((error = sys_getpeername(p, &ga, retval)) != 0) {
DPRINTF(("getmsg: getpeername failed %d\n", error));
return error;
}
if ((error = copyin(sup, skp, sasize)) != 0)
return error;
sc.cmd = SVR4_TI_CONNECT_REPLY;
sc.pad[0] = 0x4;
sc.offs = 0x18;
sc.pad[1] = 0x14;
sc.pad[2] = 0x04000402;
switch (st->s_family) {
case AF_INET:
sc.len = sasize;
sockaddr_to_netaddr_in(&sc, &sain);
break;
case AF_LOCAL:
sc.len = sasize + 4;
sockaddr_to_netaddr_un(&sc, &saun);
break;
default:
return ENOSYS;
}
ctl.len = 40;
dat.len = -1;
fl = 0;
st->s_cmd = sc.cmd;
break;
case SVR4_TI__ACCEPT_OK:
DPRINTF(("getmsg: TI__ACCEPT_OK\n"));
/*
* We do the connect in one step, so the putmsg should
* have gotten the error.
*/
sc.cmd = SVR4_TI_OK_REPLY;
sc.len = 1;
ctl.len = 8;
dat.len = -1;
fl = 1;
st->s_cmd = SVR4_TI__ACCEPT_WAIT;
break;
case SVR4_TI__ACCEPT_WAIT:
DPRINTF(("getmsg: TI__ACCEPT_WAIT\n"));
/*
* We are after a listen, so we try to accept...
*/
SCARG(&aa, s) = SCARG(uap, fd);
SCARG(&aa, name) = (void *) sup;
SCARG(&aa, anamelen) = flen;
if ((error = sys_accept(p, &aa, retval)) != 0) {
DPRINTF(("getmsg: accept failed %d\n", error));
return error;
}
st->s_afd = *retval;
DPRINTF(("getmsg: Accept fd = %d\n", st->s_afd));
if ((error = copyin(sup, skp, sasize)) != 0)
return error;
sc.cmd = SVR4_TI_ACCEPT_REPLY;
sc.offs = 0x18;
sc.pad[0] = 0x0;
switch (st->s_family) {
case AF_INET:
sc.pad[1] = 0x28;
sockaddr_to_netaddr_in(&sc, &sain);
ctl.len = 40;
sc.len = sasize;
break;
case AF_LOCAL:
sc.pad[1] = 0x00010000;
sc.pad[2] = 0xf6bcdaa0; /* I don't know what that is */
sc.pad[3] = 0x00010000;
ctl.len = 134;
sc.len = sasize + 4;
break;
default:
return ENOSYS;
}
dat.len = -1;
fl = 0;
st->s_cmd = SVR4_TI__ACCEPT_OK;
break;
case SVR4_TI_SENDTO_REQUEST:
DPRINTF(("getmsg: TI_SENDTO_REQUEST\n"));
if (ctl.maxlen > 36 && ctl.len < 36)
ctl.len = 36;
if (ctl.len > sizeof(sc))
ctl.len = sizeof(sc);
if ((error = copyin((caddr_t)(u_long)ctl.buf, &sc, ctl.len)) != 0)
return error;
switch (st->s_family) {
case AF_INET:
sockaddr_to_netaddr_in(&sc, &sain);
break;
case AF_LOCAL:
sockaddr_to_netaddr_un(&sc, &saun);
break;
default:
return ENOSYS;
}
msg.msg_name = (caddr_t) sup;
msg.msg_namelen = sasize;
msg.msg_iov = &aiov;
msg.msg_iovlen = 1;
msg.msg_control = 0;
aiov.iov_base = (caddr_t)(u_long)dat.buf;
aiov.iov_len = dat.maxlen;
msg.msg_flags = 0;
error = recvit(p, SCARG(uap, fd), &msg, (caddr_t) flen, retval);
if (error) {
DPRINTF(("getmsg: recvit failed %d\n", error));
return error;
}
if ((error = copyin(msg.msg_name, skp, sasize)) != 0)
return error;
sc.cmd = SVR4_TI_RECVFROM_IND;
switch (st->s_family) {
case AF_INET:
sc.len = sasize;
sockaddr_to_netaddr_in(&sc, &sain);
break;
case AF_LOCAL:
sc.len = sasize + 4;
sockaddr_to_netaddr_un(&sc, &saun);
break;
default:
return ENOSYS;
}
dat.len = *retval;
fl = 0;
st->s_cmd = sc.cmd;
break;
default:
st->s_cmd = sc.cmd;
#ifdef notyet
if (st->s_cmd == SVR4_TI_CONNECT_REQUEST) {
struct sys_read_args ra;
/* More wierdness: Again, I can't find documentation
* to back this up, but when a process does a generic
* "getmsg()" call it seems that the command field is
* zero and the length of the data area is zero. I
* think processes expect getmsg() to fill in dat.len
* after reading at most dat.maxlen octets from the
* stream. Since we're using sockets I can let
* read() look after it and frob return values
* appropriately (or inappropriately :-)
* -- newton@atdot.dotat.org XXX
*/
SCARG(&ra, fd) = SCARG(uap, fd);
SCARG(&ra, buf) = dat.buf;
SCARG(&ra, nbyte) = dat.maxlen;
if ((error = sys_read(p, &ra, retval)) != 0)
return error;
dat.len = *retval;
*retval = 0;
st->s_cmd = SVR4_TI_SENDTO_REQUEST;
break;
}
#endif
DPRINTF(("getmsg: Unknown state %x\n", st->s_cmd));
return EINVAL;
}
if (SCARG(uap, ctl)) {
if (ctl.len != -1)
if ((error = copyout(&sc, (caddr_t)(u_long)ctl.buf,
ctl.len)) != 0)
return error;
if ((error = copyout(&ctl, (caddr_t)(u_long)SCARG(uap, ctl),
sizeof(ctl))) != 0)
return error;
}
if (SCARG(uap, dat)) {
if ((error = copyout(&dat, (caddr_t)(u_long)SCARG(uap, dat),
sizeof(dat))) != 0)
return error;
}
if (SCARG(uap, flags)) { /* XXX: Need translation */
if ((error = copyout(&fl, (caddr_t)(u_long)SCARG(uap, flags),
sizeof(fl))) != 0)
return error;
}
*retval = 0;
#ifdef DEBUG_SVR4
show_msg("<getmsg", SCARG(uap, fd), SCARG(uap, ctl),
SCARG(uap, dat), fl);
#endif /* DEBUG_SVR4 */
return error;
}