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