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