svr4_stream.c revision 147965
1/*-
2 * Copyright (c) 1998 Mark Newton.  All rights reserved.
3 * Copyright (c) 1994, 1996 Christos Zoulas.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Christos Zoulas.
16 * 4. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Pretend that we have streams...
33 * Yes, this is gross.
34 *
35 * ToDo: The state machine for getmsg needs re-thinking
36 */
37
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: head/sys/compat/svr4/svr4_stream.c 147965 2005-07-13 15:14:33Z jhb $");
40
41#include "opt_compat.h"
42#include "opt_ktrace.h"
43#include "opt_mac.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/fcntl.h>
48#include <sys/filedesc.h>
49#include <sys/filio.h>
50#include <sys/lock.h>
51#include <sys/malloc.h>
52#include <sys/file.h> 		/* Must come after sys/malloc.h */
53#include <sys/mac.h>
54#include <sys/mbuf.h>
55#include <sys/mutex.h>
56#include <sys/proc.h>
57#include <sys/protosw.h>
58#include <sys/signal.h>
59#include <sys/signalvar.h>
60#include <sys/socket.h>
61#include <sys/socketvar.h>
62#include <sys/stat.h>
63#include <sys/syscallsubr.h>
64#include <sys/sysproto.h>
65#include <sys/uio.h>
66#include <sys/ktrace.h>		/* Must come after sys/uio.h */
67#include <sys/un.h>
68
69#include <netinet/in.h>
70
71#include <compat/svr4/svr4.h>
72#include <compat/svr4/svr4_types.h>
73#include <compat/svr4/svr4_util.h>
74#include <compat/svr4/svr4_signal.h>
75#include <compat/svr4/svr4_proto.h>
76#include <compat/svr4/svr4_stropts.h>
77#include <compat/svr4/svr4_timod.h>
78#include <compat/svr4/svr4_sockmod.h>
79#include <compat/svr4/svr4_ioctl.h>
80#include <compat/svr4/svr4_socket.h>
81
82/* Utils */
83static int clean_pipe(struct thread *, char *);
84static void getparm(struct file *, struct svr4_si_sockparms *);
85static int svr4_do_putmsg(struct thread *, struct svr4_sys_putmsg_args *,
86			       struct file *);
87static int svr4_do_getmsg(struct thread *, struct svr4_sys_getmsg_args *,
88			       struct file *);
89
90/* Address Conversions */
91static void sockaddr_to_netaddr_in(struct svr4_strmcmd *,
92					const struct sockaddr_in *);
93static void sockaddr_to_netaddr_un(struct svr4_strmcmd *,
94					const struct sockaddr_un *);
95static void netaddr_to_sockaddr_in(struct sockaddr_in *,
96					const struct svr4_strmcmd *);
97static void netaddr_to_sockaddr_un(struct sockaddr_un *,
98					const struct svr4_strmcmd *);
99
100/* stream ioctls */
101static int i_nread(struct file *, struct thread *, register_t *, int,
102			u_long, caddr_t);
103static int i_fdinsert(struct file *, struct thread *, register_t *, int,
104			   u_long, caddr_t);
105static int i_str(struct file *, struct thread *, register_t *, int,
106			u_long, caddr_t);
107static int i_setsig(struct file *, struct thread *, register_t *, int,
108			u_long, caddr_t);
109static int i_getsig(struct file *, struct thread *, register_t *, int,
110			u_long, caddr_t);
111static int _i_bind_rsvd(struct file *, struct thread *, register_t *, int,
112			     u_long, caddr_t);
113static int _i_rele_rsvd(struct file *, struct thread *, register_t *, int,
114			     u_long, caddr_t);
115
116/* i_str sockmod calls */
117static int sockmod(struct file *, int, struct svr4_strioctl *,
118			      struct thread *);
119static int si_listen(struct file *, int, struct svr4_strioctl *,
120			      struct thread *);
121static int si_ogetudata(struct file *, int, struct svr4_strioctl *,
122			      struct thread *);
123static int si_sockparams(struct file *, int, struct svr4_strioctl *,
124			      struct thread *);
125static int si_shutdown	(struct file *, int, struct svr4_strioctl *,
126			      struct thread *);
127static int si_getudata(struct file *, int, struct svr4_strioctl *,
128			      struct thread *);
129
130/* i_str timod calls */
131static int timod(struct file *, int, struct svr4_strioctl *, struct thread *);
132static int ti_getinfo(struct file *, int, struct svr4_strioctl *,
133			      struct thread *);
134static int ti_bind(struct file *, int, struct svr4_strioctl *, struct thread *);
135
136/* infrastructure */
137static int svr4_sendit(struct thread *td, int s, struct msghdr *mp, int flags);
138
139static int svr4_recvit(struct thread *td, int s, struct msghdr *mp,
140			    caddr_t namelenp);
141
142/* <sigh>  Ok, so we shouldn't use sendit() in uipc_syscalls.c because
143 * it isn't part of a "public" interface;  We're supposed to use
144 * pru_sosend instead.  Same goes for recvit()/pru_soreceive() for
145 * that matter.  Solution:  Suck sendit()/recvit() into here where we
146 * can do what we like.
147 *
148 * I hate code duplication.
149 *
150 * I will take out all the #ifdef COMPAT_OLDSOCK gumph, though.
151 */
152static int
153svr4_sendit(td, s, mp, flags)
154	register struct thread *td;
155	int s;
156	register struct msghdr *mp;
157	int flags;
158{
159	struct uio auio;
160	register struct iovec *iov;
161	register int i;
162	struct mbuf *control;
163	struct sockaddr *to;
164	int len, error;
165	struct socket *so;
166#ifdef KTRACE
167	struct uio *ktruio = NULL;
168#endif
169
170	if ((error = fgetsock(td, s, &so, NULL)) != 0)
171		return (error);
172
173#ifdef MAC
174	SOCK_LOCK(so);
175	error = mac_check_socket_send(td->td_ucred, so);
176	SOCK_UNLOCK(so);
177	if (error)
178		goto done1;
179#endif
180
181	auio.uio_iov = mp->msg_iov;
182	auio.uio_iovcnt = mp->msg_iovlen;
183	auio.uio_segflg = UIO_USERSPACE;
184	auio.uio_rw = UIO_WRITE;
185	auio.uio_td = td;
186	auio.uio_offset = 0;			/* XXX */
187	auio.uio_resid = 0;
188	iov = mp->msg_iov;
189	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
190		if ((auio.uio_resid += iov->iov_len) < 0) {
191			error = EINVAL;
192			goto done1;
193		}
194	}
195	if (mp->msg_name) {
196		error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
197		if (error)
198			goto done1;
199	} else {
200		to = 0;
201	}
202	if (mp->msg_control) {
203		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
204			error = EINVAL;
205			goto bad;
206		}
207		error = sockargs(&control, mp->msg_control,
208		    mp->msg_controllen, MT_CONTROL);
209		if (error)
210			goto bad;
211	} else {
212		control = 0;
213	}
214#ifdef KTRACE
215	if (KTRPOINT(td, KTR_GENIO))
216		ktruio = cloneuio(&auio);
217#endif
218	len = auio.uio_resid;
219	error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
220						     flags, td);
221	if (error) {
222		if (auio.uio_resid != len && (error == ERESTART ||
223		    error == EINTR || error == EWOULDBLOCK))
224			error = 0;
225		if (error == EPIPE) {
226			PROC_LOCK(td->td_proc);
227			psignal(td->td_proc, SIGPIPE);
228			PROC_UNLOCK(td->td_proc);
229		}
230	}
231	if (error == 0)
232		td->td_retval[0] = len - auio.uio_resid;
233#ifdef KTRACE
234	if (ktruio != NULL) {
235		ktruio->uio_resid = td->td_retval[0];
236		ktrgenio(s, UIO_WRITE, ktruio, error);
237	}
238#endif
239bad:
240	if (to)
241		FREE(to, M_SONAME);
242done1:
243	fputsock(so);
244	return (error);
245}
246
247static int
248svr4_recvit(td, s, mp, namelenp)
249	register struct thread *td;
250	int s;
251	register struct msghdr *mp;
252	caddr_t namelenp;
253{
254	struct uio auio;
255	register struct iovec *iov;
256	register int i;
257	int len, error;
258	struct mbuf *m, *control = 0;
259	caddr_t ctlbuf;
260	struct socket *so;
261	struct sockaddr *fromsa = 0;
262#ifdef KTRACE
263	struct uio *ktruio = NULL;
264#endif
265
266	if ((error = fgetsock(td, s, &so, NULL)) != 0)
267		return (error);
268
269#ifdef MAC
270	SOCK_LOCK(so);
271	error = mac_check_socket_receive(td->td_ucred, so);
272	SOCK_UNLOCK(so);
273	if (error)
274		goto done1;
275#endif
276
277	auio.uio_iov = mp->msg_iov;
278	auio.uio_iovcnt = mp->msg_iovlen;
279	auio.uio_segflg = UIO_USERSPACE;
280	auio.uio_rw = UIO_READ;
281	auio.uio_td = td;
282	auio.uio_offset = 0;			/* XXX */
283	auio.uio_resid = 0;
284	iov = mp->msg_iov;
285	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
286		if ((auio.uio_resid += iov->iov_len) < 0) {
287			error = EINVAL;
288			goto done1;
289		}
290	}
291#ifdef KTRACE
292	if (KTRPOINT(td, KTR_GENIO))
293		ktruio = cloneuio(&auio);
294#endif
295	len = auio.uio_resid;
296	error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
297	    (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
298	    &mp->msg_flags);
299	if (error) {
300		if (auio.uio_resid != len && (error == ERESTART ||
301		    error == EINTR || error == EWOULDBLOCK))
302			error = 0;
303	}
304#ifdef KTRACE
305	if (ktruio != NULL) {
306		ktruio->uio_resid = len - auio.uio_resid;
307		ktrgenio(s, UIO_READ, ktruio, error);
308	}
309#endif
310	if (error)
311		goto out;
312	td->td_retval[0] = len - auio.uio_resid;
313	if (mp->msg_name) {
314		len = mp->msg_namelen;
315		if (len <= 0 || fromsa == 0)
316			len = 0;
317		else {
318			/* save sa_len before it is destroyed by MSG_COMPAT */
319			len = MIN(len, fromsa->sa_len);
320			error = copyout(fromsa,
321			    (caddr_t)mp->msg_name, (unsigned)len);
322			if (error)
323				goto out;
324		}
325		mp->msg_namelen = len;
326		if (namelenp &&
327		    (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
328			goto out;
329		}
330	}
331	if (mp->msg_control) {
332		len = mp->msg_controllen;
333		m = control;
334		mp->msg_controllen = 0;
335		ctlbuf = (caddr_t) mp->msg_control;
336
337		while (m && len > 0) {
338			unsigned int tocopy;
339
340			if (len >= m->m_len)
341				tocopy = m->m_len;
342			else {
343				mp->msg_flags |= MSG_CTRUNC;
344				tocopy = len;
345			}
346
347			if ((error = copyout((caddr_t)mtod(m, caddr_t),
348					ctlbuf, tocopy)) != 0)
349				goto out;
350
351			ctlbuf += tocopy;
352			len -= tocopy;
353			m = m->m_next;
354		}
355		mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
356	}
357out:
358	if (fromsa)
359		FREE(fromsa, M_SONAME);
360	if (control)
361		m_freem(control);
362done1:
363	fputsock(so);
364	return (error);
365}
366
367#ifdef DEBUG_SVR4
368static void bufprint(u_char *, size_t);
369static int show_ioc(const char *, struct svr4_strioctl *);
370static int show_strbuf(struct svr4_strbuf *);
371static void show_msg(const char *, int, struct svr4_strbuf *,
372			  struct svr4_strbuf *, int);
373
374static void
375bufprint(buf, len)
376	u_char *buf;
377	size_t len;
378{
379	size_t i;
380
381	uprintf("\n\t");
382	for (i = 0; i < len; i++) {
383		uprintf("%x ", buf[i]);
384		if (i && (i % 16) == 0)
385			uprintf("\n\t");
386	}
387}
388
389static int
390show_ioc(str, ioc)
391	const char		*str;
392	struct svr4_strioctl	*ioc;
393{
394	u_char *ptr = NULL;
395	int len;
396	int error;
397
398	len = ioc->len;
399	if (len > 1024)
400		len = 1024;
401
402	if (len > 0) {
403		ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK);
404		if ((error = copyin(ioc->buf, ptr, len)) != 0) {
405			free((char *) ptr, M_TEMP);
406			return error;
407		}
408	}
409
410	uprintf("%s cmd = %ld, timeout = %d, len = %d, buf = %p { ",
411	    str, ioc->cmd, ioc->timeout, ioc->len, ioc->buf);
412
413	if (ptr != NULL)
414		bufprint(ptr, len);
415
416	uprintf("}\n");
417
418	if (ptr != NULL)
419		free((char *) ptr, M_TEMP);
420	return 0;
421}
422
423
424static int
425show_strbuf(str)
426	struct svr4_strbuf *str;
427{
428	int error;
429	u_char *ptr = NULL;
430	int maxlen = str->maxlen;
431	int len = str->len;
432
433	if (maxlen > 8192)
434		maxlen = 8192;
435
436	if (maxlen < 0)
437		maxlen = 0;
438
439	if (len >= maxlen)
440		len = maxlen;
441
442	if (len > 0) {
443	    ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK);
444
445	    if ((error = copyin(str->buf, ptr, len)) != 0) {
446		    free((char *) ptr, M_TEMP);
447		    return error;
448	    }
449	}
450
451	uprintf(", { %d, %d, %p=[ ", str->maxlen, str->len, str->buf);
452
453	if (ptr)
454		bufprint(ptr, len);
455
456	uprintf("]}");
457
458	if (ptr)
459		free((char *) ptr, M_TEMP);
460
461	return 0;
462}
463
464
465static void
466show_msg(str, fd, ctl, dat, flags)
467	const char		*str;
468	int			 fd;
469	struct svr4_strbuf	*ctl;
470	struct svr4_strbuf	*dat;
471	int			 flags;
472{
473	struct svr4_strbuf	buf;
474	int error;
475
476	uprintf("%s(%d", str, fd);
477	if (ctl != NULL) {
478		if ((error = copyin(ctl, &buf, sizeof(buf))) != 0)
479			return;
480		show_strbuf(&buf);
481	}
482	else
483		uprintf(", NULL");
484
485	if (dat != NULL) {
486		if ((error = copyin(dat, &buf, sizeof(buf))) != 0)
487			return;
488		show_strbuf(&buf);
489	}
490	else
491		uprintf(", NULL");
492
493	uprintf(", %x);\n", flags);
494}
495
496#endif /* DEBUG_SVR4 */
497
498/*
499 * We are faced with an interesting situation. On svr4 unix sockets
500 * are really pipes. But we really have sockets, and we might as
501 * well use them. At the point where svr4 calls TI_BIND, it has
502 * already created a named pipe for the socket using mknod(2).
503 * We need to create a socket with the same name when we bind,
504 * so we need to remove the pipe before, otherwise we'll get address
505 * already in use. So we *carefully* remove the pipe, to avoid
506 * using this as a random file removal tool. We use system calls
507 * to avoid code duplication.
508 */
509static int
510clean_pipe(td, path)
511	struct thread *td;
512	char *path;
513{
514	struct stat st;
515	int error;
516
517	error = kern_lstat(td, path, UIO_SYSSPACE, &st);
518
519	/*
520	 * Make sure we are dealing with a mode 0 named pipe.
521	 */
522	if ((st.st_mode & S_IFMT) != S_IFIFO)
523		return (0);
524
525	if ((st.st_mode & ALLPERMS) != 0)
526		return (0);
527
528	error = kern_unlink(td, path, UIO_SYSSPACE);
529	if (error)
530		DPRINTF(("clean_pipe: unlink failed %d\n", error));
531	return (error);
532}
533
534
535static void
536sockaddr_to_netaddr_in(sc, sain)
537	struct svr4_strmcmd *sc;
538	const struct sockaddr_in *sain;
539{
540	struct svr4_netaddr_in *na;
541	na = SVR4_ADDROF(sc);
542
543	na->family = sain->sin_family;
544	na->port = sain->sin_port;
545	na->addr = sain->sin_addr.s_addr;
546	DPRINTF(("sockaddr_in -> netaddr %d %d %lx\n", na->family, na->port,
547		 na->addr));
548}
549
550
551static void
552sockaddr_to_netaddr_un(sc, saun)
553	struct svr4_strmcmd *sc;
554	const struct sockaddr_un *saun;
555{
556	struct svr4_netaddr_un *na;
557	char *dst, *edst = ((char *) sc) + sc->offs + sizeof(na->family) + 1  -
558	    sizeof(*sc);
559	const char *src;
560
561	na = SVR4_ADDROF(sc);
562	na->family = saun->sun_family;
563	for (src = saun->sun_path, dst = na->path; (*dst++ = *src++) != '\0'; )
564		if (dst == edst)
565			break;
566	DPRINTF(("sockaddr_un -> netaddr %d %s\n", na->family, na->path));
567}
568
569
570static void
571netaddr_to_sockaddr_in(sain, sc)
572	struct sockaddr_in *sain;
573	const struct svr4_strmcmd *sc;
574{
575	const struct svr4_netaddr_in *na;
576
577
578	na = SVR4_C_ADDROF(sc);
579	memset(sain, 0, sizeof(*sain));
580	sain->sin_len = sizeof(*sain);
581	sain->sin_family = na->family;
582	sain->sin_port = na->port;
583	sain->sin_addr.s_addr = na->addr;
584	DPRINTF(("netaddr -> sockaddr_in %d %d %x\n", sain->sin_family,
585		 sain->sin_port, sain->sin_addr.s_addr));
586}
587
588
589static void
590netaddr_to_sockaddr_un(saun, sc)
591	struct sockaddr_un *saun;
592	const struct svr4_strmcmd *sc;
593{
594	const struct svr4_netaddr_un *na;
595	char *dst, *edst = &saun->sun_path[sizeof(saun->sun_path) - 1];
596	const char *src;
597
598	na = SVR4_C_ADDROF(sc);
599	memset(saun, 0, sizeof(*saun));
600	saun->sun_family = na->family;
601	for (src = na->path, dst = saun->sun_path; (*dst++ = *src++) != '\0'; )
602		if (dst == edst)
603			break;
604	saun->sun_len = dst - saun->sun_path;
605	DPRINTF(("netaddr -> sockaddr_un %d %s\n", saun->sun_family,
606		 saun->sun_path));
607}
608
609
610static void
611getparm(fp, pa)
612	struct file *fp;
613	struct svr4_si_sockparms *pa;
614{
615	struct svr4_strm *st;
616	struct socket *so;
617
618	st = svr4_stream_get(fp);
619	if (st == NULL)
620		return;
621
622	so = fp->f_data;
623
624	pa->family = st->s_family;
625
626	switch (so->so_type) {
627	case SOCK_DGRAM:
628		pa->type = SVR4_T_CLTS;
629		pa->protocol = IPPROTO_UDP;
630		DPRINTF(("getparm(dgram)\n"));
631		return;
632
633	case SOCK_STREAM:
634	        pa->type = SVR4_T_COTS;  /* What about T_COTS_ORD? XXX */
635		pa->protocol = IPPROTO_IP;
636		DPRINTF(("getparm(stream)\n"));
637		return;
638
639	case SOCK_RAW:
640		pa->type = SVR4_T_CLTS;
641		pa->protocol = IPPROTO_RAW;
642		DPRINTF(("getparm(raw)\n"));
643		return;
644
645	default:
646		pa->type = 0;
647		pa->protocol = 0;
648		DPRINTF(("getparm(type %d?)\n", so->so_type));
649		return;
650	}
651}
652
653
654static int
655si_ogetudata(fp, fd, ioc, td)
656	struct file		*fp;
657	int 			 fd;
658	struct svr4_strioctl	*ioc;
659	struct thread		*td;
660{
661	int error;
662	struct svr4_si_oudata ud;
663	struct svr4_si_sockparms pa;
664
665	if (ioc->len != sizeof(ud) && ioc->len != sizeof(ud) - sizeof(int)) {
666		DPRINTF(("SI_OGETUDATA: Wrong size %d != %d\n",
667			 sizeof(ud), ioc->len));
668		return EINVAL;
669	}
670
671	if ((error = copyin(ioc->buf, &ud, sizeof(ud))) != 0)
672		return error;
673
674	getparm(fp, &pa);
675
676	switch (pa.family) {
677	case AF_INET:
678	    ud.tidusize = 16384;
679	    ud.addrsize = sizeof(struct svr4_sockaddr_in);
680	    if (pa.type == SVR4_SOCK_STREAM)
681		    ud.etsdusize = 1;
682	    else
683		    ud.etsdusize = 0;
684	    break;
685
686	case AF_LOCAL:
687	    ud.tidusize = 65536;
688	    ud.addrsize = 128;
689	    ud.etsdusize = 128;
690	    break;
691
692	default:
693	    DPRINTF(("SI_OGETUDATA: Unsupported address family %d\n",
694		     pa.family));
695	    return ENOSYS;
696	}
697
698	/* I have no idea what these should be! */
699	ud.optsize = 128;
700	ud.tsdusize = 128;
701
702	ud.servtype = pa.type;
703
704	/* XXX: Fixme */
705	ud.so_state = 0;
706	ud.so_options = 0;
707	return copyout(&ud, ioc->buf, ioc->len);
708}
709
710
711static int
712si_sockparams(fp, fd, ioc, td)
713	struct file		*fp;
714	int 			 fd;
715	struct svr4_strioctl	*ioc;
716	struct thread		*td;
717{
718	struct svr4_si_sockparms pa;
719
720	getparm(fp, &pa);
721	return copyout(&pa, ioc->buf, sizeof(pa));
722}
723
724
725static int
726si_listen(fp, fd, ioc, td)
727	struct file		*fp;
728	int 			 fd;
729	struct svr4_strioctl	*ioc;
730	struct thread		*td;
731{
732	int error;
733	struct svr4_strm *st = svr4_stream_get(fp);
734	struct svr4_strmcmd lst;
735	struct listen_args la;
736
737	if (st == NULL)
738		return EINVAL;
739
740	if (ioc->len < 0 || ioc->len > sizeof(lst))
741		return EINVAL;
742
743	if ((error = copyin(ioc->buf, &lst, ioc->len)) != 0)
744		return error;
745
746	if (lst.cmd != SVR4_TI_OLD_BIND_REQUEST) {
747		DPRINTF(("si_listen: bad request %ld\n", lst.cmd));
748		return EINVAL;
749	}
750
751	/*
752	 * We are making assumptions again...
753	 */
754	la.s = fd;
755	DPRINTF(("SI_LISTEN: fileno %d backlog = %d\n", fd, 5));
756	la.backlog = 5;
757
758	if ((error = listen(td, &la)) != 0) {
759		DPRINTF(("SI_LISTEN: listen failed %d\n", error));
760		return error;
761	}
762
763	st->s_cmd = SVR4_TI__ACCEPT_WAIT;
764	lst.cmd = SVR4_TI_BIND_REPLY;
765
766	switch (st->s_family) {
767	case AF_INET:
768		/* XXX: Fill the length here */
769		break;
770
771	case AF_LOCAL:
772		lst.len = 140;
773		lst.pad[28] = 0x00000000;	/* magic again */
774		lst.pad[29] = 0x00000800;	/* magic again */
775		lst.pad[30] = 0x80001400;	/* magic again */
776		break;
777
778	default:
779		DPRINTF(("SI_LISTEN: Unsupported address family %d\n",
780		    st->s_family));
781		return ENOSYS;
782	}
783
784
785	if ((error = copyout(&lst, ioc->buf, ioc->len)) != 0)
786		return error;
787
788	return 0;
789}
790
791
792static int
793si_getudata(fp, fd, ioc, td)
794	struct file		*fp;
795	int 			 fd;
796	struct svr4_strioctl	*ioc;
797	struct thread		*td;
798{
799	int error;
800	struct svr4_si_udata ud;
801
802	if (sizeof(ud) != ioc->len) {
803		DPRINTF(("SI_GETUDATA: Wrong size %d != %d\n",
804			 sizeof(ud), ioc->len));
805		return EINVAL;
806	}
807
808	if ((error = copyin(ioc->buf, &ud, sizeof(ud))) != 0)
809		return error;
810
811	getparm(fp, &ud.sockparms);
812
813	switch (ud.sockparms.family) {
814	case AF_INET:
815	    DPRINTF(("getudata_inet\n"));
816	    ud.tidusize = 16384;
817	    ud.tsdusize = 16384;
818	    ud.addrsize = sizeof(struct svr4_sockaddr_in);
819	    if (ud.sockparms.type == SVR4_SOCK_STREAM)
820		    ud.etsdusize = 1;
821	    else
822		    ud.etsdusize = 0;
823	    ud.optsize = 0;
824	    break;
825
826	case AF_LOCAL:
827	    DPRINTF(("getudata_local\n"));
828	    ud.tidusize = 65536;
829	    ud.tsdusize = 128;
830	    ud.addrsize = 128;
831	    ud.etsdusize = 128;
832	    ud.optsize = 128;
833	    break;
834
835	default:
836	    DPRINTF(("SI_GETUDATA: Unsupported address family %d\n",
837		     ud.sockparms.family));
838	    return ENOSYS;
839	}
840
841
842	ud.servtype = ud.sockparms.type;
843	DPRINTF(("ud.servtype = %d\n", ud.servtype));
844	/* XXX: Fixme */
845	ud.so_state = 0;
846	ud.so_options = 0;
847	return copyout(&ud, ioc->buf, sizeof(ud));
848}
849
850
851static int
852si_shutdown(fp, fd, ioc, td)
853	struct file		*fp;
854	int 			 fd;
855	struct svr4_strioctl	*ioc;
856	struct thread		*td;
857{
858	int error;
859	struct shutdown_args ap;
860
861	if (ioc->len != sizeof(ap.how)) {
862		DPRINTF(("SI_SHUTDOWN: Wrong size %d != %d\n",
863			 sizeof(ap.how), ioc->len));
864		return EINVAL;
865	}
866
867	if ((error = copyin(ioc->buf, &ap.how, ioc->len)) != 0)
868		return error;
869
870	ap.s = fd;
871
872	return shutdown(td, &ap);
873}
874
875
876static int
877sockmod(fp, fd, ioc, td)
878	struct file		*fp;
879	int			 fd;
880	struct svr4_strioctl	*ioc;
881	struct thread		*td;
882{
883	switch (ioc->cmd) {
884	case SVR4_SI_OGETUDATA:
885		DPRINTF(("SI_OGETUDATA\n"));
886		return si_ogetudata(fp, fd, ioc, td);
887
888	case SVR4_SI_SHUTDOWN:
889		DPRINTF(("SI_SHUTDOWN\n"));
890		return si_shutdown(fp, fd, ioc, td);
891
892	case SVR4_SI_LISTEN:
893		DPRINTF(("SI_LISTEN\n"));
894		return si_listen(fp, fd, ioc, td);
895
896	case SVR4_SI_SETMYNAME:
897		DPRINTF(("SI_SETMYNAME\n"));
898		return 0;
899
900	case SVR4_SI_SETPEERNAME:
901		DPRINTF(("SI_SETPEERNAME\n"));
902		return 0;
903
904	case SVR4_SI_GETINTRANSIT:
905		DPRINTF(("SI_GETINTRANSIT\n"));
906		return 0;
907
908	case SVR4_SI_TCL_LINK:
909		DPRINTF(("SI_TCL_LINK\n"));
910		return 0;
911
912	case SVR4_SI_TCL_UNLINK:
913		DPRINTF(("SI_TCL_UNLINK\n"));
914		return 0;
915
916	case SVR4_SI_SOCKPARAMS:
917		DPRINTF(("SI_SOCKPARAMS\n"));
918		return si_sockparams(fp, fd, ioc, td);
919
920	case SVR4_SI_GETUDATA:
921		DPRINTF(("SI_GETUDATA\n"));
922		return si_getudata(fp, fd, ioc, td);
923
924	default:
925		DPRINTF(("Unknown sockmod ioctl %lx\n", ioc->cmd));
926		return 0;
927
928	}
929}
930
931
932static int
933ti_getinfo(fp, fd, ioc, td)
934	struct file		*fp;
935	int 			 fd;
936	struct svr4_strioctl	*ioc;
937	struct thread		*td;
938{
939	int error;
940	struct svr4_infocmd info;
941
942	memset(&info, 0, sizeof(info));
943
944	if (ioc->len < 0 || ioc->len > sizeof(info))
945		return EINVAL;
946
947	if ((error = copyin(ioc->buf, &info, ioc->len)) != 0)
948		return error;
949
950	if (info.cmd != SVR4_TI_INFO_REQUEST)
951		return EINVAL;
952
953	info.cmd = SVR4_TI_INFO_REPLY;
954	info.tsdu = 0;
955	info.etsdu = 1;
956	info.cdata = -2;
957	info.ddata = -2;
958	info.addr = 16;
959	info.opt = -1;
960	info.tidu = 16384;
961	info.serv = 2;
962	info.current = 0;
963	info.provider = 2;
964
965	ioc->len = sizeof(info);
966	if ((error = copyout(&info, ioc->buf, ioc->len)) != 0)
967		return error;
968
969	return 0;
970}
971
972
973static int
974ti_bind(fp, fd, ioc, td)
975	struct file		*fp;
976	int 			 fd;
977	struct svr4_strioctl	*ioc;
978	struct thread		*td;
979{
980	int error;
981	struct svr4_strm *st = svr4_stream_get(fp);
982	struct sockaddr_in sain;
983	struct sockaddr_un saun;
984	caddr_t sg;
985	void *skp, *sup = NULL;
986	int sasize;
987	struct svr4_strmcmd bnd;
988	struct bind_args ba;
989
990	if (st == NULL) {
991		DPRINTF(("ti_bind: bad file descriptor\n"));
992		return EINVAL;
993	}
994
995	if (ioc->len < 0 || ioc->len > sizeof(bnd))
996		return EINVAL;
997
998	if ((error = copyin(ioc->buf, &bnd, ioc->len)) != 0)
999		return error;
1000
1001	if (bnd.cmd != SVR4_TI_OLD_BIND_REQUEST) {
1002		DPRINTF(("ti_bind: bad request %ld\n", bnd.cmd));
1003		return EINVAL;
1004	}
1005
1006	switch (st->s_family) {
1007	case AF_INET:
1008		skp = &sain;
1009		sasize = sizeof(sain);
1010
1011		if (bnd.offs == 0)
1012			goto reply;
1013
1014		netaddr_to_sockaddr_in(&sain, &bnd);
1015
1016		DPRINTF(("TI_BIND: fam %d, port %d, addr %x\n",
1017			 sain.sin_family, sain.sin_port,
1018			 sain.sin_addr.s_addr));
1019		break;
1020
1021	case AF_LOCAL:
1022		skp = &saun;
1023		sasize = sizeof(saun);
1024		if (bnd.offs == 0)
1025			goto reply;
1026
1027		netaddr_to_sockaddr_un(&saun, &bnd);
1028
1029		if (saun.sun_path[0] == '\0')
1030			goto reply;
1031
1032		DPRINTF(("TI_BIND: fam %d, path %s\n",
1033			 saun.sun_family, saun.sun_path));
1034
1035		if ((error = clean_pipe(td, saun.sun_path)) != 0)
1036			return error;
1037
1038		bnd.pad[28] = 0x00001000;	/* magic again */
1039		break;
1040
1041	default:
1042		DPRINTF(("TI_BIND: Unsupported address family %d\n",
1043			 st->s_family));
1044		return ENOSYS;
1045	}
1046
1047	sg = stackgap_init();
1048	sup = stackgap_alloc(&sg, sasize);
1049
1050	if ((error = copyout(skp, sup, sasize)) != 0)
1051		return error;
1052
1053	ba.s = fd;
1054	DPRINTF(("TI_BIND: fileno %d\n", fd));
1055	ba.name = (void *) sup;
1056	ba.namelen = sasize;
1057
1058	if ((error = bind(td, &ba)) != 0) {
1059		DPRINTF(("TI_BIND: bind failed %d\n", error));
1060		return error;
1061	}
1062
1063reply:
1064	if (sup == NULL) {
1065		memset(&bnd, 0, sizeof(bnd));
1066		bnd.len = sasize + 4;
1067		bnd.offs = 0x10;	/* XXX */
1068	}
1069
1070	bnd.cmd = SVR4_TI_BIND_REPLY;
1071
1072	if ((error = copyout(&bnd, ioc->buf, ioc->len)) != 0)
1073		return error;
1074
1075	return 0;
1076}
1077
1078
1079static int
1080timod(fp, fd, ioc, td)
1081	struct file		*fp;
1082	int			 fd;
1083	struct svr4_strioctl	*ioc;
1084	struct thread		*td;
1085{
1086	switch (ioc->cmd) {
1087	case SVR4_TI_GETINFO:
1088		DPRINTF(("TI_GETINFO\n"));
1089		return ti_getinfo(fp, fd, ioc, td);
1090
1091	case SVR4_TI_OPTMGMT:
1092		DPRINTF(("TI_OPTMGMT\n"));
1093		return 0;
1094
1095	case SVR4_TI_BIND:
1096		DPRINTF(("TI_BIND\n"));
1097		return ti_bind(fp, fd, ioc, td);
1098
1099	case SVR4_TI_UNBIND:
1100		DPRINTF(("TI_UNBIND\n"));
1101		return 0;
1102
1103	default:
1104		DPRINTF(("Unknown timod ioctl %lx\n", ioc->cmd));
1105		return 0;
1106	}
1107}
1108
1109
1110int
1111svr4_stream_ti_ioctl(fp, td, retval, fd, cmd, dat)
1112	struct file *fp;
1113	struct thread *td;
1114	register_t *retval;
1115	int fd;
1116	u_long cmd;
1117	caddr_t dat;
1118{
1119	struct svr4_strbuf skb, *sub = (struct svr4_strbuf *) dat;
1120	struct svr4_strm *st = svr4_stream_get(fp);
1121	int error;
1122	void *skp, *sup;
1123	struct sockaddr_in sain;
1124	struct sockaddr_un saun;
1125	struct svr4_strmcmd sc;
1126	int sasize, oldsasize;
1127	caddr_t sg;
1128	int *lenp;
1129
1130	DPRINTF(("svr4_stream_ti_ioctl\n"));
1131
1132	if (st == NULL)
1133		return EINVAL;
1134
1135	sc.offs = 0x10;
1136
1137	if ((error = copyin(sub, &skb, sizeof(skb))) != 0) {
1138		DPRINTF(("ti_ioctl: error copying in strbuf\n"));
1139		return error;
1140	}
1141
1142	switch (st->s_family) {
1143	case AF_INET:
1144		skp = &sain;
1145		sasize = sizeof(sain);
1146		break;
1147
1148	case AF_LOCAL:
1149		skp = &saun;
1150		sasize = sizeof(saun);
1151		break;
1152
1153	default:
1154		DPRINTF(("ti_ioctl: Unsupported address family %d\n",
1155			 st->s_family));
1156		return ENOSYS;
1157	}
1158
1159	sg = stackgap_init();
1160	sup = stackgap_alloc(&sg, sasize);
1161	lenp = stackgap_alloc(&sg, sizeof(*lenp));
1162
1163	if ((error = copyout(&sasize, lenp, sizeof(*lenp))) != 0) {
1164		DPRINTF(("ti_ioctl: error copying out lenp\n"));
1165		return error;
1166	}
1167
1168	switch (cmd) {
1169	case SVR4_TI_GETMYNAME:
1170		DPRINTF(("TI_GETMYNAME\n"));
1171		{
1172			struct getsockname_args ap;
1173			ap.fdes = fd;
1174			ap.asa = sup;
1175			ap.alen = lenp;
1176			if ((error = getsockname(td, &ap)) != 0) {
1177				DPRINTF(("ti_ioctl: getsockname error\n"));
1178				return error;
1179			}
1180		}
1181		break;
1182
1183	case SVR4_TI_GETPEERNAME:
1184		DPRINTF(("TI_GETPEERNAME\n"));
1185		{
1186			struct getpeername_args ap;
1187			ap.fdes = fd;
1188			ap.asa = sup;
1189			ap.alen = lenp;
1190			if ((error = getpeername(td, &ap)) != 0) {
1191				DPRINTF(("ti_ioctl: getpeername error\n"));
1192				return error;
1193			}
1194		}
1195		break;
1196
1197	case SVR4_TI_SETMYNAME:
1198		DPRINTF(("TI_SETMYNAME\n"));
1199		return 0;
1200
1201	case SVR4_TI_SETPEERNAME:
1202		DPRINTF(("TI_SETPEERNAME\n"));
1203		return 0;
1204	default:
1205		DPRINTF(("ti_ioctl: Unknown ioctl %lx\n", cmd));
1206		return ENOSYS;
1207	}
1208
1209	if ((error = copyin(sup, skp, sasize)) != 0) {
1210		DPRINTF(("ti_ioctl: error copying in socket data\n"));
1211		return error;
1212	}
1213
1214	oldsasize = sasize;
1215
1216	if ((error = copyin(lenp, &sasize, sizeof(*lenp))) != 0) {
1217		DPRINTF(("ti_ioctl: error copying in socket size\n"));
1218		return error;
1219	}
1220
1221	if (sasize < 0 || sasize > oldsasize)
1222		return EINVAL;
1223
1224	switch (st->s_family) {
1225	case AF_INET:
1226		sockaddr_to_netaddr_in(&sc, &sain);
1227		skb.len = sasize;
1228		break;
1229
1230	case AF_LOCAL:
1231		sockaddr_to_netaddr_un(&sc, &saun);
1232		skb.len = sasize + 4;
1233		break;
1234
1235	default:
1236		return ENOSYS;
1237	}
1238
1239
1240	if ((error = copyout(SVR4_ADDROF(&sc), skb.buf, sasize)) != 0) {
1241		DPRINTF(("ti_ioctl: error copying out socket data\n"));
1242		return error;
1243	}
1244
1245
1246	if ((error = copyout(&skb, sub, sizeof(skb))) != 0) {
1247		DPRINTF(("ti_ioctl: error copying out strbuf\n"));
1248		return error;
1249	}
1250
1251	return error;
1252}
1253
1254
1255
1256
1257static int
1258i_nread(fp, td, retval, fd, cmd, dat)
1259	struct file *fp;
1260	struct thread *td;
1261	register_t *retval;
1262	int fd;
1263	u_long cmd;
1264	caddr_t dat;
1265{
1266	int error;
1267	int nread = 0;
1268
1269	/*
1270	 * We are supposed to return the message length in nread, and the
1271	 * number of messages in retval. We don't have the notion of number
1272	 * of stream messages, so we just find out if we have any bytes waiting
1273	 * for us, and if we do, then we assume that we have at least one
1274	 * message waiting for us.
1275	 */
1276	if ((error = fo_ioctl(fp, FIONREAD, (caddr_t) &nread, td->td_ucred,
1277	    td)) != 0)
1278		return error;
1279
1280	if (nread != 0)
1281		*retval = 1;
1282	else
1283		*retval = 0;
1284
1285	return copyout(&nread, dat, sizeof(nread));
1286}
1287
1288static int
1289i_fdinsert(fp, td, retval, fd, cmd, dat)
1290	struct file *fp;
1291	struct thread *td;
1292	register_t *retval;
1293	int fd;
1294	u_long cmd;
1295	caddr_t dat;
1296{
1297	/*
1298	 * Major hack again here. We assume that we are using this to
1299	 * implement accept(2). If that is the case, we have already
1300	 * called accept, and we have stored the file descriptor in
1301	 * afd. We find the file descriptor that the code wants to use
1302	 * in fd insert, and then we dup2() our accepted file descriptor
1303	 * to it.
1304	 */
1305	int error;
1306	struct svr4_strm *st = svr4_stream_get(fp);
1307	struct svr4_strfdinsert fdi;
1308	struct dup2_args d2p;
1309	struct close_args clp;
1310
1311	if (st == NULL) {
1312		DPRINTF(("fdinsert: bad file type\n"));
1313		return EINVAL;
1314	}
1315
1316	if (st->s_afd == -1) {
1317		DPRINTF(("fdinsert: accept fd not found\n"));
1318		return ENOENT;
1319	}
1320
1321	if ((error = copyin(dat, &fdi, sizeof(fdi))) != 0) {
1322		DPRINTF(("fdinsert: copyin failed %d\n", error));
1323		return error;
1324	}
1325
1326	d2p.from = st->s_afd;
1327	d2p.to = fdi.fd;
1328
1329	if ((error = dup2(td, &d2p)) != 0) {
1330		DPRINTF(("fdinsert: dup2(%d, %d) failed %d\n",
1331		    st->s_afd, fdi.fd, error));
1332		return error;
1333	}
1334
1335	clp.fd = st->s_afd;
1336
1337	if ((error = close(td, &clp)) != 0) {
1338		DPRINTF(("fdinsert: close(%d) failed %d\n",
1339		    st->s_afd, error));
1340		return error;
1341	}
1342
1343	st->s_afd = -1;
1344
1345	*retval = 0;
1346	return 0;
1347}
1348
1349
1350static int
1351_i_bind_rsvd(fp, td, retval, fd, cmd, dat)
1352	struct file *fp;
1353	struct thread *td;
1354	register_t *retval;
1355	int fd;
1356	u_long cmd;
1357	caddr_t dat;
1358{
1359	struct mkfifo_args ap;
1360
1361	/*
1362	 * This is a supposed to be a kernel and library only ioctl.
1363	 * It gets called before ti_bind, when we have a unix
1364	 * socket, to physically create the socket transport and
1365	 * ``reserve'' it. I don't know how this get reserved inside
1366	 * the kernel, but we are going to create it nevertheless.
1367	 */
1368	ap.path = dat;
1369	ap.mode = S_IFIFO;
1370
1371	return mkfifo(td, &ap);
1372}
1373
1374static int
1375_i_rele_rsvd(fp, td, retval, fd, cmd, dat)
1376	struct file *fp;
1377	struct thread *td;
1378	register_t *retval;
1379	int fd;
1380	u_long cmd;
1381	caddr_t dat;
1382{
1383	struct unlink_args ap;
1384
1385	/*
1386	 * This is a supposed to be a kernel and library only ioctl.
1387	 * I guess it is supposed to release the socket.
1388	 */
1389	ap.path = dat;
1390
1391	return unlink(td, &ap);
1392}
1393
1394static int
1395i_str(fp, td, retval, fd, cmd, dat)
1396	struct file *fp;
1397	struct thread *td;
1398	register_t *retval;
1399	int fd;
1400	u_long cmd;
1401	caddr_t dat;
1402{
1403	int			 error;
1404	struct svr4_strioctl	 ioc;
1405
1406	if ((error = copyin(dat, &ioc, sizeof(ioc))) != 0)
1407		return error;
1408
1409#ifdef DEBUG_SVR4
1410	if ((error = show_ioc(">", &ioc)) != 0)
1411		return error;
1412#endif /* DEBUG_SVR4 */
1413
1414	switch (ioc.cmd & 0xff00) {
1415	case SVR4_SIMOD:
1416		if ((error = sockmod(fp, fd, &ioc, td)) != 0)
1417			return error;
1418		break;
1419
1420	case SVR4_TIMOD:
1421		if ((error = timod(fp, fd, &ioc, td)) != 0)
1422			return error;
1423		break;
1424
1425	default:
1426		DPRINTF(("Unimplemented module %c %ld\n",
1427			 (char) (cmd >> 8), cmd & 0xff));
1428		return 0;
1429	}
1430
1431#ifdef DEBUG_SVR4
1432	if ((error = show_ioc("<", &ioc)) != 0)
1433		return error;
1434#endif /* DEBUG_SVR4 */
1435	return copyout(&ioc, dat, sizeof(ioc));
1436}
1437
1438static int
1439i_setsig(fp, td, retval, fd, cmd, dat)
1440	struct file *fp;
1441	struct thread *td;
1442	register_t *retval;
1443	int fd;
1444	u_long cmd;
1445	caddr_t dat;
1446{
1447	/*
1448	 * This is the best we can do for now; we cannot generate
1449	 * signals only for specific events so the signal mask gets
1450	 * ignored; we save it just to pass it to a possible I_GETSIG...
1451	 *
1452	 * We alse have to fix the O_ASYNC fcntl bit, so the
1453	 * process will get SIGPOLLs.
1454	 */
1455	int error;
1456	register_t oflags, flags;
1457	struct svr4_strm *st = svr4_stream_get(fp);
1458
1459	if (st == NULL) {
1460		DPRINTF(("i_setsig: bad file descriptor\n"));
1461		return EINVAL;
1462	}
1463	/* get old status flags */
1464	error = kern_fcntl(td, fd, F_GETFL, 0);
1465	if (error)
1466		return (error);
1467
1468	oflags = td->td_retval[0];
1469
1470	/* update the flags */
1471	if (dat != NULL) {
1472		int mask;
1473
1474		flags = oflags | O_ASYNC;
1475		if ((error = copyin(dat, &mask, sizeof(mask))) != 0) {
1476			  DPRINTF(("i_setsig: bad eventmask pointer\n"));
1477			  return error;
1478		}
1479		if (mask & SVR4_S_ALLMASK) {
1480			  DPRINTF(("i_setsig: bad eventmask data %x\n", mask));
1481			  return EINVAL;
1482		}
1483		st->s_eventmask = mask;
1484	}
1485	else {
1486		flags = oflags & ~O_ASYNC;
1487		st->s_eventmask = 0;
1488	}
1489
1490	/* set the new flags, if changed */
1491	if (flags != oflags) {
1492		error = kern_fcntl(td, fd, F_SETFL, flags);
1493		if (error)
1494			return (error);
1495		flags = td->td_retval[0];
1496	}
1497
1498	/* set up SIGIO receiver if needed */
1499	if (dat != NULL)
1500		return (kern_fcntl(td, fd, F_SETOWN, td->td_proc->p_pid));
1501	return 0;
1502}
1503
1504static int
1505i_getsig(fp, td, retval, fd, cmd, dat)
1506	struct file *fp;
1507	struct thread *td;
1508	register_t *retval;
1509	int fd;
1510	u_long cmd;
1511	caddr_t dat;
1512{
1513	int error;
1514
1515	if (dat != NULL) {
1516		struct svr4_strm *st = svr4_stream_get(fp);
1517
1518		if (st == NULL) {
1519			DPRINTF(("i_getsig: bad file descriptor\n"));
1520			return EINVAL;
1521		}
1522		if ((error = copyout(&st->s_eventmask, dat,
1523				     sizeof(st->s_eventmask))) != 0) {
1524			DPRINTF(("i_getsig: bad eventmask pointer\n"));
1525			return error;
1526		}
1527	}
1528	return 0;
1529}
1530
1531int
1532svr4_stream_ioctl(fp, td, retval, fd, cmd, dat)
1533	struct file *fp;
1534	struct thread *td;
1535	register_t *retval;
1536	int fd;
1537	u_long cmd;
1538	caddr_t dat;
1539{
1540	*retval = 0;
1541
1542	/*
1543	 * All the following stuff assumes "sockmod" is pushed...
1544	 */
1545	switch (cmd) {
1546	case SVR4_I_NREAD:
1547		DPRINTF(("I_NREAD\n"));
1548		return i_nread(fp, td, retval, fd, cmd, dat);
1549
1550	case SVR4_I_PUSH:
1551		DPRINTF(("I_PUSH %p\n", dat));
1552#if defined(DEBUG_SVR4)
1553		show_strbuf((struct svr4_strbuf *)dat);
1554#endif
1555		return 0;
1556
1557	case SVR4_I_POP:
1558		DPRINTF(("I_POP\n"));
1559		return 0;
1560
1561	case SVR4_I_LOOK:
1562		DPRINTF(("I_LOOK\n"));
1563		return 0;
1564
1565	case SVR4_I_FLUSH:
1566		DPRINTF(("I_FLUSH\n"));
1567		return 0;
1568
1569	case SVR4_I_SRDOPT:
1570		DPRINTF(("I_SRDOPT\n"));
1571		return 0;
1572
1573	case SVR4_I_GRDOPT:
1574		DPRINTF(("I_GRDOPT\n"));
1575		return 0;
1576
1577	case SVR4_I_STR:
1578		DPRINTF(("I_STR\n"));
1579		return i_str(fp, td, retval, fd, cmd, dat);
1580
1581	case SVR4_I_SETSIG:
1582		DPRINTF(("I_SETSIG\n"));
1583		return i_setsig(fp, td, retval, fd, cmd, dat);
1584
1585	case SVR4_I_GETSIG:
1586	        DPRINTF(("I_GETSIG\n"));
1587		return i_getsig(fp, td, retval, fd, cmd, dat);
1588
1589	case SVR4_I_FIND:
1590		DPRINTF(("I_FIND\n"));
1591		/*
1592		 * Here we are not pushing modules really, we just
1593		 * pretend all are present
1594		 */
1595		*retval = 0;
1596		return 0;
1597
1598	case SVR4_I_LINK:
1599		DPRINTF(("I_LINK\n"));
1600		return 0;
1601
1602	case SVR4_I_UNLINK:
1603		DPRINTF(("I_UNLINK\n"));
1604		return 0;
1605
1606	case SVR4_I_ERECVFD:
1607		DPRINTF(("I_ERECVFD\n"));
1608		return 0;
1609
1610	case SVR4_I_PEEK:
1611		DPRINTF(("I_PEEK\n"));
1612		return 0;
1613
1614	case SVR4_I_FDINSERT:
1615		DPRINTF(("I_FDINSERT\n"));
1616		return i_fdinsert(fp, td, retval, fd, cmd, dat);
1617
1618	case SVR4_I_SENDFD:
1619		DPRINTF(("I_SENDFD\n"));
1620		return 0;
1621
1622	case SVR4_I_RECVFD:
1623		DPRINTF(("I_RECVFD\n"));
1624		return 0;
1625
1626	case SVR4_I_SWROPT:
1627		DPRINTF(("I_SWROPT\n"));
1628		return 0;
1629
1630	case SVR4_I_GWROPT:
1631		DPRINTF(("I_GWROPT\n"));
1632		return 0;
1633
1634	case SVR4_I_LIST:
1635		DPRINTF(("I_LIST\n"));
1636		return 0;
1637
1638	case SVR4_I_PLINK:
1639		DPRINTF(("I_PLINK\n"));
1640		return 0;
1641
1642	case SVR4_I_PUNLINK:
1643		DPRINTF(("I_PUNLINK\n"));
1644		return 0;
1645
1646	case SVR4_I_SETEV:
1647		DPRINTF(("I_SETEV\n"));
1648		return 0;
1649
1650	case SVR4_I_GETEV:
1651		DPRINTF(("I_GETEV\n"));
1652		return 0;
1653
1654	case SVR4_I_STREV:
1655		DPRINTF(("I_STREV\n"));
1656		return 0;
1657
1658	case SVR4_I_UNSTREV:
1659		DPRINTF(("I_UNSTREV\n"));
1660		return 0;
1661
1662	case SVR4_I_FLUSHBAND:
1663		DPRINTF(("I_FLUSHBAND\n"));
1664		return 0;
1665
1666	case SVR4_I_CKBAND:
1667		DPRINTF(("I_CKBAND\n"));
1668		return 0;
1669
1670	case SVR4_I_GETBAND:
1671		DPRINTF(("I_GETBANK\n"));
1672		return 0;
1673
1674	case SVR4_I_ATMARK:
1675		DPRINTF(("I_ATMARK\n"));
1676		return 0;
1677
1678	case SVR4_I_SETCLTIME:
1679		DPRINTF(("I_SETCLTIME\n"));
1680		return 0;
1681
1682	case SVR4_I_GETCLTIME:
1683		DPRINTF(("I_GETCLTIME\n"));
1684		return 0;
1685
1686	case SVR4_I_CANPUT:
1687		DPRINTF(("I_CANPUT\n"));
1688		return 0;
1689
1690	case SVR4__I_BIND_RSVD:
1691		DPRINTF(("_I_BIND_RSVD\n"));
1692		return _i_bind_rsvd(fp, td, retval, fd, cmd, dat);
1693
1694	case SVR4__I_RELE_RSVD:
1695		DPRINTF(("_I_RELE_RSVD\n"));
1696		return _i_rele_rsvd(fp, td, retval, fd, cmd, dat);
1697
1698	default:
1699		DPRINTF(("unimpl cmd = %lx\n", cmd));
1700		break;
1701	}
1702
1703	return 0;
1704}
1705
1706
1707
1708int
1709svr4_sys_putmsg(td, uap)
1710	register struct thread *td;
1711	struct svr4_sys_putmsg_args *uap;
1712{
1713	struct file     *fp;
1714	int error;
1715
1716	if ((error = fget(td, uap->fd, &fp)) != 0) {
1717#ifdef DEBUG_SVR4
1718	        uprintf("putmsg: bad fp\n");
1719#endif
1720		return EBADF;
1721	}
1722	error = svr4_do_putmsg(td, uap, fp);
1723	fdrop(fp, td);
1724	return (error);
1725}
1726
1727static int
1728svr4_do_putmsg(td, uap, fp)
1729	struct thread *td;
1730	struct svr4_sys_putmsg_args *uap;
1731	struct file	*fp;
1732{
1733	struct svr4_strbuf dat, ctl;
1734	struct svr4_strmcmd sc;
1735	struct sockaddr_in sain;
1736	struct sockaddr_un saun;
1737	void *skp, *sup;
1738	int sasize, *retval;
1739	struct svr4_strm *st;
1740	int error;
1741	caddr_t sg;
1742
1743	retval = td->td_retval;
1744
1745#ifdef DEBUG_SVR4
1746	show_msg(">putmsg", uap->fd, uap->ctl,
1747		 uap->dat, uap->flags);
1748#endif /* DEBUG_SVR4 */
1749
1750	FILE_LOCK_ASSERT(fp, MA_NOTOWNED);
1751
1752	if (uap->ctl != NULL) {
1753	  if ((error = copyin(uap->ctl, &ctl, sizeof(ctl))) != 0) {
1754#ifdef DEBUG_SVR4
1755	    uprintf("putmsg: copyin(): %d\n", error);
1756#endif
1757	    return error;
1758	  }
1759	}
1760	else
1761		ctl.len = -1;
1762
1763	if (uap->dat != NULL) {
1764	  if ((error = copyin(uap->dat, &dat, sizeof(dat))) != 0) {
1765#ifdef DEBUG_SVR4
1766	    uprintf("putmsg: copyin(): %d (2)\n", error);
1767#endif
1768	    return error;
1769	  }
1770	}
1771	else
1772		dat.len = -1;
1773
1774	/*
1775	 * Only for sockets for now.
1776	 */
1777	if ((st = svr4_stream_get(fp)) == NULL) {
1778		DPRINTF(("putmsg: bad file type\n"));
1779		return EINVAL;
1780	}
1781
1782	if (ctl.len < 0 || ctl.len > sizeof(sc)) {
1783		DPRINTF(("putmsg: Bad control size %d != %d\n", ctl.len,
1784			 sizeof(struct svr4_strmcmd)));
1785		return EINVAL;
1786	}
1787
1788	if ((error = copyin(ctl.buf, &sc, ctl.len)) != 0)
1789		return error;
1790
1791	switch (st->s_family) {
1792	case AF_INET:
1793	        if (sc.len != sizeof(sain)) {
1794		        if (sc.cmd == SVR4_TI_DATA_REQUEST) {
1795			        struct write_args wa;
1796
1797				/* Solaris seems to use sc.cmd = 3 to
1798				 * send "expedited" data.  telnet uses
1799				 * this for options processing, sending EOF,
1800				 * etc.  I'm sure other things use it too.
1801				 * I don't have any documentation
1802				 * on it, so I'm making a guess that this
1803				 * is how it works. newton@atdot.dotat.org XXX
1804				 */
1805				DPRINTF(("sending expedited data ??\n"));
1806				wa.fd = uap->fd;
1807				wa.buf = dat.buf;
1808				wa.nbyte = dat.len;
1809				return write(td, &wa);
1810			}
1811	                DPRINTF(("putmsg: Invalid inet length %ld\n", sc.len));
1812	                return EINVAL;
1813	        }
1814	        netaddr_to_sockaddr_in(&sain, &sc);
1815	        skp = &sain;
1816	        sasize = sizeof(sain);
1817	        error = sain.sin_family != st->s_family;
1818		break;
1819
1820	case AF_LOCAL:
1821		if (ctl.len == 8) {
1822			/* We are doing an accept; succeed */
1823			DPRINTF(("putmsg: Do nothing\n"));
1824			*retval = 0;
1825			return 0;
1826		}
1827		else {
1828			/* Maybe we've been given a device/inode pair */
1829			dev_t *dev = SVR4_ADDROF(&sc);
1830			ino_t *ino = (ino_t *) &dev[1];
1831			skp = svr4_find_socket(td, fp, *dev, *ino);
1832			if (skp == NULL) {
1833				skp = &saun;
1834				/* I guess we have it by name */
1835				netaddr_to_sockaddr_un(skp, &sc);
1836			}
1837			sasize = sizeof(saun);
1838		}
1839		break;
1840
1841	default:
1842		DPRINTF(("putmsg: Unsupported address family %d\n",
1843			 st->s_family));
1844		return ENOSYS;
1845	}
1846
1847	sg = stackgap_init();
1848	sup = stackgap_alloc(&sg, sasize);
1849
1850	if ((error = copyout(skp, sup, sasize)) != 0)
1851		return error;
1852
1853	switch (st->s_cmd = sc.cmd) {
1854	case SVR4_TI_CONNECT_REQUEST:	/* connect 	*/
1855		{
1856			struct connect_args co;
1857
1858			co.s = uap->fd;
1859			co.name = (void *) sup;
1860			co.namelen = (int) sasize;
1861
1862			return connect(td, &co);
1863		}
1864
1865	case SVR4_TI_SENDTO_REQUEST:	/* sendto 	*/
1866		{
1867			struct msghdr msg;
1868			struct iovec aiov;
1869
1870			msg.msg_name = (caddr_t) sup;
1871			msg.msg_namelen = sasize;
1872			msg.msg_iov = &aiov;
1873			msg.msg_iovlen = 1;
1874			msg.msg_control = 0;
1875			msg.msg_flags = 0;
1876			aiov.iov_base = dat.buf;
1877			aiov.iov_len = dat.len;
1878#if 0
1879			error = so->so_proto->pr_usrreqs->pru_sosend(so, 0,
1880					      uio, 0, 0, 0, uio->uio_td);
1881#endif
1882			error = svr4_sendit(td, uap->fd, &msg,
1883				       uap->flags);
1884			DPRINTF(("sendto_request error: %d\n", error));
1885			*retval = 0;
1886			return error;
1887		}
1888
1889	default:
1890		DPRINTF(("putmsg: Unimplemented command %lx\n", sc.cmd));
1891		return ENOSYS;
1892	}
1893}
1894
1895int
1896svr4_sys_getmsg(td, uap)
1897	struct thread *td;
1898	struct svr4_sys_getmsg_args *uap;
1899{
1900	struct file     *fp;
1901	int error;
1902
1903	if ((error = fget(td, uap->fd, &fp)) != 0) {
1904#ifdef DEBUG_SVR4
1905	        uprintf("getmsg: bad fp\n");
1906#endif
1907		return EBADF;
1908	}
1909	error = svr4_do_getmsg(td, uap, fp);
1910	fdrop(fp, td);
1911	return (error);
1912}
1913
1914int
1915svr4_do_getmsg(td, uap, fp)
1916	register struct thread *td;
1917	struct svr4_sys_getmsg_args *uap;
1918	struct file *fp;
1919{
1920	struct getpeername_args ga;
1921	struct accept_args aa;
1922	struct svr4_strbuf dat, ctl;
1923	struct svr4_strmcmd sc;
1924	int error, *retval;
1925	struct msghdr msg;
1926	struct iovec aiov;
1927	struct sockaddr_in sain;
1928	struct sockaddr_un saun;
1929	void *skp, *sup;
1930	int sasize;
1931	struct svr4_strm *st;
1932	int *flen;
1933	int fl;
1934	caddr_t sg;
1935
1936	retval = td->td_retval;
1937
1938	FILE_LOCK_ASSERT(fp, MA_NOTOWNED);
1939
1940	memset(&sc, 0, sizeof(sc));
1941
1942#ifdef DEBUG_SVR4
1943	show_msg(">getmsg", uap->fd, uap->ctl,
1944		 uap->dat, 0);
1945#endif /* DEBUG_SVR4 */
1946
1947	if (uap->ctl != NULL) {
1948		if ((error = copyin(uap->ctl, &ctl, sizeof(ctl))) != 0)
1949			return error;
1950		if (ctl.len < 0)
1951			return EINVAL;
1952	}
1953	else {
1954		ctl.len = -1;
1955		ctl.maxlen = 0;
1956	}
1957
1958	if (uap->dat != NULL) {
1959	    	if ((error = copyin(uap->dat, &dat, sizeof(dat))) != 0)
1960			return error;
1961	}
1962	else {
1963		dat.len = -1;
1964		dat.maxlen = 0;
1965	}
1966
1967	/*
1968	 * Only for sockets for now.
1969	 */
1970	if ((st = svr4_stream_get(fp)) == NULL) {
1971		DPRINTF(("getmsg: bad file type\n"));
1972		return EINVAL;
1973	}
1974
1975	if (ctl.maxlen == -1 || dat.maxlen == -1) {
1976		DPRINTF(("getmsg: Cannot handle -1 maxlen (yet)\n"));
1977		return ENOSYS;
1978	}
1979
1980	switch (st->s_family) {
1981	case AF_INET:
1982		skp = &sain;
1983		sasize = sizeof(sain);
1984		break;
1985
1986	case AF_LOCAL:
1987		skp = &saun;
1988		sasize = sizeof(saun);
1989		break;
1990
1991	default:
1992		DPRINTF(("getmsg: Unsupported address family %d\n",
1993			 st->s_family));
1994		return ENOSYS;
1995	}
1996
1997	sg = stackgap_init();
1998	sup = stackgap_alloc(&sg, sasize);
1999	flen = (int *) stackgap_alloc(&sg, sizeof(*flen));
2000
2001	fl = sasize;
2002	if ((error = copyout(&fl, flen, sizeof(fl))) != 0)
2003		return error;
2004
2005	switch (st->s_cmd) {
2006	case SVR4_TI_CONNECT_REQUEST:
2007		DPRINTF(("getmsg: TI_CONNECT_REQUEST\n"));
2008		/*
2009		 * We do the connect in one step, so the putmsg should
2010		 * have gotten the error.
2011		 */
2012		sc.cmd = SVR4_TI_OK_REPLY;
2013		sc.len = 0;
2014
2015		ctl.len = 8;
2016		dat.len = -1;
2017		fl = 1;
2018		st->s_cmd = sc.cmd;
2019		break;
2020
2021	case SVR4_TI_OK_REPLY:
2022		DPRINTF(("getmsg: TI_OK_REPLY\n"));
2023		/*
2024		 * We are immediately after a connect reply, so we send
2025		 * a connect verification.
2026		 */
2027
2028		ga.fdes = uap->fd;
2029		ga.asa = (void *) sup;
2030		ga.alen = flen;
2031
2032		if ((error = getpeername(td, &ga)) != 0) {
2033			DPRINTF(("getmsg: getpeername failed %d\n", error));
2034			return error;
2035		}
2036
2037		if ((error = copyin(sup, skp, sasize)) != 0)
2038			return error;
2039
2040		sc.cmd = SVR4_TI_CONNECT_REPLY;
2041		sc.pad[0] = 0x4;
2042		sc.offs = 0x18;
2043		sc.pad[1] = 0x14;
2044		sc.pad[2] = 0x04000402;
2045
2046		switch (st->s_family) {
2047		case AF_INET:
2048			sc.len = sasize;
2049			sockaddr_to_netaddr_in(&sc, &sain);
2050			break;
2051
2052		case AF_LOCAL:
2053			sc.len = sasize + 4;
2054			sockaddr_to_netaddr_un(&sc, &saun);
2055			break;
2056
2057		default:
2058			return ENOSYS;
2059		}
2060
2061		ctl.len = 40;
2062		dat.len = -1;
2063		fl = 0;
2064		st->s_cmd = sc.cmd;
2065		break;
2066
2067	case SVR4_TI__ACCEPT_OK:
2068		DPRINTF(("getmsg: TI__ACCEPT_OK\n"));
2069		/*
2070		 * We do the connect in one step, so the putmsg should
2071		 * have gotten the error.
2072		 */
2073		sc.cmd = SVR4_TI_OK_REPLY;
2074		sc.len = 1;
2075
2076		ctl.len = 8;
2077		dat.len = -1;
2078		fl = 1;
2079		st->s_cmd = SVR4_TI__ACCEPT_WAIT;
2080		break;
2081
2082	case SVR4_TI__ACCEPT_WAIT:
2083		DPRINTF(("getmsg: TI__ACCEPT_WAIT\n"));
2084		/*
2085		 * We are after a listen, so we try to accept...
2086		 */
2087		aa.s = uap->fd;
2088		aa.name = (void *) sup;
2089		aa.anamelen = flen;
2090
2091		if ((error = accept(td, &aa)) != 0) {
2092			DPRINTF(("getmsg: accept failed %d\n", error));
2093			return error;
2094		}
2095
2096		st->s_afd = *retval;
2097
2098		DPRINTF(("getmsg: Accept fd = %d\n", st->s_afd));
2099
2100		if ((error = copyin(sup, skp, sasize)) != 0)
2101			return error;
2102
2103		sc.cmd = SVR4_TI_ACCEPT_REPLY;
2104		sc.offs = 0x18;
2105		sc.pad[0] = 0x0;
2106
2107		switch (st->s_family) {
2108		case AF_INET:
2109			sc.pad[1] = 0x28;
2110			sockaddr_to_netaddr_in(&sc, &sain);
2111			ctl.len = 40;
2112			sc.len = sasize;
2113			break;
2114
2115		case AF_LOCAL:
2116			sc.pad[1] = 0x00010000;
2117			sc.pad[2] = 0xf6bcdaa0;	/* I don't know what that is */
2118			sc.pad[3] = 0x00010000;
2119			ctl.len = 134;
2120			sc.len = sasize + 4;
2121			break;
2122
2123		default:
2124			return ENOSYS;
2125		}
2126
2127		dat.len = -1;
2128		fl = 0;
2129		st->s_cmd = SVR4_TI__ACCEPT_OK;
2130		break;
2131
2132	case SVR4_TI_SENDTO_REQUEST:
2133		DPRINTF(("getmsg: TI_SENDTO_REQUEST\n"));
2134		if (ctl.maxlen > 36 && ctl.len < 36)
2135		    ctl.len = 36;
2136
2137		if (ctl.len > sizeof(sc))
2138			ctl.len = sizeof(sc);
2139
2140		if ((error = copyin(ctl.buf, &sc, ctl.len)) != 0)
2141			return error;
2142
2143		switch (st->s_family) {
2144		case AF_INET:
2145			sockaddr_to_netaddr_in(&sc, &sain);
2146			break;
2147
2148		case AF_LOCAL:
2149			sockaddr_to_netaddr_un(&sc, &saun);
2150			break;
2151
2152		default:
2153			return ENOSYS;
2154		}
2155
2156		msg.msg_name = (caddr_t) sup;
2157		msg.msg_namelen = sasize;
2158		msg.msg_iov = &aiov;
2159		msg.msg_iovlen = 1;
2160		msg.msg_control = 0;
2161		aiov.iov_base = dat.buf;
2162		aiov.iov_len = dat.maxlen;
2163		msg.msg_flags = 0;
2164
2165		error = svr4_recvit(td, uap->fd, &msg, (caddr_t) flen);
2166
2167		if (error) {
2168			DPRINTF(("getmsg: recvit failed %d\n", error));
2169			return error;
2170		}
2171
2172		if ((error = copyin(msg.msg_name, skp, sasize)) != 0)
2173			return error;
2174
2175		sc.cmd = SVR4_TI_RECVFROM_IND;
2176
2177		switch (st->s_family) {
2178		case AF_INET:
2179			sc.len = sasize;
2180			sockaddr_to_netaddr_in(&sc, &sain);
2181			break;
2182
2183		case AF_LOCAL:
2184			sc.len = sasize + 4;
2185			sockaddr_to_netaddr_un(&sc, &saun);
2186			break;
2187
2188		default:
2189			return ENOSYS;
2190		}
2191
2192		dat.len = *retval;
2193		fl = 0;
2194		st->s_cmd = sc.cmd;
2195		break;
2196
2197	default:
2198		st->s_cmd = sc.cmd;
2199		if (st->s_cmd == SVR4_TI_CONNECT_REQUEST) {
2200		        struct read_args ra;
2201
2202			/* More weirdness:  Again, I can't find documentation
2203			 * to back this up, but when a process does a generic
2204			 * "getmsg()" call it seems that the command field is
2205			 * zero and the length of the data area is zero.  I
2206			 * think processes expect getmsg() to fill in dat.len
2207			 * after reading at most dat.maxlen octets from the
2208			 * stream.  Since we're using sockets I can let
2209			 * read() look after it and frob return values
2210			 * appropriately (or inappropriately :-)
2211			 *   -- newton@atdot.dotat.org        XXX
2212			 */
2213			ra.fd = uap->fd;
2214			ra.buf = dat.buf;
2215			ra.nbyte = dat.maxlen;
2216			if ((error = read(td, &ra)) != 0) {
2217			        return error;
2218			}
2219			dat.len = *retval;
2220			*retval = 0;
2221			st->s_cmd = SVR4_TI_SENDTO_REQUEST;
2222			break;
2223		}
2224		DPRINTF(("getmsg: Unknown state %x\n", st->s_cmd));
2225		return EINVAL;
2226	}
2227
2228	if (uap->ctl) {
2229		if (ctl.len > sizeof(sc))
2230			ctl.len = sizeof(sc);
2231		if (ctl.len != -1)
2232			if ((error = copyout(&sc, ctl.buf, ctl.len)) != 0)
2233				return error;
2234
2235		if ((error = copyout(&ctl, uap->ctl, sizeof(ctl))) != 0)
2236			return error;
2237	}
2238
2239	if (uap->dat) {
2240		if ((error = copyout(&dat, uap->dat, sizeof(dat))) != 0)
2241			return error;
2242	}
2243
2244	if (uap->flags) { /* XXX: Need translation */
2245		if ((error = copyout(&fl, uap->flags, sizeof(fl))) != 0)
2246			return error;
2247	}
2248
2249	*retval = 0;
2250
2251#ifdef DEBUG_SVR4
2252	show_msg("<getmsg", uap->fd, uap->ctl,
2253		 uap->dat, fl);
2254#endif /* DEBUG_SVR4 */
2255	return error;
2256}
2257
2258int svr4_sys_send(td, uap)
2259	struct thread *td;
2260	struct svr4_sys_send_args *uap;
2261{
2262	struct osend_args osa;
2263	osa.s = uap->s;
2264	osa.buf = uap->buf;
2265	osa.len = uap->len;
2266	osa.flags = uap->flags;
2267	return osend(td, &osa);
2268}
2269
2270int svr4_sys_recv(td, uap)
2271	struct thread *td;
2272	struct svr4_sys_recv_args *uap;
2273{
2274	struct orecv_args ora;
2275	ora.s = uap->s;
2276	ora.buf = uap->buf;
2277	ora.len = uap->len;
2278	ora.flags = uap->flags;
2279	return orecv(td, &ora);
2280}
2281
2282/*
2283 * XXX This isn't necessary, but it's handy for inserting debug code into
2284 * sendto().  Let's leave it here for now...
2285 */
2286int
2287svr4_sys_sendto(td, uap)
2288        struct thread *td;
2289        struct svr4_sys_sendto_args *uap;
2290{
2291        struct sendto_args sa;
2292
2293	sa.s = uap->s;
2294	sa.buf = uap->buf;
2295	sa.len = uap->len;
2296	sa.flags = uap->flags;
2297	sa.to = (caddr_t)uap->to;
2298	sa.tolen = uap->tolen;
2299
2300	DPRINTF(("calling sendto()\n"));
2301	return sendto(td, &sa);
2302}
2303
2304