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