xref: /openbsd-src/sys/kern/uipc_syscalls.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: uipc_syscalls.c,v 1.82 2011/07/08 20:54:03 deraadt 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 #include <net/route.h>
58 
59 /*
60  * System call interface to the socket abstraction.
61  */
62 extern	struct fileops socketops;
63 
64 int
65 sys_socket(struct proc *p, void *v, register_t *retval)
66 {
67 	struct sys_socket_args /* {
68 		syscallarg(int) domain;
69 		syscallarg(int) type;
70 		syscallarg(int) protocol;
71 	} */ *uap = v;
72 	struct filedesc *fdp = p->p_fd;
73 	struct socket *so;
74 	struct file *fp;
75 	int fd, error;
76 
77 	fdplock(fdp);
78 
79 	if ((error = falloc(p, &fp, &fd)) != 0)
80 		goto out;
81 	fp->f_flag = FREAD|FWRITE;
82 	fp->f_type = DTYPE_SOCKET;
83 	fp->f_ops = &socketops;
84 	error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
85 			 SCARG(uap, protocol));
86 	if (error) {
87 		fdremove(fdp, fd);
88 		closef(fp, p);
89 	} else {
90 		fp->f_data = so;
91 		FILE_SET_MATURE(fp);
92 		*retval = fd;
93 	}
94 out:
95 	fdpunlock(fdp);
96 	return (error);
97 }
98 
99 /* ARGSUSED */
100 int
101 sys_bind(struct proc *p, void *v, register_t *retval)
102 {
103 	struct sys_bind_args /* {
104 		syscallarg(int) s;
105 		syscallarg(const 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, SCARG(uap, name), SCARG(uap, namelen),
115 			 MT_SONAME);
116 	if (error == 0) {
117 #ifdef KTRACE
118 	if (KTRPOINT(p, KTR_STRUCT))
119 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
120 #endif
121 		error = sobind(fp->f_data, nam, p);
122 		m_freem(nam);
123 	}
124 	FRELE(fp);
125 	return (error);
126 }
127 
128 /* ARGSUSED */
129 int
130 sys_listen(struct proc *p, void *v, register_t *retval)
131 {
132 	struct sys_listen_args /* {
133 		syscallarg(int) s;
134 		syscallarg(int) backlog;
135 	} */ *uap = v;
136 	struct file *fp;
137 	int error;
138 
139 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
140 		return (error);
141 	error = solisten(fp->f_data, SCARG(uap, backlog));
142 	FRELE(fp);
143 	return (error);
144 }
145 
146 int
147 sys_accept(struct proc *p, void *v, register_t *retval)
148 {
149 	struct sys_accept_args /* {
150 		syscallarg(int) s;
151 		syscallarg(struct sockaddr *) name;
152 		syscallarg(socklen_t *) anamelen;
153 	} */ *uap = v;
154 	struct file *fp, *headfp;
155 	struct mbuf *nam;
156 	socklen_t namelen;
157 	int error, s, tmpfd;
158 	struct socket *head, *so;
159 	int nflag;
160 
161 	if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen),
162 	    &namelen, sizeof (namelen))))
163 		return (error);
164 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
165 		return (error);
166 	headfp = fp;
167 	s = splsoftnet();
168 	head = fp->f_data;
169 	if ((head->so_options & SO_ACCEPTCONN) == 0) {
170 		error = EINVAL;
171 		goto bad;
172 	}
173 	if ((head->so_state & SS_NBIO) && head->so_qlen == 0) {
174 		if (head->so_state & SS_CANTRCVMORE)
175 			error = ECONNABORTED;
176 		else
177 			error = EWOULDBLOCK;
178 		goto bad;
179 	}
180 	while (head->so_qlen == 0 && head->so_error == 0) {
181 		if (head->so_state & SS_CANTRCVMORE) {
182 			head->so_error = ECONNABORTED;
183 			break;
184 		}
185 		error = tsleep(&head->so_timeo, PSOCK | PCATCH, "netcon", 0);
186 		if (error) {
187 			goto bad;
188 		}
189 	}
190 	if (head->so_error) {
191 		error = head->so_error;
192 		head->so_error = 0;
193 		goto bad;
194 	}
195 
196 	/*
197 	 * At this point we know that there is at least one connection
198 	 * ready to be accepted. Remove it from the queue prior to
199 	 * allocating the file descriptor for it since falloc() may
200 	 * block allowing another process to accept the connection
201 	 * instead.
202 	 */
203 	so = TAILQ_FIRST(&head->so_q);
204 	if (soqremque(so, 1) == 0)
205 		panic("accept");
206 
207 	/* Take note if socket was non-blocking. */
208 	nflag = (fp->f_flag & FNONBLOCK);
209 
210 	fdplock(p->p_fd);
211 	if ((error = falloc(p, &fp, &tmpfd)) != 0) {
212 		/*
213 		 * Probably ran out of file descriptors. Put the
214 		 * unaccepted connection back onto the queue and
215 		 * do another wakeup so some other process might
216 		 * have a chance at it.
217 		 */
218 		soqinsque(head, so, 1);
219 		wakeup_one(&head->so_timeo);
220 		goto unlock;
221 	}
222 	*retval = tmpfd;
223 
224 	/* connection has been removed from the listen queue */
225 	KNOTE(&head->so_rcv.sb_sel.si_note, 0);
226 
227 	fp->f_type = DTYPE_SOCKET;
228 	fp->f_flag = FREAD | FWRITE | nflag;
229 	fp->f_ops = &socketops;
230 	fp->f_data = so;
231 	nam = m_get(M_WAIT, MT_SONAME);
232 	error = soaccept(so, nam);
233 	if (!error && SCARG(uap, name)) {
234 		if (namelen > nam->m_len)
235 			namelen = nam->m_len;
236 		/* SHOULD COPY OUT A CHAIN HERE */
237 		if ((error = copyout(mtod(nam, caddr_t),
238 		    SCARG(uap, name), namelen)) == 0) {
239 #ifdef KTRACE
240 			if (KTRPOINT(p, KTR_STRUCT))
241 				ktrsockaddr(p, mtod(nam, caddr_t), namelen);
242 #endif
243 			error = copyout(&namelen, SCARG(uap, anamelen),
244 			    sizeof (*SCARG(uap, anamelen)));
245 		}
246 	}
247 	/* if an error occurred, free the file descriptor */
248 	if (error) {
249 		fdremove(p->p_fd, tmpfd);
250 		closef(fp, p);
251 	} else {
252 		FILE_SET_MATURE(fp);
253 	}
254 	m_freem(nam);
255 unlock:
256 	fdpunlock(p->p_fd);
257 bad:
258 	splx(s);
259 	FRELE(headfp);
260 	return (error);
261 }
262 
263 /* ARGSUSED */
264 int
265 sys_connect(struct proc *p, void *v, register_t *retval)
266 {
267 	struct sys_connect_args /* {
268 		syscallarg(int) s;
269 		syscallarg(const struct sockaddr *) name;
270 		syscallarg(socklen_t) namelen;
271 	} */ *uap = v;
272 	struct file *fp;
273 	struct socket *so;
274 	struct mbuf *nam = NULL;
275 	int error, s;
276 
277 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
278 		return (error);
279 	so = fp->f_data;
280 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
281 		FRELE(fp);
282 		return (EALREADY);
283 	}
284 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
285 			 MT_SONAME);
286 	if (error)
287 		goto bad;
288 #ifdef KTRACE
289 	if (KTRPOINT(p, KTR_STRUCT))
290 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
291 #endif
292 	error = soconnect(so, nam);
293 	if (error)
294 		goto bad;
295 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
296 		FRELE(fp);
297 		m_freem(nam);
298 		return (EINPROGRESS);
299 	}
300 	s = splsoftnet();
301 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
302 		error = tsleep(&so->so_timeo, PSOCK | PCATCH,
303 		    "netcon2", 0);
304 		if (error)
305 			break;
306 	}
307 	if (error == 0) {
308 		error = so->so_error;
309 		so->so_error = 0;
310 	}
311 	splx(s);
312 bad:
313 	so->so_state &= ~SS_ISCONNECTING;
314 	FRELE(fp);
315 	if (nam)
316 		m_freem(nam);
317 	if (error == ERESTART)
318 		error = EINTR;
319 	return (error);
320 }
321 
322 int
323 sys_socketpair(struct proc *p, void *v, register_t *retval)
324 {
325 	struct sys_socketpair_args /* {
326 		syscallarg(int) domain;
327 		syscallarg(int) type;
328 		syscallarg(int) protocol;
329 		syscallarg(int *) rsv;
330 	} */ *uap = v;
331 	struct filedesc *fdp = p->p_fd;
332 	struct file *fp1, *fp2;
333 	struct socket *so1, *so2;
334 	int fd, error, sv[2];
335 
336 	error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
337 			 SCARG(uap, protocol));
338 	if (error)
339 		return (error);
340 	error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
341 			 SCARG(uap, protocol));
342 	if (error)
343 		goto free1;
344 
345 	fdplock(fdp);
346 	if ((error = falloc(p, &fp1, &fd)) != 0)
347 		goto free2;
348 	sv[0] = fd;
349 	fp1->f_flag = FREAD|FWRITE;
350 	fp1->f_type = DTYPE_SOCKET;
351 	fp1->f_ops = &socketops;
352 	fp1->f_data = so1;
353 	if ((error = falloc(p, &fp2, &fd)) != 0)
354 		goto free3;
355 	fp2->f_flag = FREAD|FWRITE;
356 	fp2->f_type = DTYPE_SOCKET;
357 	fp2->f_ops = &socketops;
358 	fp2->f_data = so2;
359 	sv[1] = fd;
360 	if ((error = soconnect2(so1, so2)) != 0)
361 		goto free4;
362 	if (SCARG(uap, type) == SOCK_DGRAM) {
363 		/*
364 		 * Datagram socket connection is asymmetric.
365 		 */
366 		 if ((error = soconnect2(so2, so1)) != 0)
367 			goto free4;
368 	}
369 	error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
370 	if (error == 0) {
371 		FILE_SET_MATURE(fp1);
372 		FILE_SET_MATURE(fp2);
373 		fdpunlock(fdp);
374 		return (0);
375 	}
376 free4:
377 	fdremove(fdp, sv[1]);
378 	closef(fp2, p);
379 	so2 = NULL;
380 free3:
381 	fdremove(fdp, sv[0]);
382 	closef(fp1, p);
383 	so1 = NULL;
384 free2:
385 	if (so2 != NULL)
386 		(void)soclose(so2);
387 	fdpunlock(fdp);
388 free1:
389 	if (so1 != NULL)
390 		(void)soclose(so1);
391 	return (error);
392 }
393 
394 int
395 sys_sendto(struct proc *p, void *v, register_t *retval)
396 {
397 	struct sys_sendto_args /* {
398 		syscallarg(int) s;
399 		syscallarg(const void *) buf;
400 		syscallarg(size_t) len;
401 		syscallarg(int) flags;
402 		syscallarg(const struct sockaddr *) to;
403 		syscallarg(socklen_t) tolen;
404 	} */ *uap = v;
405 	struct msghdr msg;
406 	struct iovec aiov;
407 
408 	msg.msg_name = (caddr_t)SCARG(uap, to);
409 	msg.msg_namelen = SCARG(uap, tolen);
410 	msg.msg_iov = &aiov;
411 	msg.msg_iovlen = 1;
412 	msg.msg_control = 0;
413 	msg.msg_flags = 0;
414 	aiov.iov_base = (char *)SCARG(uap, buf);
415 	aiov.iov_len = SCARG(uap, len);
416 	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
417 }
418 
419 int
420 sys_sendmsg(struct proc *p, void *v, register_t *retval)
421 {
422 	struct sys_sendmsg_args /* {
423 		syscallarg(int) s;
424 		syscallarg(const struct msghdr *) 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 > 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 	msg.msg_flags = 0;
447 	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
448 done:
449 	if (iov != aiov)
450 		free(iov, M_IOV);
451 	return (error);
452 }
453 
454 int
455 sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
456 {
457 	struct file *fp;
458 	struct uio auio;
459 	struct iovec *iov;
460 	int i;
461 	struct mbuf *to, *control;
462 	size_t len;
463 	int error;
464 #ifdef KTRACE
465 	struct iovec *ktriov = NULL;
466 #endif
467 
468 	to = NULL;
469 
470 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
471 		return (error);
472 	auio.uio_iov = mp->msg_iov;
473 	auio.uio_iovcnt = mp->msg_iovlen;
474 	auio.uio_segflg = UIO_USERSPACE;
475 	auio.uio_rw = UIO_WRITE;
476 	auio.uio_procp = p;
477 	auio.uio_offset = 0;			/* XXX */
478 	auio.uio_resid = 0;
479 	iov = mp->msg_iov;
480 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
481 		/* Don't allow sum > SSIZE_MAX */
482 		if (iov->iov_len > SSIZE_MAX ||
483 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
484 			error = EINVAL;
485 			goto bad;
486 		}
487 	}
488 	if (mp->msg_name) {
489 		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
490 				 MT_SONAME);
491 		if (error)
492 			goto bad;
493 #ifdef KTRACE
494 		if (KTRPOINT(p, KTR_STRUCT))
495 		 	ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen);
496 #endif
497 	}
498 	if (mp->msg_control) {
499 		if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) {
500 			error = EINVAL;
501 			goto bad;
502 		}
503 		error = sockargs(&control, mp->msg_control,
504 				 mp->msg_controllen, MT_CONTROL);
505 		if (error)
506 			goto bad;
507 	} else
508 		control = 0;
509 #ifdef KTRACE
510 	if (KTRPOINT(p, KTR_GENIO)) {
511 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
512 
513 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
514 		bcopy(auio.uio_iov, ktriov, iovlen);
515 	}
516 #endif
517 	len = auio.uio_resid;
518 	error = sosend(fp->f_data, to, &auio, NULL, control, flags);
519 	if (error) {
520 		if (auio.uio_resid != len && (error == ERESTART ||
521 		    error == EINTR || error == EWOULDBLOCK))
522 			error = 0;
523 		if (error == EPIPE)
524 			ptsignal(p, SIGPIPE, STHREAD);
525 	}
526 	if (error == 0) {
527 		*retsize = len - auio.uio_resid;
528 		fp->f_wxfer++;
529 		fp->f_wbytes += *retsize;
530 	}
531 #ifdef KTRACE
532 	if (ktriov != NULL) {
533 		if (error == 0)
534 			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
535 		free(ktriov, M_TEMP);
536 	}
537 #endif
538 bad:
539 	FRELE(fp);
540 	if (to)
541 		m_freem(to);
542 	return (error);
543 }
544 
545 int
546 sys_recvfrom(struct proc *p, void *v, register_t *retval)
547 {
548 	struct sys_recvfrom_args /* {
549 		syscallarg(int) s;
550 		syscallarg(void *) buf;
551 		syscallarg(size_t) len;
552 		syscallarg(int) flags;
553 		syscallarg(struct sockaddr *) from;
554 		syscallarg(socklen_t *) fromlenaddr;
555 	} */ *uap = v;
556 	struct msghdr msg;
557 	struct iovec aiov;
558 	int error;
559 
560 	if (SCARG(uap, fromlenaddr)) {
561 		error = copyin(SCARG(uap, fromlenaddr),
562 		    &msg.msg_namelen, sizeof (msg.msg_namelen));
563 		if (error)
564 			return (error);
565 	} else
566 		msg.msg_namelen = 0;
567 	msg.msg_name = (caddr_t)SCARG(uap, from);
568 	msg.msg_iov = &aiov;
569 	msg.msg_iovlen = 1;
570 	aiov.iov_base = SCARG(uap, buf);
571 	aiov.iov_len = SCARG(uap, len);
572 	msg.msg_control = 0;
573 	msg.msg_flags = SCARG(uap, flags);
574 	return (recvit(p, SCARG(uap, s), &msg,
575 	    (caddr_t)SCARG(uap, fromlenaddr), retval));
576 }
577 
578 int
579 sys_recvmsg(struct proc *p, void *v, register_t *retval)
580 {
581 	struct sys_recvmsg_args /* {
582 		syscallarg(int) s;
583 		syscallarg(struct msghdr *) msg;
584 		syscallarg(int) flags;
585 	} */ *uap = v;
586 	struct msghdr msg;
587 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
588 	int error;
589 
590 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
591 	if (error)
592 		return (error);
593 	if (msg.msg_iovlen > IOV_MAX)
594 		return (EMSGSIZE);
595 	if (msg.msg_iovlen > UIO_SMALLIOV)
596 		iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
597 		    M_IOV, M_WAITOK);
598 	else
599 		iov = aiov;
600 	msg.msg_flags = SCARG(uap, flags);
601 	if (msg.msg_iovlen > 0) {
602 		error = copyin(msg.msg_iov, iov,
603 		    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
604 		if (error)
605 			goto done;
606 	}
607 	uiov = msg.msg_iov;
608 	msg.msg_iov = iov;
609 	if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
610 		msg.msg_iov = uiov;
611 		error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
612 	}
613 done:
614 	if (iov != aiov)
615 		free(iov, M_IOV);
616 	return (error);
617 }
618 
619 int
620 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
621     register_t *retsize)
622 {
623 	struct file *fp;
624 	struct uio auio;
625 	struct iovec *iov;
626 	int i;
627 	size_t len;
628 	int error;
629 	struct mbuf *from = NULL, *control = NULL;
630 #ifdef KTRACE
631 	struct iovec *ktriov = NULL;
632 #endif
633 
634 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
635 		return (error);
636 	auio.uio_iov = mp->msg_iov;
637 	auio.uio_iovcnt = mp->msg_iovlen;
638 	auio.uio_segflg = UIO_USERSPACE;
639 	auio.uio_rw = UIO_READ;
640 	auio.uio_procp = p;
641 	auio.uio_offset = 0;			/* XXX */
642 	auio.uio_resid = 0;
643 	iov = mp->msg_iov;
644 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
645 		/* Don't allow sum > SSIZE_MAX */
646 		if (iov->iov_len > SSIZE_MAX ||
647 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
648 			error = EINVAL;
649 			goto out;
650 		}
651 	}
652 #ifdef KTRACE
653 	if (KTRPOINT(p, KTR_GENIO)) {
654 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
655 
656 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
657 		bcopy(auio.uio_iov, ktriov, iovlen);
658 	}
659 #endif
660 	len = auio.uio_resid;
661 	error = soreceive(fp->f_data, &from, &auio, NULL,
662 			  mp->msg_control ? &control : NULL,
663 			  &mp->msg_flags,
664 			  mp->msg_control ? mp->msg_controllen : 0);
665 	if (error) {
666 		if (auio.uio_resid != len && (error == ERESTART ||
667 		    error == EINTR || error == EWOULDBLOCK))
668 			error = 0;
669 	}
670 #ifdef KTRACE
671 	if (ktriov != NULL) {
672 		if (error == 0)
673 			ktrgenio(p, s, UIO_READ,
674 				ktriov, len - auio.uio_resid, error);
675 		free(ktriov, M_TEMP);
676 	}
677 #endif
678 	if (error)
679 		goto out;
680 	*retsize = len - auio.uio_resid;
681 	if (mp->msg_name) {
682 		socklen_t alen;
683 
684 		if (from == NULL)
685 			alen = 0;
686 		else {
687 			alen = MIN(from->m_len, mp->msg_namelen);
688 			error = copyout(mtod(from, caddr_t), mp->msg_name,
689 			    alen);
690 			if (error)
691 				goto out;
692 #ifdef KTRACE
693 			if (KTRPOINT(p, KTR_STRUCT))
694 				ktrsockaddr(p, mtod(from, caddr_t), alen);
695 #endif
696 
697 		}
698 		mp->msg_namelen = alen;
699 		if (namelenp &&
700 		    (error = copyout(&alen, namelenp, sizeof(alen)))) {
701 			goto out;
702 		}
703 	}
704 	if (mp->msg_control) {
705 		len = mp->msg_controllen;
706 		if (len <= 0 || control == NULL)
707 			len = 0;
708 		else {
709 			struct mbuf *m = control;
710 			caddr_t p = mp->msg_control;
711 
712 			do {
713 				i = m->m_len;
714 				if (len < i) {
715 					mp->msg_flags |= MSG_CTRUNC;
716 					i = len;
717 				}
718 				error = copyout(mtod(m, caddr_t), p,
719 				    (unsigned)i);
720 				if (m->m_next)
721 					i = ALIGN(i);
722 				p += i;
723 				len -= i;
724 				if (error != 0 || len <= 0)
725 					break;
726 			} while ((m = m->m_next) != NULL);
727 			len = p - (caddr_t)mp->msg_control;
728 		}
729 		mp->msg_controllen = len;
730 	}
731 	if (!error) {
732 		fp->f_rxfer++;
733 		fp->f_rbytes += *retsize;
734 	}
735 out:
736 	FRELE(fp);
737 	if (from)
738 		m_freem(from);
739 	if (control)
740 		m_freem(control);
741 	return (error);
742 }
743 
744 /* ARGSUSED */
745 int
746 sys_shutdown(struct proc *p, void *v, register_t *retval)
747 {
748 	struct sys_shutdown_args /* {
749 		syscallarg(int) s;
750 		syscallarg(int) how;
751 	} */ *uap = v;
752 	struct file *fp;
753 	int error;
754 
755 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
756 		return (error);
757 	error = soshutdown(fp->f_data, SCARG(uap, how));
758 	FRELE(fp);
759 	return (error);
760 }
761 
762 /* ARGSUSED */
763 int
764 sys_setsockopt(struct proc *p, void *v, register_t *retval)
765 {
766 	struct sys_setsockopt_args /* {
767 		syscallarg(int) s;
768 		syscallarg(int) level;
769 		syscallarg(int) name;
770 		syscallarg(const void *) val;
771 		syscallarg(socklen_t) valsize;
772 	} */ *uap = v;
773 	struct file *fp;
774 	struct mbuf *m = NULL;
775 	int error;
776 
777 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
778 		return (error);
779 	if (SCARG(uap, valsize) > MCLBYTES) {
780 		error = EINVAL;
781 		goto bad;
782 	}
783 	if (SCARG(uap, val)) {
784 		m = m_get(M_WAIT, MT_SOOPTS);
785 		if (SCARG(uap, valsize) > MLEN) {
786 			MCLGET(m, M_DONTWAIT);
787 			if ((m->m_flags & M_EXT) == 0) {
788 				error = ENOBUFS;
789 				goto bad;
790 			}
791 		}
792 		if (m == NULL) {
793 			error = ENOBUFS;
794 			goto bad;
795 		}
796 		error = copyin(SCARG(uap, val), mtod(m, caddr_t),
797 		    SCARG(uap, valsize));
798 		if (error) {
799 			goto bad;
800 		}
801 		m->m_len = SCARG(uap, valsize);
802 	}
803 	error = sosetopt(fp->f_data, SCARG(uap, level),
804 			 SCARG(uap, name), m);
805 	m = NULL;
806 bad:
807 	if (m)
808 		m_freem(m);
809 	FRELE(fp);
810 	return (error);
811 }
812 
813 /* ARGSUSED */
814 int
815 sys_getsockopt(struct proc *p, void *v, register_t *retval)
816 {
817 	struct sys_getsockopt_args /* {
818 		syscallarg(int) s;
819 		syscallarg(int) level;
820 		syscallarg(int) name;
821 		syscallarg(void *) val;
822 		syscallarg(socklen_t *) avalsize;
823 	} */ *uap = v;
824 	struct file *fp;
825 	struct mbuf *m = NULL;
826 	socklen_t valsize;
827 	int error;
828 
829 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
830 		return (error);
831 	if (SCARG(uap, val)) {
832 		error = copyin(SCARG(uap, avalsize),
833 		    &valsize, sizeof (valsize));
834 		if (error)
835 			goto out;
836 	} else
837 		valsize = 0;
838 	if ((error = sogetopt(fp->f_data, SCARG(uap, level),
839 	    SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
840 	    m != NULL) {
841 		if (valsize > m->m_len)
842 			valsize = m->m_len;
843 		error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
844 		if (error == 0)
845 			error = copyout(&valsize,
846 			    SCARG(uap, avalsize), sizeof (valsize));
847 	}
848 out:
849 	FRELE(fp);
850 	if (m != NULL)
851 		(void)m_free(m);
852 	return (error);
853 }
854 
855 /*
856  * Get socket name.
857  */
858 /* ARGSUSED */
859 int
860 sys_getsockname(struct proc *p, void *v, register_t *retval)
861 {
862 	struct sys_getsockname_args /* {
863 		syscallarg(int) fdes;
864 		syscallarg(struct sockaddr *) asa;
865 		syscallarg(socklen_t *) alen;
866 	} */ *uap = v;
867 	struct file *fp;
868 	struct socket *so;
869 	struct mbuf *m = NULL;
870 	socklen_t len;
871 	int error;
872 
873 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
874 		return (error);
875 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
876 	if (error)
877 		goto bad;
878 	so = fp->f_data;
879 	m = m_getclr(M_WAIT, MT_SONAME);
880 	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p);
881 	if (error)
882 		goto bad;
883 	if (len > m->m_len)
884 		len = m->m_len;
885 	error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
886 	if (error == 0) {
887 #ifdef KTRACE
888 		if (KTRPOINT(p, KTR_STRUCT))
889 			ktrsockaddr(p, mtod(m, caddr_t), len);
890 #endif
891 		error = copyout(&len, SCARG(uap, alen), sizeof (len));
892 	}
893 bad:
894 	FRELE(fp);
895 	if (m)
896 		m_freem(m);
897 	return (error);
898 }
899 
900 /*
901  * Get name of peer for connected socket.
902  */
903 /* ARGSUSED */
904 int
905 sys_getpeername(struct proc *p, void *v, register_t *retval)
906 {
907 	struct sys_getpeername_args /* {
908 		syscallarg(int) fdes;
909 		syscallarg(struct sockaddr *) asa;
910 		syscallarg(socklen_t *) alen;
911 	} */ *uap = v;
912 	struct file *fp;
913 	struct socket *so;
914 	struct mbuf *m = NULL;
915 	socklen_t len;
916 	int error;
917 
918 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
919 		return (error);
920 	so = fp->f_data;
921 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
922 		FRELE(fp);
923 		return (ENOTCONN);
924 	}
925 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
926 	if (error)
927 		goto bad;
928 	m = m_getclr(M_WAIT, MT_SONAME);
929 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p);
930 	if (error)
931 		goto bad;
932 	if (len > m->m_len)
933 		len = m->m_len;
934 	error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
935 	if (error == 0) {
936 #ifdef KTRACE
937 		if (KTRPOINT(p, KTR_STRUCT))
938 			ktrsockaddr(p, mtod(m, caddr_t), len);
939 #endif
940 		error = copyout(&len, SCARG(uap, alen), sizeof (len));
941 	}
942 bad:
943 	FRELE(fp);
944 	m_freem(m);
945 	return (error);
946 }
947 
948 int
949 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
950 {
951 	struct sockaddr *sa;
952 	struct mbuf *m;
953 	int error;
954 
955 	/*
956 	 * We can't allow socket names > UCHAR_MAX in length, since that
957 	 * will overflow sa_len. Also, control data more than MCLBYTES in
958 	 * length is just too much.
959 	 */
960 	if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES))
961 		return (EINVAL);
962 
963 	/* Allocate an mbuf to hold the arguments. */
964 	m = m_get(M_WAIT, type);
965 	if ((u_int)buflen > MLEN) {
966 		MCLGET(m, M_WAITOK);
967 		if ((m->m_flags & M_EXT) == 0) {
968 			m_free(m);
969 			return ENOBUFS;
970 		}
971 	}
972 	m->m_len = buflen;
973 	error = copyin(buf, mtod(m, caddr_t), buflen);
974 	if (error) {
975 		(void) m_free(m);
976 		return (error);
977 	}
978 	*mp = m;
979 	if (type == MT_SONAME) {
980 		sa = mtod(m, struct sockaddr *);
981 #if BYTE_ORDER != BIG_ENDIAN
982 		if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
983 			sa->sa_family = sa->sa_len;
984 #endif
985 		sa->sa_len = buflen;
986 	}
987 	return (0);
988 }
989 
990 int
991 getsock(struct filedesc *fdp, int fdes, struct file **fpp)
992 {
993 	struct file *fp;
994 
995 	if ((fp = fd_getfile(fdp, fdes)) == NULL)
996 		return (EBADF);
997 	if (fp->f_type != DTYPE_SOCKET)
998 		return (ENOTSOCK);
999 	*fpp = fp;
1000 	FREF(fp);
1001 
1002 	return (0);
1003 }
1004 
1005 /* ARGSUSED */
1006 int
1007 sys_setrtable(struct proc *p, void *v, register_t *retval)
1008 {
1009 	struct sys_setrtable_args /* {
1010 		syscallarg(int) rtableid;
1011 	} */ *uap = v;
1012 	int rtableid, error;
1013 
1014 	rtableid = SCARG(uap, rtableid);
1015 
1016 	if (p->p_p->ps_rtableid == (u_int)rtableid)
1017 		return (0);
1018 	if (p->p_p->ps_rtableid != 0 && (error = suser(p, 0)) != 0)
1019 		return (error);
1020 	if (rtableid < 0 || !rtable_exists((u_int)rtableid))
1021 		return (EINVAL);
1022 
1023 	p->p_p->ps_rtableid = (u_int)rtableid;
1024 	return (0);
1025 }
1026 
1027 /* ARGSUSED */
1028 int
1029 sys_getrtable(struct proc *p, void *v, register_t *retval)
1030 {
1031 	*retval = (int)p->p_p->ps_rtableid;
1032 	return (0);
1033 }
1034