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