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