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