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