xref: /openbsd/sys/kern/uipc_syscalls.c (revision db3296cf)
1 /*	$OpenBSD: uipc_syscalls.c,v 1.55 2003/07/21 22:44:50 tedu Exp $	*/
2 /*	$NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/filedesc.h>
38 #include <sys/proc.h>
39 #include <sys/file.h>
40 #include <sys/buf.h>
41 #include <sys/malloc.h>
42 #include <sys/event.h>
43 #include <sys/mbuf.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/signalvar.h>
48 #include <sys/unpcb.h>
49 #include <sys/un.h>
50 #ifdef KTRACE
51 #include <sys/ktrace.h>
52 #endif
53 
54 #include <sys/mount.h>
55 #include <sys/syscallargs.h>
56 
57 /*
58  * System call interface to the socket abstraction.
59  */
60 extern	struct fileops socketops;
61 
62 int
63 sys_socket(p, v, retval)
64 	struct proc *p;
65 	void *v;
66 	register_t *retval;
67 {
68 	register struct sys_socket_args /* {
69 		syscallarg(int) domain;
70 		syscallarg(int) type;
71 		syscallarg(int) protocol;
72 	} */ *uap = v;
73 	struct filedesc *fdp = p->p_fd;
74 	struct socket *so;
75 	struct file *fp;
76 	int fd, error;
77 
78 	if ((error = falloc(p, &fp, &fd)) != 0)
79 		return (error);
80 	fp->f_flag = FREAD|FWRITE;
81 	fp->f_type = DTYPE_SOCKET;
82 	fp->f_ops = &socketops;
83 	error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
84 			 SCARG(uap, protocol));
85 	if (error) {
86 		fdremove(fdp, fd);
87 		closef(fp, p);
88 	} else {
89 		fp->f_data = so;
90 		FILE_SET_MATURE(fp);
91 		*retval = fd;
92 	}
93 	return (error);
94 }
95 
96 /* ARGSUSED */
97 int
98 sys_bind(p, v, retval)
99 	struct proc *p;
100 	void *v;
101 	register_t *retval;
102 {
103 	register struct sys_bind_args /* {
104 		syscallarg(int) s;
105 		syscallarg(struct sockaddr *) name;
106 		syscallarg(socklen_t) namelen;
107 	} */ *uap = v;
108 	struct file *fp;
109 	struct mbuf *nam;
110 	int error;
111 
112 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
113 		return (error);
114 	error = sockargs(&nam, (caddr_t)SCARG(uap, name), SCARG(uap, namelen),
115 			 MT_SONAME);
116 	if (error == 0) {
117 		error = sobind((struct socket *)fp->f_data, nam);
118 		m_freem(nam);
119 	}
120 	FRELE(fp);
121 	return (error);
122 }
123 
124 /* ARGSUSED */
125 int
126 sys_listen(p, v, retval)
127 	struct proc *p;
128 	void *v;
129 	register_t *retval;
130 {
131 	register struct sys_listen_args /* {
132 		syscallarg(int) s;
133 		syscallarg(int) backlog;
134 	} */ *uap = v;
135 	struct file *fp;
136 	int error;
137 
138 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
139 		return (error);
140 	error = solisten((struct socket *)fp->f_data, SCARG(uap, backlog));
141 	FRELE(fp);
142 	return (error);
143 }
144 
145 int
146 sys_accept(p, v, retval)
147 	struct proc *p;
148 	void *v;
149 	register_t *retval;
150 {
151 	struct sys_accept_args /* {
152 		syscallarg(int) s;
153 		syscallarg(struct sockaddr *) name;
154 		syscallarg(socklen_t *) anamelen;
155 	} */ *uap = v;
156 	struct file *fp, *headfp;
157 	struct mbuf *nam;
158 	socklen_t namelen;
159 	int error, s, tmpfd;
160 	struct socket *head, *so;
161 	int nflag;
162 
163 	if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen),
164 	    &namelen, sizeof (namelen))))
165 		return (error);
166 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
167 		return (error);
168 	headfp = fp;
169 	s = splsoftnet();
170 	head = (struct socket *)fp->f_data;
171 	if ((head->so_options & SO_ACCEPTCONN) == 0) {
172 		error = EINVAL;
173 		goto bad;
174 	}
175 	if ((head->so_state & SS_NBIO) && head->so_qlen == 0) {
176 		error = EWOULDBLOCK;
177 		goto bad;
178 	}
179 	while (head->so_qlen == 0 && head->so_error == 0) {
180 		if (head->so_state & SS_CANTRCVMORE) {
181 			head->so_error = ECONNABORTED;
182 			break;
183 		}
184 		error = tsleep(&head->so_timeo, PSOCK | PCATCH, netcon, 0);
185 		if (error) {
186 			goto bad;
187 		}
188 	}
189 	if (head->so_error) {
190 		error = head->so_error;
191 		head->so_error = 0;
192 		goto bad;
193 	}
194 
195 	/*
196 	 * At this point we know that there is at least one connection
197 	 * ready to be accepted. Remove it from the queue prior to
198 	 * allocating the file descriptor for it since falloc() may
199 	 * block allowing another process to accept the connection
200 	 * instead.
201 	 */
202 	so = TAILQ_FIRST(&head->so_q);
203 	if (soqremque(so, 1) == 0)
204 		panic("accept");
205 
206 	/* Take note if socket was non-blocking. */
207 	nflag = (fp->f_flag & FNONBLOCK);
208 
209 	if ((error = falloc(p, &fp, &tmpfd)) != 0) {
210 		/*
211 		 * Probably ran out of file descriptors. Put the
212 		 * unaccepted connection back onto the queue and
213 		 * do another wakeup so some other process might
214 		 * have a chance at it.
215 		 */
216 		so->so_head = head;
217 		head->so_qlen++;
218 		so->so_onq = &head->so_q;
219 		TAILQ_INSERT_HEAD(so->so_onq, so, so_qe);
220 		wakeup_one(&head->so_timeo);
221 		goto bad;
222 	}
223 	*retval = tmpfd;
224 
225 	/* connection has been removed from the listen queue */
226 	KNOTE(&head->so_rcv.sb_sel.si_note, 0);
227 
228 	fp->f_type = DTYPE_SOCKET;
229 	fp->f_flag = FREAD | FWRITE | nflag;
230 	fp->f_ops = &socketops;
231 	fp->f_data = so;
232 	nam = m_get(M_WAIT, MT_SONAME);
233 	error = soaccept(so, nam);
234 	if (!error && SCARG(uap, name)) {
235 		if (namelen > nam->m_len)
236 			namelen = nam->m_len;
237 		/* SHOULD COPY OUT A CHAIN HERE */
238 		if ((error = copyout(mtod(nam, caddr_t),
239 		    SCARG(uap, name), namelen)) == 0)
240 			error = copyout(&namelen, SCARG(uap, anamelen),
241 			    sizeof (*SCARG(uap, anamelen)));
242 	}
243 	/* if an error occurred, free the file descriptor */
244 	if (error) {
245 		fdremove(p->p_fd, tmpfd);
246 		closef(fp, p);
247 	} else {
248 		FILE_SET_MATURE(fp);
249 	}
250 	m_freem(nam);
251 bad:
252 	splx(s);
253 	FRELE(headfp);
254 	return (error);
255 }
256 
257 /* ARGSUSED */
258 int
259 sys_connect(p, v, retval)
260 	struct proc *p;
261 	void *v;
262 	register_t *retval;
263 {
264 	struct sys_connect_args /* {
265 		syscallarg(int) s;
266 		syscallarg(struct sockaddr *) name;
267 		syscallarg(socklen_t) namelen;
268 	} */ *uap = v;
269 	struct file *fp;
270 	struct socket *so;
271 	struct mbuf *nam = NULL;
272 	int error, s;
273 
274 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
275 		return (error);
276 	so = (struct socket *)fp->f_data;
277 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
278 		FRELE(fp);
279 		return (EALREADY);
280 	}
281 	error = sockargs(&nam, (caddr_t)SCARG(uap, name), SCARG(uap, namelen),
282 			 MT_SONAME);
283 	if (error)
284 		goto bad;
285 	error = soconnect(so, nam);
286 	if (error)
287 		goto bad;
288 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
289 		FRELE(fp);
290 		m_freem(nam);
291 		return (EINPROGRESS);
292 	}
293 	s = splsoftnet();
294 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
295 		error = tsleep(&so->so_timeo, PSOCK | PCATCH,
296 		    netcon, 0);
297 		if (error)
298 			break;
299 	}
300 	if (error == 0) {
301 		error = so->so_error;
302 		so->so_error = 0;
303 	}
304 	splx(s);
305 bad:
306 	so->so_state &= ~SS_ISCONNECTING;
307 	FRELE(fp);
308 	if (nam)
309 		m_freem(nam);
310 	if (error == ERESTART)
311 		error = EINTR;
312 	return (error);
313 }
314 
315 int
316 sys_socketpair(p, v, retval)
317 	struct proc *p;
318 	void *v;
319 	register_t *retval;
320 {
321 	register struct sys_socketpair_args /* {
322 		syscallarg(int) domain;
323 		syscallarg(int) type;
324 		syscallarg(int) protocol;
325 		syscallarg(int *) rsv;
326 	} */ *uap = v;
327 	register struct filedesc *fdp = p->p_fd;
328 	struct file *fp1, *fp2;
329 	struct socket *so1, *so2;
330 	int fd, error, sv[2];
331 
332 	error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
333 			 SCARG(uap, protocol));
334 	if (error)
335 		return (error);
336 	error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
337 			 SCARG(uap, protocol));
338 	if (error)
339 		goto free1;
340 	if ((error = falloc(p, &fp1, &fd)) != 0)
341 		goto free2;
342 	sv[0] = fd;
343 	fp1->f_flag = FREAD|FWRITE;
344 	fp1->f_type = DTYPE_SOCKET;
345 	fp1->f_ops = &socketops;
346 	fp1->f_data = so1;
347 	if ((error = falloc(p, &fp2, &fd)) != 0)
348 		goto free3;
349 	fp2->f_flag = FREAD|FWRITE;
350 	fp2->f_type = DTYPE_SOCKET;
351 	fp2->f_ops = &socketops;
352 	fp2->f_data = so2;
353 	sv[1] = fd;
354 	if ((error = soconnect2(so1, so2)) != 0)
355 		goto free4;
356 	if (SCARG(uap, type) == SOCK_DGRAM) {
357 		/*
358 		 * Datagram socket connection is asymmetric.
359 		 */
360 		 if ((error = soconnect2(so2, so1)) != 0)
361 			goto free4;
362 	}
363 	error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
364 	if (error == 0) {
365 		FILE_SET_MATURE(fp1);
366 		FILE_SET_MATURE(fp2);
367 		return (error);
368 	}
369 free4:
370 	fdremove(fdp, sv[1]);
371 	closef(fp2, p);
372 	so2 = NULL;
373 free3:
374 	fdremove(fdp, sv[0]);
375 	closef(fp1, p);
376 	so1 = NULL;
377 free2:
378 	if (so2 != NULL)
379 		(void)soclose(so2);
380 free1:
381 	if (so1 != NULL)
382 		(void)soclose(so1);
383 	return (error);
384 }
385 
386 int
387 sys_sendto(p, v, retval)
388 	struct proc *p;
389 	void *v;
390 	register_t *retval;
391 {
392 	register struct sys_sendto_args /* {
393 		syscallarg(int) s;
394 		syscallarg(caddr_t) buf;
395 		syscallarg(size_t) len;
396 		syscallarg(int) flags;
397 		syscallarg(struct sockaddr *) to;
398 		syscallarg(socklen_t) tolen;
399 	} */ *uap = v;
400 	struct msghdr msg;
401 	struct iovec aiov;
402 
403 	msg.msg_name = (caddr_t)SCARG(uap, to);
404 	msg.msg_namelen = SCARG(uap, tolen);
405 	msg.msg_iov = &aiov;
406 	msg.msg_iovlen = 1;
407 	msg.msg_control = 0;
408 #ifdef COMPAT_OLDSOCK
409 	msg.msg_flags = 0;
410 #endif
411 	aiov.iov_base = (char *)SCARG(uap, buf);
412 	aiov.iov_len = SCARG(uap, len);
413 	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
414 }
415 
416 int
417 sys_sendmsg(p, v, retval)
418 	struct proc *p;
419 	void *v;
420 	register_t *retval;
421 {
422 	register struct sys_sendmsg_args /* {
423 		syscallarg(int) s;
424 		syscallarg(caddr_t) msg;
425 		syscallarg(int) flags;
426 	} */ *uap = v;
427 	struct msghdr msg;
428 	struct iovec aiov[UIO_SMALLIOV], *iov;
429 	int error;
430 
431 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
432 	if (error)
433 		return (error);
434 	if (msg.msg_iovlen < 0 || msg.msg_iovlen > IOV_MAX)
435 		return (EMSGSIZE);
436 	if (msg.msg_iovlen > UIO_SMALLIOV)
437 		iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
438 		    M_IOV, M_WAITOK);
439 	else
440 		iov = aiov;
441 	if (msg.msg_iovlen &&
442 	    (error = copyin(msg.msg_iov, iov,
443 		    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
444 		goto done;
445 	msg.msg_iov = iov;
446 #ifdef COMPAT_OLDSOCK
447 	msg.msg_flags = 0;
448 #endif
449 	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
450 done:
451 	if (iov != aiov)
452 		free(iov, M_IOV);
453 	return (error);
454 }
455 
456 int
457 sendit(p, s, mp, flags, retsize)
458 	struct proc *p;
459 	int s;
460 	struct msghdr *mp;
461 	int flags;
462 	register_t *retsize;
463 {
464 	struct file *fp;
465 	struct uio auio;
466 	struct iovec *iov;
467 	int i;
468 	struct mbuf *to, *control;
469 	int len, error;
470 #ifdef KTRACE
471 	struct iovec *ktriov = NULL;
472 #endif
473 
474 	to = NULL;
475 
476 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
477 		return (error);
478 	auio.uio_iov = mp->msg_iov;
479 	auio.uio_iovcnt = mp->msg_iovlen;
480 	auio.uio_segflg = UIO_USERSPACE;
481 	auio.uio_rw = UIO_WRITE;
482 	auio.uio_procp = p;
483 	auio.uio_offset = 0;			/* XXX */
484 	auio.uio_resid = 0;
485 	iov = mp->msg_iov;
486 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
487 		/* Don't allow sum > SSIZE_MAX */
488 		if (iov->iov_len > SSIZE_MAX ||
489 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
490 			error = EINVAL;
491 			goto bad;
492 		}
493 	}
494 	if (mp->msg_name) {
495 		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
496 				 MT_SONAME);
497 		if (error)
498 			goto bad;
499 	}
500 	if (mp->msg_control) {
501 		if (mp->msg_controllen < sizeof(struct cmsghdr)
502 #ifdef COMPAT_OLDSOCK
503 		    && mp->msg_flags != MSG_COMPAT
504 #endif
505 		) {
506 			error = EINVAL;
507 			goto bad;
508 		}
509 		error = sockargs(&control, mp->msg_control,
510 				 mp->msg_controllen, MT_CONTROL);
511 		if (error)
512 			goto bad;
513 #ifdef COMPAT_OLDSOCK
514 		if (mp->msg_flags == MSG_COMPAT) {
515 			register struct cmsghdr *cm;
516 
517 			M_PREPEND(control, sizeof(*cm), M_WAIT);
518 			cm = mtod(control, struct cmsghdr *);
519 			cm->cmsg_len = control->m_len;
520 			cm->cmsg_level = SOL_SOCKET;
521 			cm->cmsg_type = SCM_RIGHTS;
522 		}
523 #endif
524 	} else
525 		control = 0;
526 #ifdef KTRACE
527 	if (KTRPOINT(p, KTR_GENIO)) {
528 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
529 
530 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
531 		bcopy(auio.uio_iov, ktriov, iovlen);
532 	}
533 #endif
534 	len = auio.uio_resid;
535 	error = sosend((struct socket *)fp->f_data, to, &auio,
536 	    NULL, control, flags);
537 	if (error) {
538 		if (auio.uio_resid != len && (error == ERESTART ||
539 		    error == EINTR || error == EWOULDBLOCK))
540 			error = 0;
541 		if (error == EPIPE)
542 			psignal(p, SIGPIPE);
543 	}
544 	if (error == 0)
545 		*retsize = len - auio.uio_resid;
546 #ifdef KTRACE
547 	if (ktriov != NULL) {
548 		if (error == 0)
549 			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
550 		free(ktriov, M_TEMP);
551 	}
552 #endif
553 bad:
554 	FRELE(fp);
555 	if (to)
556 		m_freem(to);
557 	return (error);
558 }
559 
560 int
561 sys_recvfrom(p, v, retval)
562 	struct proc *p;
563 	void *v;
564 	register_t *retval;
565 {
566 	register struct sys_recvfrom_args /* {
567 		syscallarg(int) s;
568 		syscallarg(caddr_t) buf;
569 		syscallarg(size_t) len;
570 		syscallarg(int) flags;
571 		syscallarg(struct sockaddr *) from;
572 		syscallarg(socklen_t *) fromlenaddr;
573 	} */ *uap = v;
574 	struct msghdr msg;
575 	struct iovec aiov;
576 	int error;
577 
578 	if (SCARG(uap, fromlenaddr)) {
579 		error = copyin(SCARG(uap, fromlenaddr),
580 		    &msg.msg_namelen, sizeof (msg.msg_namelen));
581 		if (error)
582 			return (error);
583 	} else
584 		msg.msg_namelen = 0;
585 	msg.msg_name = (caddr_t)SCARG(uap, from);
586 	msg.msg_iov = &aiov;
587 	msg.msg_iovlen = 1;
588 	aiov.iov_base = SCARG(uap, buf);
589 	aiov.iov_len = SCARG(uap, len);
590 	msg.msg_control = 0;
591 	msg.msg_flags = SCARG(uap, flags);
592 	return (recvit(p, SCARG(uap, s), &msg,
593 	    (caddr_t)SCARG(uap, fromlenaddr), retval));
594 }
595 
596 int
597 sys_recvmsg(p, v, retval)
598 	struct proc *p;
599 	void *v;
600 	register_t *retval;
601 {
602 	register struct sys_recvmsg_args /* {
603 		syscallarg(int) s;
604 		syscallarg(struct msghdr *) msg;
605 		syscallarg(int) flags;
606 	} */ *uap = v;
607 	struct msghdr msg;
608 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
609 	int error;
610 
611 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
612 	if (error)
613 		return (error);
614 	if (msg.msg_iovlen < 0 || msg.msg_iovlen > IOV_MAX)
615 		return (EMSGSIZE);
616 	if (msg.msg_iovlen > UIO_SMALLIOV)
617 		iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
618 		    M_IOV, M_WAITOK);
619 	else
620 		iov = aiov;
621 #ifdef COMPAT_OLDSOCK
622 	msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
623 #else
624 	msg.msg_flags = SCARG(uap, flags);
625 #endif
626 	if (msg.msg_iovlen > 0) {
627 		error = copyin(msg.msg_iov, iov,
628 		    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
629 		if (error)
630 			goto done;
631 	}
632 	uiov = msg.msg_iov;
633 	msg.msg_iov = iov;
634 	if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
635 		msg.msg_iov = uiov;
636 		error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
637 	}
638 done:
639 	if (iov != aiov)
640 		free(iov, M_IOV);
641 	return (error);
642 }
643 
644 int
645 recvit(p, s, mp, namelenp, retsize)
646 	struct proc *p;
647 	int s;
648 	struct msghdr *mp;
649 	caddr_t namelenp;
650 	register_t *retsize;
651 {
652 	struct file *fp;
653 	struct uio auio;
654 	register struct iovec *iov;
655 	register int i;
656 	size_t len;
657 	int error;
658 	struct mbuf *from = NULL, *control = NULL;
659 #ifdef KTRACE
660 	struct iovec *ktriov = NULL;
661 #endif
662 
663 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
664 		return (error);
665 	auio.uio_iov = mp->msg_iov;
666 	auio.uio_iovcnt = mp->msg_iovlen;
667 	auio.uio_segflg = UIO_USERSPACE;
668 	auio.uio_rw = UIO_READ;
669 	auio.uio_procp = p;
670 	auio.uio_offset = 0;			/* XXX */
671 	auio.uio_resid = 0;
672 	iov = mp->msg_iov;
673 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
674 		/* Don't allow sum > SSIZE_MAX */
675 		if (iov->iov_len > SSIZE_MAX ||
676 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
677 			error = EINVAL;
678 			goto out;
679 		}
680 	}
681 #ifdef KTRACE
682 	if (KTRPOINT(p, KTR_GENIO)) {
683 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
684 
685 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
686 		bcopy(auio.uio_iov, ktriov, iovlen);
687 	}
688 #endif
689 	len = auio.uio_resid;
690 	error = soreceive((struct socket *)fp->f_data, &from, &auio,
691 			  NULL, mp->msg_control ? &control : NULL,
692 			  &mp->msg_flags);
693 	if (error) {
694 		if (auio.uio_resid != len && (error == ERESTART ||
695 		    error == EINTR || error == EWOULDBLOCK))
696 			error = 0;
697 	}
698 #ifdef KTRACE
699 	if (ktriov != NULL) {
700 		if (error == 0)
701 			ktrgenio(p, s, UIO_READ,
702 				ktriov, len - auio.uio_resid, error);
703 		free(ktriov, M_TEMP);
704 	}
705 #endif
706 	if (error)
707 		goto out;
708 	*retsize = len - auio.uio_resid;
709 	if (mp->msg_name) {
710 		socklen_t alen;
711 
712 		if (from == 0)
713 			alen = 0;
714 		else {
715 			/* save sa_len before it is destroyed by MSG_COMPAT */
716 			alen = mp->msg_namelen;
717 			if (alen > from->m_len)
718 				alen = from->m_len;
719 			/* else if alen < from->m_len ??? */
720 #ifdef COMPAT_OLDSOCK
721 			if (mp->msg_flags & MSG_COMPAT)
722 				mtod(from, struct osockaddr *)->sa_family =
723 				    mtod(from, struct sockaddr *)->sa_family;
724 #endif
725 			error = copyout(mtod(from, caddr_t),
726 			    mp->msg_name, alen);
727 			if (error)
728 				goto out;
729 		}
730 		mp->msg_namelen = alen;
731 		if (namelenp &&
732 		    (error = copyout(&alen, namelenp, sizeof(alen)))) {
733 #ifdef COMPAT_OLDSOCK
734 			if (mp->msg_flags & MSG_COMPAT)
735 				error = 0;	/* old recvfrom didn't check */
736 			else
737 #endif
738 			goto out;
739 		}
740 	}
741 	if (mp->msg_control) {
742 #ifdef COMPAT_OLDSOCK
743 		/*
744 		 * We assume that old recvmsg calls won't receive access
745 		 * rights and other control info, esp. as control info
746 		 * is always optional and those options didn't exist in 4.3.
747 		 * If we receive rights, trim the cmsghdr; anything else
748 		 * is tossed.
749 		 */
750 		if (control && mp->msg_flags & MSG_COMPAT) {
751 			if (mtod(control, struct cmsghdr *)->cmsg_level !=
752 			    SOL_SOCKET ||
753 			    mtod(control, struct cmsghdr *)->cmsg_type !=
754 			    SCM_RIGHTS) {
755 				mp->msg_controllen = 0;
756 				goto out;
757 			}
758 			control->m_len -= sizeof (struct cmsghdr);
759 			control->m_data += sizeof (struct cmsghdr);
760 		}
761 #endif
762 		len = mp->msg_controllen;
763 		if (len <= 0 || control == 0)
764 			len = 0;
765 		else {
766 			struct mbuf *m = control;
767 			caddr_t p = (caddr_t)mp->msg_control;
768 
769 			do {
770 				i = m->m_len;
771 				if (len < i) {
772 					mp->msg_flags |= MSG_CTRUNC;
773 					i = len;
774 				}
775 				error = copyout(mtod(m, caddr_t), p,
776 				    (unsigned)i);
777 				if (m->m_next)
778 					i = ALIGN(i);
779 				p += i;
780 				len -= i;
781 				if (error != 0 || len <= 0)
782 					break;
783 			} while ((m = m->m_next) != NULL);
784 			len = p - (caddr_t)mp->msg_control;
785 		}
786 		mp->msg_controllen = len;
787 	}
788 out:
789 	FRELE(fp);
790 	if (from)
791 		m_freem(from);
792 	if (control)
793 		m_freem(control);
794 	return (error);
795 }
796 
797 /* ARGSUSED */
798 int
799 sys_shutdown(p, v, retval)
800 	struct proc *p;
801 	void *v;
802 	register_t *retval;
803 {
804 	struct sys_shutdown_args /* {
805 		syscallarg(int) s;
806 		syscallarg(int) how;
807 	} */ *uap = v;
808 	struct file *fp;
809 	int error;
810 
811 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
812 		return (error);
813 	error = soshutdown((struct socket *)fp->f_data, SCARG(uap, how));
814 	FRELE(fp);
815 	return (error);
816 }
817 
818 /* ARGSUSED */
819 int
820 sys_setsockopt(p, v, retval)
821 	struct proc *p;
822 	void *v;
823 	register_t *retval;
824 {
825 	struct sys_setsockopt_args /* {
826 		syscallarg(int) s;
827 		syscallarg(int) level;
828 		syscallarg(int) name;
829 		syscallarg(caddr_t) val;
830 		syscallarg(socklen_t) valsize;
831 	} */ *uap = v;
832 	struct file *fp;
833 	struct mbuf *m = NULL;
834 	int error;
835 
836 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
837 		return (error);
838 	if (SCARG(uap, valsize) > MCLBYTES) {
839 		error = EINVAL;
840 		goto bad;
841 	}
842 	if (SCARG(uap, val)) {
843 		m = m_get(M_WAIT, MT_SOOPTS);
844 		if (SCARG(uap, valsize) > MLEN) {
845 			MCLGET(m, M_DONTWAIT);
846 			if ((m->m_flags & M_EXT) == 0) {
847 				error = ENOBUFS;
848 				goto bad;
849 			}
850 		}
851 		if (m == NULL) {
852 			error = ENOBUFS;
853 			goto bad;
854 		}
855 		error = copyin(SCARG(uap, val), mtod(m, caddr_t),
856 		    SCARG(uap, valsize));
857 		if (error) {
858 			goto bad;
859 		}
860 		m->m_len = SCARG(uap, valsize);
861 	}
862 	error = sosetopt((struct socket *)fp->f_data, SCARG(uap, level),
863 			 SCARG(uap, name), m);
864 	m = NULL;
865 bad:
866 	if (m)
867 		m_freem(m);
868 	FRELE(fp);
869 	return (error);
870 }
871 
872 /* ARGSUSED */
873 int
874 sys_getsockopt(p, v, retval)
875 	struct proc *p;
876 	void *v;
877 	register_t *retval;
878 {
879 	struct sys_getsockopt_args /* {
880 		syscallarg(int) s;
881 		syscallarg(int) level;
882 		syscallarg(int) name;
883 		syscallarg(caddr_t) val;
884 		syscallarg(socklen_t *) avalsize;
885 	} */ *uap = v;
886 	struct file *fp;
887 	struct mbuf *m = NULL;
888 	socklen_t valsize;
889 	int error;
890 
891 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
892 		return (error);
893 	if (SCARG(uap, val)) {
894 		error = copyin((caddr_t)SCARG(uap, avalsize),
895 		    (caddr_t)&valsize, sizeof (valsize));
896 		if (error)
897 			goto out;
898 	} else
899 		valsize = 0;
900 	if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level),
901 	    SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
902 	    m != NULL) {
903 		if (valsize > m->m_len)
904 			valsize = m->m_len;
905 		error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
906 		if (error == 0)
907 			error = copyout((caddr_t)&valsize,
908 			    (caddr_t)SCARG(uap, avalsize), sizeof (valsize));
909 	}
910 out:
911 	FRELE(fp);
912 	if (m != NULL)
913 		(void) m_free(m);
914 	return (error);
915 }
916 
917 int
918 sys_pipe(struct proc *p, void *v, register_t *retval)
919 {
920 	register struct sys_pipe_args /* {
921 		syscallarg(int *) fdp;
922 	} */ *uap = v;
923 	int error, fds[2];
924 	register_t rval[2];
925 
926 	if ((error = sys_opipe(p, v, rval)) != 0)
927 		return (error);
928 
929 	fds[0] = rval[0];
930 	fds[1] = rval[1];
931 	error = copyout((caddr_t)fds, (caddr_t)SCARG(uap, fdp),
932 	    2 * sizeof (int));
933 	if (error) {
934 		fdrelease(p, fds[0]);
935 		fdrelease(p, fds[1]);
936 	}
937 	return (error);
938 }
939 
940 /*
941  * Get socket name.
942  */
943 /* ARGSUSED */
944 int
945 sys_getsockname(p, v, retval)
946 	struct proc *p;
947 	void *v;
948 	register_t *retval;
949 {
950 	struct sys_getsockname_args /* {
951 		syscallarg(int) fdes;
952 		syscallarg(caddr_t) asa;
953 		syscallarg(socklen_t *) alen;
954 	} */ *uap = v;
955 	struct file *fp;
956 	struct socket *so;
957 	struct mbuf *m = NULL;
958 	socklen_t len;
959 	int error;
960 
961 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
962 		return (error);
963 	error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len));
964 	if (error)
965 		goto bad;
966 	so = (struct socket *)fp->f_data;
967 	m = m_getclr(M_WAIT, MT_SONAME);
968 	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
969 	if (error)
970 		goto bad;
971 	if (len > m->m_len)
972 		len = m->m_len;
973 	error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len);
974 	if (error == 0)
975 		error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
976 		    sizeof (len));
977 bad:
978 	FRELE(fp);
979 	if (m)
980 		m_freem(m);
981 	return (error);
982 }
983 
984 /*
985  * Get name of peer for connected socket.
986  */
987 /* ARGSUSED */
988 int
989 sys_getpeername(p, v, retval)
990 	struct proc *p;
991 	void *v;
992 	register_t *retval;
993 {
994 	struct sys_getpeername_args /* {
995 		syscallarg(int) fdes;
996 		syscallarg(caddr_t) asa;
997 		syscallarg(socklen_t *) alen;
998 	} */ *uap = v;
999 	struct file *fp;
1000 	register struct socket *so;
1001 	struct mbuf *m = NULL;
1002 	socklen_t len;
1003 	int error;
1004 
1005 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1006 		return (error);
1007 	so = (struct socket *)fp->f_data;
1008 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
1009 		FRELE(fp);
1010 		return (ENOTCONN);
1011 	}
1012 	error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len));
1013 	if (error)
1014 		goto bad;
1015 	m = m_getclr(M_WAIT, MT_SONAME);
1016 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
1017 	if (error)
1018 		goto bad;
1019 	if (len > m->m_len)
1020 		len = m->m_len;
1021 	error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len);
1022 	if (error == 0)
1023 		error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
1024 		    sizeof (len));
1025 bad:
1026 	FRELE(fp);
1027 	m_freem(m);
1028 	return (error);
1029 }
1030 
1031 /*
1032  * Get eid of peer for connected socket.
1033  */
1034 /* ARGSUSED */
1035 int
1036 sys_getpeereid(p, v, retval)
1037 	struct proc *p;
1038 	void *v;
1039 	register_t *retval;
1040 {
1041 	struct sys_getpeereid_args /* {
1042 		syscallarg(int) fdes;
1043 		syscallarg(uid_t *) euid;
1044 		syscallarg(gid_t *) egid;
1045 	} */ *uap = v;
1046 	struct file *fp;
1047 	struct socket *so;
1048 	struct mbuf *m = NULL;
1049 	struct unpcbid *id;
1050 	int error;
1051 
1052 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1053 		return (error);
1054 	so = (struct socket *)fp->f_data;
1055 	if (so->so_proto != pffindtype(AF_LOCAL, SOCK_STREAM)) {
1056 		FRELE(fp);
1057 		return (EOPNOTSUPP);
1058 	}
1059 	m = m_getclr(M_WAIT, MT_SONAME);
1060 	if (m == NULL) {
1061 		error = ENOBUFS;
1062 		goto bad;
1063 	}
1064 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEEREID, 0, m, 0);
1065 	if (!error && m->m_len != sizeof(struct unpcbid))
1066 		error = EOPNOTSUPP;
1067 	if (error)
1068 		goto bad;
1069 	id = mtod(m, struct unpcbid *);
1070 	error = copyout((caddr_t)&(id->unp_euid),
1071 		(caddr_t)SCARG(uap, euid), sizeof(uid_t));
1072 	if (error == 0)
1073 		error = copyout((caddr_t)&(id->unp_egid),
1074 		    (caddr_t)SCARG(uap, egid), sizeof(gid_t));
1075 bad:
1076 	FRELE(fp);
1077 	m_freem(m);
1078 	return (error);
1079 }
1080 
1081 int
1082 sockargs(mp, buf, buflen, type)
1083 	struct mbuf **mp;
1084 	caddr_t buf;
1085 	socklen_t buflen;
1086 	int type;
1087 {
1088 	struct sockaddr *sa;
1089 	struct mbuf *m;
1090 	int error;
1091 
1092 	/*
1093 	 * We can't allow socket names > UCHAR_MAX in length, since that
1094 	 * will overflow sa_len.
1095 	 */
1096 	if (type == MT_SONAME && (u_int)buflen > UCHAR_MAX)
1097 		return (EINVAL);
1098 	if ((u_int)buflen > MCLBYTES)
1099 		return (EINVAL);
1100 
1101 	/* Allocate an mbuf to hold the arguments. */
1102 	m = m_get(M_WAIT, type);
1103 	if ((u_int)buflen > MLEN) {
1104 		MCLGET(m, M_WAITOK);
1105 		if ((m->m_flags & M_EXT) == 0) {
1106 			m_free(m);
1107 			return ENOBUFS;
1108 		}
1109 	}
1110 	m->m_len = buflen;
1111 	error = copyin(buf, mtod(m, caddr_t), buflen);
1112 	if (error) {
1113 		(void) m_free(m);
1114 		return (error);
1115 	}
1116 	*mp = m;
1117 	if (type == MT_SONAME) {
1118 		sa = mtod(m, struct sockaddr *);
1119 
1120 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1121 		if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1122 			sa->sa_family = sa->sa_len;
1123 #endif
1124 		sa->sa_len = buflen;
1125 	}
1126 	return (0);
1127 }
1128 
1129 int
1130 getsock(struct filedesc *fdp, int fdes, struct file **fpp)
1131 {
1132 	struct file *fp;
1133 
1134 	if ((fp = fd_getfile(fdp, fdes)) == NULL)
1135 		return (EBADF);
1136 	if (fp->f_type != DTYPE_SOCKET)
1137 		return (ENOTSOCK);
1138 	*fpp = fp;
1139 	FREF(fp);
1140 
1141 	return (0);
1142 }
1143