kern_sendfile.c revision 13203
1/*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1993
3 *	The Regents of the University of California.  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 the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
34 * $Id: uipc_syscalls.c,v 1.11 1996/01/01 10:28:21 peter Exp $
35 */
36
37#include "opt_ktrace.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/sysproto.h>
42#include <sys/filedesc.h>
43#include <sys/proc.h>
44#include <sys/file.h>
45#include <sys/buf.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
48#include <sys/protosw.h>
49#include <sys/stat.h>
50#include <sys/socket.h>
51#include <sys/socketvar.h>
52#include <sys/signalvar.h>
53#include <sys/un.h>
54#ifdef KTRACE
55#include <sys/ktrace.h>
56#endif
57
58extern int sendit __P((struct proc *p, int s, struct msghdr *mp, int flags,
59		       int *retsize));
60extern int recvit __P((struct proc *p, int s, struct msghdr *mp,
61		       caddr_t namelenp, int *retsize));
62
63static int accept1 __P((struct proc *p, struct accept_args *uap, int *retval,
64			int compat));
65static int getsockname1 __P((struct proc *p, struct getsockname_args *uap,
66			     int *retval, int compat));
67static int getpeername1 __P((struct proc *p, struct getpeername_args *uap,
68			     int *retval, int compat));
69
70/*
71 * System call interface to the socket abstraction.
72 */
73#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
74#define COMPAT_OLDSOCK
75#endif
76
77extern	struct fileops socketops;
78
79int
80socket(p, uap, retval)
81	struct proc *p;
82	register struct socket_args /* {
83		int	domain;
84		int	type;
85		int	protocol;
86	} */ *uap;
87	int *retval;
88{
89	struct filedesc *fdp = p->p_fd;
90	struct socket *so;
91	struct file *fp;
92	int fd, error;
93
94	error = falloc(p, &fp, &fd);
95	if (error)
96		return (error);
97	fp->f_flag = FREAD|FWRITE;
98	fp->f_type = DTYPE_SOCKET;
99	fp->f_ops = &socketops;
100	error = socreate(uap->domain, &so, uap->type, uap->protocol);
101	if (error) {
102		fdp->fd_ofiles[fd] = 0;
103		ffree(fp);
104	} else {
105		fp->f_data = (caddr_t)so;
106		*retval = fd;
107	}
108	return (error);
109}
110
111/* ARGSUSED */
112int
113bind(p, uap, retval)
114	struct proc *p;
115	register struct bind_args /* {
116		int	s;
117		caddr_t	name;
118		int	namelen;
119	} */ *uap;
120	int *retval;
121{
122	struct file *fp;
123	struct mbuf *nam;
124	int error;
125
126	error = getsock(p->p_fd, uap->s, &fp);
127	if (error)
128		return (error);
129	error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
130	if (error)
131		return (error);
132	error = sobind((struct socket *)fp->f_data, nam);
133	m_freem(nam);
134	return (error);
135}
136
137/* ARGSUSED */
138int
139listen(p, uap, retval)
140	struct proc *p;
141	register struct listen_args /* {
142		int	s;
143		int	backlog;
144	} */ *uap;
145	int *retval;
146{
147	struct file *fp;
148	int error;
149
150	error = getsock(p->p_fd, uap->s, &fp);
151	if (error)
152		return (error);
153	return (solisten((struct socket *)fp->f_data, uap->backlog));
154}
155
156static int
157accept1(p, uap, retval, compat)
158	struct proc *p;
159	register struct accept_args /* {
160		int	s;
161		caddr_t	name;
162		int	*anamelen;
163	} */ *uap;
164	int *retval;
165	int compat;
166{
167	struct file *fp;
168	struct mbuf *nam;
169	int namelen, error, s;
170	register struct socket *so;
171
172	if (uap->name) {
173		error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
174			sizeof (namelen));
175		if(error)
176			return (error);
177	}
178	error = getsock(p->p_fd, uap->s, &fp);
179	if (error)
180		return (error);
181	s = splnet();
182	so = (struct socket *)fp->f_data;
183	if ((so->so_options & SO_ACCEPTCONN) == 0) {
184		splx(s);
185		return (EINVAL);
186	}
187	if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
188		splx(s);
189		return (EWOULDBLOCK);
190	}
191	while (so->so_qlen == 0 && so->so_error == 0) {
192		if (so->so_state & SS_CANTRCVMORE) {
193			so->so_error = ECONNABORTED;
194			break;
195		}
196		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
197		    "accept", 0);
198		if (error) {
199			splx(s);
200			return (error);
201		}
202	}
203	if (so->so_error) {
204		error = so->so_error;
205		so->so_error = 0;
206		splx(s);
207		return (error);
208	}
209	error = falloc(p, &fp, retval);
210	if (error) {
211		splx(s);
212		return (error);
213	}
214	{ struct socket *aso = so->so_q;
215	  if (soqremque(aso, 1) == 0)
216		panic("accept");
217	  so = aso;
218	}
219	fp->f_type = DTYPE_SOCKET;
220	fp->f_flag = FREAD|FWRITE;
221	fp->f_ops = &socketops;
222	fp->f_data = (caddr_t)so;
223	nam = m_get(M_WAIT, MT_SONAME);
224	(void) soaccept(so, nam);
225	if (uap->name) {
226#ifdef COMPAT_OLDSOCK
227		if (compat)
228			mtod(nam, struct osockaddr *)->sa_family =
229			    mtod(nam, struct sockaddr *)->sa_family;
230#endif
231		if (namelen > nam->m_len)
232			namelen = nam->m_len;
233		/* SHOULD COPY OUT A CHAIN HERE */
234		error = copyout(mtod(nam, caddr_t), (caddr_t)uap->name,
235		    (u_int)namelen);
236		if (!error)
237			error = copyout((caddr_t)&namelen,
238			    (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
239	}
240	m_freem(nam);
241	splx(s);
242	return (error);
243}
244
245int
246accept(p, uap, retval)
247	struct proc *p;
248	struct accept_args *uap;
249	int *retval;
250{
251
252	return (accept1(p, uap, retval, 0));
253}
254
255#ifdef COMPAT_OLDSOCK
256int
257oaccept(p, uap, retval)
258	struct proc *p;
259	struct accept_args *uap;
260	int *retval;
261{
262
263	return (accept1(p, uap, retval, 1));
264}
265#endif /* COMPAT_OLDSOCK */
266
267/* ARGSUSED */
268int
269connect(p, uap, retval)
270	struct proc *p;
271	register struct connect_args /* {
272		int	s;
273		caddr_t	name;
274		int	namelen;
275	} */ *uap;
276	int *retval;
277{
278	struct file *fp;
279	register struct socket *so;
280	struct mbuf *nam;
281	int error, s;
282
283	error = getsock(p->p_fd, uap->s, &fp);
284	if (error)
285		return (error);
286	so = (struct socket *)fp->f_data;
287	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
288		return (EALREADY);
289	error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
290	if (error)
291		return (error);
292	error = soconnect(so, nam);
293	if (error)
294		goto bad;
295	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
296		m_freem(nam);
297		return (EINPROGRESS);
298	}
299	s = splnet();
300	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
301		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
302		    "connec", 0);
303		if (error)
304			break;
305	}
306	if (error == 0) {
307		error = so->so_error;
308		so->so_error = 0;
309	}
310	splx(s);
311bad:
312	so->so_state &= ~SS_ISCONNECTING;
313	m_freem(nam);
314	if (error == ERESTART)
315		error = EINTR;
316	return (error);
317}
318
319int
320socketpair(p, uap, retval)
321	struct proc *p;
322	register struct socketpair_args /* {
323		int	domain;
324		int	type;
325		int	protocol;
326		int	*rsv;
327	} */ *uap;
328	int retval[];
329{
330	register struct filedesc *fdp = p->p_fd;
331	struct file *fp1, *fp2;
332	struct socket *so1, *so2;
333	int fd, error, sv[2];
334
335	error = socreate(uap->domain, &so1, uap->type, uap->protocol);
336	if (error)
337		return (error);
338	error = socreate(uap->domain, &so2, uap->type, uap->protocol);
339	if (error)
340		goto free1;
341	error = falloc(p, &fp1, &fd);
342	if (error)
343		goto free2;
344	sv[0] = fd;
345	fp1->f_flag = FREAD|FWRITE;
346	fp1->f_type = DTYPE_SOCKET;
347	fp1->f_ops = &socketops;
348	fp1->f_data = (caddr_t)so1;
349	error = falloc(p, &fp2, &fd);
350	if (error)
351		goto free3;
352	fp2->f_flag = FREAD|FWRITE;
353	fp2->f_type = DTYPE_SOCKET;
354	fp2->f_ops = &socketops;
355	fp2->f_data = (caddr_t)so2;
356	sv[1] = fd;
357	error = soconnect2(so1, so2);
358	if (error)
359		goto free4;
360	if (uap->type == SOCK_DGRAM) {
361		/*
362		 * Datagram socket connection is asymmetric.
363		 */
364		 error = soconnect2(so2, so1);
365		 if (error)
366			goto free4;
367	}
368	error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
369	retval[0] = sv[0];		/* XXX ??? */
370	retval[1] = sv[1];		/* XXX ??? */
371	return (error);
372free4:
373	ffree(fp2);
374	fdp->fd_ofiles[sv[1]] = 0;
375free3:
376	ffree(fp1);
377	fdp->fd_ofiles[sv[0]] = 0;
378free2:
379	(void)soclose(so2);
380free1:
381	(void)soclose(so1);
382	return (error);
383}
384
385int
386sendit(p, s, mp, flags, retsize)
387	register struct proc *p;
388	int s;
389	register struct msghdr *mp;
390	int flags, *retsize;
391{
392	struct file *fp;
393	struct uio auio;
394	register struct iovec *iov;
395	register int i;
396	struct mbuf *to, *control;
397	int len, error;
398#ifdef KTRACE
399	struct iovec *ktriov = NULL;
400#endif
401
402	error = getsock(p->p_fd, s, &fp);
403	if (error)
404		return (error);
405	auio.uio_iov = mp->msg_iov;
406	auio.uio_iovcnt = mp->msg_iovlen;
407	auio.uio_segflg = UIO_USERSPACE;
408	auio.uio_rw = UIO_WRITE;
409	auio.uio_procp = p;
410	auio.uio_offset = 0;			/* XXX */
411	auio.uio_resid = 0;
412	iov = mp->msg_iov;
413	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
414		if ((auio.uio_resid += iov->iov_len) < 0)
415			return (EINVAL);
416	}
417	if (mp->msg_name) {
418		error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
419		if (error)
420			return (error);
421	} else
422		to = 0;
423	if (mp->msg_control) {
424		if (mp->msg_controllen < sizeof(struct cmsghdr)
425#ifdef COMPAT_OLDSOCK
426		    && mp->msg_flags != MSG_COMPAT
427#endif
428		) {
429			error = EINVAL;
430			goto bad;
431		}
432		error = sockargs(&control, mp->msg_control,
433		    mp->msg_controllen, MT_CONTROL);
434		if (error)
435			goto bad;
436#ifdef COMPAT_OLDSOCK
437		if (mp->msg_flags == MSG_COMPAT) {
438			register struct cmsghdr *cm;
439
440			M_PREPEND(control, sizeof(*cm), M_WAIT);
441			if (control == 0) {
442				error = ENOBUFS;
443				goto bad;
444			} else {
445				cm = mtod(control, struct cmsghdr *);
446				cm->cmsg_len = control->m_len;
447				cm->cmsg_level = SOL_SOCKET;
448				cm->cmsg_type = SCM_RIGHTS;
449			}
450		}
451#endif
452	} else
453		control = 0;
454#ifdef KTRACE
455	if (KTRPOINT(p, KTR_GENIO)) {
456		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
457
458		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
459		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
460	}
461#endif
462	len = auio.uio_resid;
463	error = sosend((struct socket *)fp->f_data, to, &auio,
464	    (struct mbuf *)0, control, flags);
465	if (error) {
466		if (auio.uio_resid != len && (error == ERESTART ||
467		    error == EINTR || error == EWOULDBLOCK))
468			error = 0;
469		if (error == EPIPE)
470			psignal(p, SIGPIPE);
471	}
472	if (error == 0)
473		*retsize = len - auio.uio_resid;
474#ifdef KTRACE
475	if (ktriov != NULL) {
476		if (error == 0)
477			ktrgenio(p->p_tracep, s, UIO_WRITE,
478				ktriov, *retsize, error);
479		FREE(ktriov, M_TEMP);
480	}
481#endif
482bad:
483	if (to)
484		m_freem(to);
485	return (error);
486}
487
488int
489sendto(p, uap, retval)
490	struct proc *p;
491	register struct sendto_args /* {
492		int	s;
493		caddr_t	buf;
494		size_t	len;
495		int	flags;
496		caddr_t	to;
497		int	tolen;
498	} */ *uap;
499	int *retval;
500{
501	struct msghdr msg;
502	struct iovec aiov;
503
504	msg.msg_name = uap->to;
505	msg.msg_namelen = uap->tolen;
506	msg.msg_iov = &aiov;
507	msg.msg_iovlen = 1;
508	msg.msg_control = 0;
509#ifdef COMPAT_OLDSOCK
510	msg.msg_flags = 0;
511#endif
512	aiov.iov_base = uap->buf;
513	aiov.iov_len = uap->len;
514	return (sendit(p, uap->s, &msg, uap->flags, retval));
515}
516
517#ifdef COMPAT_OLDSOCK
518int
519osend(p, uap, retval)
520	struct proc *p;
521	register struct osend_args /* {
522		int	s;
523		caddr_t	buf;
524		int	len;
525		int	flags;
526	} */ *uap;
527	int *retval;
528{
529	struct msghdr msg;
530	struct iovec aiov;
531
532	msg.msg_name = 0;
533	msg.msg_namelen = 0;
534	msg.msg_iov = &aiov;
535	msg.msg_iovlen = 1;
536	aiov.iov_base = uap->buf;
537	aiov.iov_len = uap->len;
538	msg.msg_control = 0;
539	msg.msg_flags = 0;
540	return (sendit(p, uap->s, &msg, uap->flags, retval));
541}
542
543int
544osendmsg(p, uap, retval)
545	struct proc *p;
546	register struct osendmsg_args /* {
547		int	s;
548		caddr_t	msg;
549		int	flags;
550	} */ *uap;
551	int *retval;
552{
553	struct msghdr msg;
554	struct iovec aiov[UIO_SMALLIOV], *iov;
555	int error;
556
557	error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr));
558	if (error)
559		return (error);
560	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
561		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
562			return (EMSGSIZE);
563		MALLOC(iov, struct iovec *,
564		      sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
565		      M_WAITOK);
566	} else
567		iov = aiov;
568	error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
569	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
570	if (error)
571		goto done;
572	msg.msg_flags = MSG_COMPAT;
573	msg.msg_iov = iov;
574	error = sendit(p, uap->s, &msg, uap->flags, retval);
575done:
576	if (iov != aiov)
577		FREE(iov, M_IOV);
578	return (error);
579}
580#endif
581
582int
583sendmsg(p, uap, retval)
584	struct proc *p;
585	register struct sendmsg_args /* {
586		int	s;
587		caddr_t	msg;
588		int	flags;
589	} */ *uap;
590	int *retval;
591{
592	struct msghdr msg;
593	struct iovec aiov[UIO_SMALLIOV], *iov;
594	int error;
595
596	error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
597	if (error)
598		return (error);
599	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
600		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
601			return (EMSGSIZE);
602		MALLOC(iov, struct iovec *,
603		       sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
604		       M_WAITOK);
605	} else
606		iov = aiov;
607	if (msg.msg_iovlen &&
608	    (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
609	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
610		goto done;
611	msg.msg_iov = iov;
612#ifdef COMPAT_OLDSOCK
613	msg.msg_flags = 0;
614#endif
615	error = sendit(p, uap->s, &msg, uap->flags, retval);
616done:
617	if (iov != aiov)
618		FREE(iov, M_IOV);
619	return (error);
620}
621
622int
623recvit(p, s, mp, namelenp, retsize)
624	register struct proc *p;
625	int s;
626	register struct msghdr *mp;
627	caddr_t namelenp;
628	int *retsize;
629{
630	struct file *fp;
631	struct uio auio;
632	register struct iovec *iov;
633	register int i;
634	int len, error;
635	struct mbuf *from = 0, *control = 0;
636#ifdef KTRACE
637	struct iovec *ktriov = NULL;
638#endif
639
640	error = getsock(p->p_fd, s, &fp);
641	if (error)
642		return (error);
643	auio.uio_iov = mp->msg_iov;
644	auio.uio_iovcnt = mp->msg_iovlen;
645	auio.uio_segflg = UIO_USERSPACE;
646	auio.uio_rw = UIO_READ;
647	auio.uio_procp = p;
648	auio.uio_offset = 0;			/* XXX */
649	auio.uio_resid = 0;
650	iov = mp->msg_iov;
651	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
652		if ((auio.uio_resid += iov->iov_len) < 0)
653			return (EINVAL);
654	}
655#ifdef KTRACE
656	if (KTRPOINT(p, KTR_GENIO)) {
657		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
658
659		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
660		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
661	}
662#endif
663	len = auio.uio_resid;
664	error = soreceive((struct socket *)fp->f_data, &from, &auio,
665	    (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
666	    &mp->msg_flags);
667	if (error) {
668		if (auio.uio_resid != len && (error == ERESTART ||
669		    error == EINTR || error == EWOULDBLOCK))
670			error = 0;
671	}
672#ifdef KTRACE
673	if (ktriov != NULL) {
674		if (error == 0)
675			ktrgenio(p->p_tracep, s, UIO_READ,
676				ktriov, len - auio.uio_resid, error);
677		FREE(ktriov, M_TEMP);
678	}
679#endif
680	if (error)
681		goto out;
682	*retsize = len - auio.uio_resid;
683	if (mp->msg_name) {
684		len = mp->msg_namelen;
685		if (len <= 0 || from == 0)
686			len = 0;
687		else {
688#ifdef COMPAT_OLDSOCK
689			if (mp->msg_flags & MSG_COMPAT)
690				mtod(from, struct osockaddr *)->sa_family =
691				    mtod(from, struct sockaddr *)->sa_family;
692#endif
693			if (len > from->m_len)
694				len = from->m_len;
695			/* else if len < from->m_len ??? */
696			error = copyout(mtod(from, caddr_t),
697			    (caddr_t)mp->msg_name, (unsigned)len);
698			if (error)
699				goto out;
700		}
701		mp->msg_namelen = len;
702		if (namelenp &&
703		    (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
704#ifdef COMPAT_OLDSOCK
705			if (mp->msg_flags & MSG_COMPAT)
706				error = 0;	/* old recvfrom didn't check */
707			else
708#endif
709			goto out;
710		}
711	}
712	if (mp->msg_control) {
713#ifdef COMPAT_OLDSOCK
714		/*
715		 * We assume that old recvmsg calls won't receive access
716		 * rights and other control info, esp. as control info
717		 * is always optional and those options didn't exist in 4.3.
718		 * If we receive rights, trim the cmsghdr; anything else
719		 * is tossed.
720		 */
721		if (control && mp->msg_flags & MSG_COMPAT) {
722			if (mtod(control, struct cmsghdr *)->cmsg_level !=
723			    SOL_SOCKET ||
724			    mtod(control, struct cmsghdr *)->cmsg_type !=
725			    SCM_RIGHTS) {
726				mp->msg_controllen = 0;
727				goto out;
728			}
729			control->m_len -= sizeof (struct cmsghdr);
730			control->m_data += sizeof (struct cmsghdr);
731		}
732#endif
733		len = mp->msg_controllen;
734		if (len <= 0 || control == 0)
735			len = 0;
736		else {
737			if (len >= control->m_len)
738				len = control->m_len;
739			else
740				mp->msg_flags |= MSG_CTRUNC;
741			error = copyout((caddr_t)mtod(control, caddr_t),
742			    (caddr_t)mp->msg_control, (unsigned)len);
743		}
744		mp->msg_controllen = len;
745	}
746out:
747	if (from)
748		m_freem(from);
749	if (control)
750		m_freem(control);
751	return (error);
752}
753
754int
755recvfrom(p, uap, retval)
756	struct proc *p;
757	register struct recvfrom_args /* {
758		int	s;
759		caddr_t	buf;
760		size_t	len;
761		int	flags;
762		caddr_t	from;
763		int	*fromlenaddr;
764	} */ *uap;
765	int *retval;
766{
767	struct msghdr msg;
768	struct iovec aiov;
769	int error;
770
771	if (uap->fromlenaddr) {
772		error = copyin((caddr_t)uap->fromlenaddr,
773		    (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen));
774		if (error)
775			return (error);
776	} else
777		msg.msg_namelen = 0;
778	msg.msg_name = uap->from;
779	msg.msg_iov = &aiov;
780	msg.msg_iovlen = 1;
781	aiov.iov_base = uap->buf;
782	aiov.iov_len = uap->len;
783	msg.msg_control = 0;
784	msg.msg_flags = uap->flags;
785	return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
786}
787
788#ifdef COMPAT_OLDSOCK
789int
790orecvfrom(p, uap, retval)
791	struct proc *p;
792	struct recvfrom_args *uap;
793	int *retval;
794{
795
796	uap->flags |= MSG_COMPAT;
797	return (recvfrom(p, uap, retval));
798}
799#endif
800
801
802#ifdef COMPAT_OLDSOCK
803int
804orecv(p, uap, retval)
805	struct proc *p;
806	register struct orecv_args /* {
807		int	s;
808		caddr_t	buf;
809		int	len;
810		int	flags;
811	} */ *uap;
812	int *retval;
813{
814	struct msghdr msg;
815	struct iovec aiov;
816
817	msg.msg_name = 0;
818	msg.msg_namelen = 0;
819	msg.msg_iov = &aiov;
820	msg.msg_iovlen = 1;
821	aiov.iov_base = uap->buf;
822	aiov.iov_len = uap->len;
823	msg.msg_control = 0;
824	msg.msg_flags = uap->flags;
825	return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
826}
827
828/*
829 * Old recvmsg.  This code takes advantage of the fact that the old msghdr
830 * overlays the new one, missing only the flags, and with the (old) access
831 * rights where the control fields are now.
832 */
833int
834orecvmsg(p, uap, retval)
835	struct proc *p;
836	register struct orecvmsg_args /* {
837		int	s;
838		struct	omsghdr *msg;
839		int	flags;
840	} */ *uap;
841	int *retval;
842{
843	struct msghdr msg;
844	struct iovec aiov[UIO_SMALLIOV], *iov;
845	int error;
846
847	error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
848	    sizeof (struct omsghdr));
849	if (error)
850		return (error);
851	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
852		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
853			return (EMSGSIZE);
854		MALLOC(iov, struct iovec *,
855		      sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
856		      M_WAITOK);
857	} else
858		iov = aiov;
859	msg.msg_flags = uap->flags | MSG_COMPAT;
860	error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
861	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
862	if (error)
863		goto done;
864	msg.msg_iov = iov;
865	error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
866
867	if (msg.msg_controllen && error == 0)
868		error = copyout((caddr_t)&msg.msg_controllen,
869		    (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
870done:
871	if (iov != aiov)
872		FREE(iov, M_IOV);
873	return (error);
874}
875#endif
876
877int
878recvmsg(p, uap, retval)
879	struct proc *p;
880	register struct recvmsg_args /* {
881		int	s;
882		struct	msghdr *msg;
883		int	flags;
884	} */ *uap;
885	int *retval;
886{
887	struct msghdr msg;
888	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
889	register int error;
890
891	error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
892	if (error)
893		return (error);
894	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
895		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
896			return (EMSGSIZE);
897		MALLOC(iov, struct iovec *,
898		       sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
899		       M_WAITOK);
900	} else
901		iov = aiov;
902#ifdef COMPAT_OLDSOCK
903	msg.msg_flags = uap->flags &~ MSG_COMPAT;
904#else
905	msg.msg_flags = uap->flags;
906#endif
907	uiov = msg.msg_iov;
908	msg.msg_iov = iov;
909	error = copyin((caddr_t)uiov, (caddr_t)iov,
910	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
911	if (error)
912		goto done;
913	error = recvit(p, uap->s, &msg, (caddr_t)0, retval);
914	if (!error) {
915		msg.msg_iov = uiov;
916		error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
917	}
918done:
919	if (iov != aiov)
920		FREE(iov, M_IOV);
921	return (error);
922}
923
924/* ARGSUSED */
925int
926shutdown(p, uap, retval)
927	struct proc *p;
928	register struct shutdown_args /* {
929		int	s;
930		int	how;
931	} */ *uap;
932	int *retval;
933{
934	struct file *fp;
935	int error;
936
937	error = getsock(p->p_fd, uap->s, &fp);
938	if (error)
939		return (error);
940	return (soshutdown((struct socket *)fp->f_data, uap->how));
941}
942
943/* ARGSUSED */
944int
945setsockopt(p, uap, retval)
946	struct proc *p;
947	register struct setsockopt_args /* {
948		int	s;
949		int	level;
950		int	name;
951		caddr_t	val;
952		int	valsize;
953	} */ *uap;
954	int *retval;
955{
956	struct file *fp;
957	struct mbuf *m = NULL;
958	int error;
959
960	error = getsock(p->p_fd, uap->s, &fp);
961	if (error)
962		return (error);
963	if (uap->valsize > MLEN)
964		return (EINVAL);
965	if (uap->val) {
966		m = m_get(M_WAIT, MT_SOOPTS);
967		if (m == NULL)
968			return (ENOBUFS);
969		error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
970		if (error) {
971			(void) m_free(m);
972			return (error);
973		}
974		m->m_len = uap->valsize;
975	}
976	return (sosetopt((struct socket *)fp->f_data, uap->level,
977	    uap->name, m));
978}
979
980/* ARGSUSED */
981int
982getsockopt(p, uap, retval)
983	struct proc *p;
984	register struct getsockopt_args /* {
985		int	s;
986		int	level;
987		int	name;
988		caddr_t	val;
989		int	*avalsize;
990	} */ *uap;
991	int *retval;
992{
993	struct file *fp;
994	struct mbuf *m = NULL;
995	int valsize, error;
996
997	error = getsock(p->p_fd, uap->s, &fp);
998	if (error)
999		return (error);
1000	if (uap->val) {
1001		error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
1002		    sizeof (valsize));
1003		if (error)
1004			return (error);
1005	} else
1006		valsize = 0;
1007	if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
1008	    uap->name, &m)) == 0 && uap->val && valsize && m != NULL) {
1009		if (valsize > m->m_len)
1010			valsize = m->m_len;
1011		error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
1012		if (error == 0)
1013			error = copyout((caddr_t)&valsize,
1014			    (caddr_t)uap->avalsize, sizeof (valsize));
1015	}
1016	if (m != NULL)
1017		(void) m_free(m);
1018	return (error);
1019}
1020
1021/* ARGSUSED */
1022int
1023pipe(p, uap, retval)
1024	struct proc *p;
1025	struct pipe_args /* {
1026		int	dummy;
1027	} */ *uap;
1028	int retval[];
1029{
1030	register struct filedesc *fdp = p->p_fd;
1031	struct file *rf, *wf;
1032	struct socket *rso, *wso;
1033	int fd, error;
1034
1035	error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0);
1036	if (error)
1037		return (error);
1038	error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0);
1039	if (error)
1040		goto free1;
1041	error = falloc(p, &rf, &fd);
1042	if (error)
1043		goto free2;
1044	retval[0] = fd;
1045	rf->f_flag = FREAD | FWRITE;
1046	rf->f_type = DTYPE_SOCKET;
1047	rf->f_ops = &socketops;
1048	rf->f_data = (caddr_t)rso;
1049	error = falloc(p, &wf, &fd);
1050	if (error)
1051		goto free3;
1052	wf->f_flag = FREAD | FWRITE;
1053	wf->f_type = DTYPE_SOCKET;
1054	wf->f_ops = &socketops;
1055	wf->f_data = (caddr_t)wso;
1056	retval[1] = fd;
1057	error = unp_connect2(wso, rso);
1058	if (error)
1059		goto free4;
1060	return (0);
1061free4:
1062	ffree(wf);
1063	fdp->fd_ofiles[retval[1]] = 0;
1064free3:
1065	ffree(rf);
1066	fdp->fd_ofiles[retval[0]] = 0;
1067free2:
1068	(void)soclose(wso);
1069free1:
1070	(void)soclose(rso);
1071	return (error);
1072}
1073
1074/*
1075 * Get socket name.
1076 */
1077/* ARGSUSED */
1078static int
1079getsockname1(p, uap, retval, compat)
1080	struct proc *p;
1081	register struct getsockname_args /* {
1082		int	fdes;
1083		caddr_t	asa;
1084		int	*alen;
1085	} */ *uap;
1086	int *retval;
1087	int compat;
1088{
1089	struct file *fp;
1090	register struct socket *so;
1091	struct mbuf *m;
1092	int len, error;
1093
1094	error = getsock(p->p_fd, uap->fdes, &fp);
1095	if (error)
1096		return (error);
1097	error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1098	if (error)
1099		return (error);
1100	so = (struct socket *)fp->f_data;
1101	m = m_getclr(M_WAIT, MT_SONAME);
1102	if (m == NULL)
1103		return (ENOBUFS);
1104	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
1105	if (error)
1106		goto bad;
1107	if (len > m->m_len)
1108		len = m->m_len;
1109#ifdef COMPAT_OLDSOCK
1110	if (compat)
1111		mtod(m, struct osockaddr *)->sa_family =
1112		    mtod(m, struct sockaddr *)->sa_family;
1113#endif
1114	error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1115	if (error == 0)
1116		error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1117		    sizeof (len));
1118bad:
1119	m_freem(m);
1120	return (error);
1121}
1122
1123int
1124getsockname(p, uap, retval)
1125	struct proc *p;
1126	struct getsockname_args *uap;
1127	int *retval;
1128{
1129
1130	return (getsockname1(p, uap, retval, 0));
1131}
1132
1133#ifdef COMPAT_OLDSOCK
1134int
1135ogetsockname(p, uap, retval)
1136	struct proc *p;
1137	struct getsockname_args *uap;
1138	int *retval;
1139{
1140
1141	return (getsockname1(p, uap, retval, 1));
1142}
1143#endif /* COMPAT_OLDSOCK */
1144
1145/*
1146 * Get name of peer for connected socket.
1147 */
1148/* ARGSUSED */
1149static int
1150getpeername1(p, uap, retval, compat)
1151	struct proc *p;
1152	register struct getpeername_args /* {
1153		int	fdes;
1154		caddr_t	asa;
1155		int	*alen;
1156	} */ *uap;
1157	int *retval;
1158	int compat;
1159{
1160	struct file *fp;
1161	register struct socket *so;
1162	struct mbuf *m;
1163	int len, error;
1164
1165	error = getsock(p->p_fd, uap->fdes, &fp);
1166	if (error)
1167		return (error);
1168	so = (struct socket *)fp->f_data;
1169	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1170		return (ENOTCONN);
1171	error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1172	if (error)
1173		return (error);
1174	m = m_getclr(M_WAIT, MT_SONAME);
1175	if (m == NULL)
1176		return (ENOBUFS);
1177	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
1178	if (error)
1179		goto bad;
1180	if (len > m->m_len)
1181		len = m->m_len;
1182#ifdef COMPAT_OLDSOCK
1183	if (compat)
1184		mtod(m, struct osockaddr *)->sa_family =
1185		    mtod(m, struct sockaddr *)->sa_family;
1186#endif
1187	error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1188	if (error)
1189		goto bad;
1190	error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1191bad:
1192	m_freem(m);
1193	return (error);
1194}
1195
1196int
1197getpeername(p, uap, retval)
1198	struct proc *p;
1199	struct getpeername_args *uap;
1200	int *retval;
1201{
1202
1203	return (getpeername1(p, uap, retval, 0));
1204}
1205
1206#ifdef COMPAT_OLDSOCK
1207int
1208ogetpeername(p, uap, retval)
1209	struct proc *p;
1210	struct ogetpeername_args *uap;
1211	int *retval;
1212{
1213
1214	/* XXX uap should have type `getpeername_args *' to begin with. */
1215	return (getpeername1(p, (struct getpeername_args *)uap, retval, 1));
1216}
1217#endif /* COMPAT_OLDSOCK */
1218
1219int
1220sockargs(mp, buf, buflen, type)
1221	struct mbuf **mp;
1222	caddr_t buf;
1223	int buflen, type;
1224{
1225	register struct sockaddr *sa;
1226	register struct mbuf *m;
1227	int error;
1228
1229	if ((u_int)buflen > MLEN) {
1230#ifdef COMPAT_OLDSOCK
1231		if (type == MT_SONAME && (u_int)buflen <= 112)
1232			buflen = MLEN;		/* unix domain compat. hack */
1233		else
1234#endif
1235		return (EINVAL);
1236	}
1237	m = m_get(M_WAIT, type);
1238	if (m == NULL)
1239		return (ENOBUFS);
1240	m->m_len = buflen;
1241	error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1242	if (error)
1243		(void) m_free(m);
1244	else {
1245		*mp = m;
1246		if (type == MT_SONAME) {
1247			sa = mtod(m, struct sockaddr *);
1248
1249#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1250			if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1251				sa->sa_family = sa->sa_len;
1252#endif
1253			sa->sa_len = buflen;
1254		}
1255	}
1256	return (error);
1257}
1258
1259int
1260getsock(fdp, fdes, fpp)
1261	struct filedesc *fdp;
1262	int fdes;
1263	struct file **fpp;
1264{
1265	register struct file *fp;
1266
1267	if ((unsigned)fdes >= fdp->fd_nfiles ||
1268	    (fp = fdp->fd_ofiles[fdes]) == NULL)
1269		return (EBADF);
1270	if (fp->f_type != DTYPE_SOCKET)
1271		return (ENOTSOCK);
1272	*fpp = fp;
1273	return (0);
1274}
1275