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