xref: /freebsd/sys/kern/uipc_syscalls.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
34  * $Id: uipc_syscalls.c,v 1.4 1994/10/02 17:35:35 phk Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/filedesc.h>
40 #include <sys/proc.h>
41 #include <sys/file.h>
42 #include <sys/buf.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/protosw.h>
46 #include <sys/stat.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 /*
56  * System call interface to the socket abstraction.
57  */
58 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
59 #define COMPAT_OLDSOCK
60 #endif
61 
62 extern	struct fileops socketops;
63 
64 struct socket_args {
65 	int	domain;
66 	int	type;
67 	int	protocol;
68 };
69 int
70 socket(p, uap, retval)
71 	struct proc *p;
72 	register struct socket_args *uap;
73 	int *retval;
74 {
75 	struct filedesc *fdp = p->p_fd;
76 	struct socket *so;
77 	struct file *fp;
78 	int fd, error;
79 
80 	error = falloc(p, &fp, &fd);
81 	if (error)
82 		return (error);
83 	fp->f_flag = FREAD|FWRITE;
84 	fp->f_type = DTYPE_SOCKET;
85 	fp->f_ops = &socketops;
86 	error = socreate(uap->domain, &so, uap->type, uap->protocol);
87 	if (error) {
88 		fdp->fd_ofiles[fd] = 0;
89 		ffree(fp);
90 	} else {
91 		fp->f_data = (caddr_t)so;
92 		*retval = fd;
93 	}
94 	return (error);
95 }
96 
97 struct bind_args {
98 	int	s;
99 	caddr_t	name;
100 	int	namelen;
101 };
102 /* ARGSUSED */
103 int
104 bind(p, uap, retval)
105 	struct proc *p;
106 	register struct bind_args *uap;
107 	int *retval;
108 {
109 	struct file *fp;
110 	struct mbuf *nam;
111 	int error;
112 
113 	error = getsock(p->p_fd, uap->s, &fp);
114 	if (error)
115 		return (error);
116 	error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
117 	if (error)
118 		return (error);
119 	error = sobind((struct socket *)fp->f_data, nam);
120 	m_freem(nam);
121 	return (error);
122 }
123 
124 struct listen_args {
125 	int	s;
126 	int	backlog;
127 };
128 /* ARGSUSED */
129 int
130 listen(p, uap, retval)
131 	struct proc *p;
132 	register struct listen_args *uap;
133 	int *retval;
134 {
135 	struct file *fp;
136 	int error;
137 
138 	error = getsock(p->p_fd, uap->s, &fp);
139 	if (error)
140 		return (error);
141 	return (solisten((struct socket *)fp->f_data, uap->backlog));
142 }
143 
144 struct accept_args {
145 	int	s;
146 	caddr_t	name;
147 	int	*anamelen;
148 #ifdef COMPAT_OLDSOCK
149 	int	compat_43;	/* pseudo */
150 #endif
151 };
152 
153 #ifndef COMPAT_OLDSOCK
154 #  define	accept1	accept
155 #endif  /* COMPAT_OLDSOCK*/
156 
157 int
158 accept1(p, uap, retval)
159 	struct proc *p;
160 	register struct accept_args *uap;
161 	int *retval;
162 {
163 	struct file *fp;
164 	struct mbuf *nam;
165 	int namelen, error, s;
166 	register struct socket *so;
167 
168 	if (uap->name) {
169 		error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
170 			sizeof (namelen));
171 		if(error)
172 			return (error);
173 	}
174 	error = getsock(p->p_fd, uap->s, &fp);
175 	if (error)
176 		return (error);
177 	s = splnet();
178 	so = (struct socket *)fp->f_data;
179 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
180 		splx(s);
181 		return (EINVAL);
182 	}
183 	if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
184 		splx(s);
185 		return (EWOULDBLOCK);
186 	}
187 	while (so->so_qlen == 0 && so->so_error == 0) {
188 		if (so->so_state & SS_CANTRCVMORE) {
189 			so->so_error = ECONNABORTED;
190 			break;
191 		}
192 		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
193 		    netcon, 0);
194 		if (error) {
195 			splx(s);
196 			return (error);
197 		}
198 	}
199 	if (so->so_error) {
200 		error = so->so_error;
201 		so->so_error = 0;
202 		splx(s);
203 		return (error);
204 	}
205 	error = falloc(p, &fp, retval);
206 	if (error) {
207 		splx(s);
208 		return (error);
209 	}
210 	{ struct socket *aso = so->so_q;
211 	  if (soqremque(aso, 1) == 0)
212 		panic("accept");
213 	  so = aso;
214 	}
215 	fp->f_type = DTYPE_SOCKET;
216 	fp->f_flag = FREAD|FWRITE;
217 	fp->f_ops = &socketops;
218 	fp->f_data = (caddr_t)so;
219 	nam = m_get(M_WAIT, MT_SONAME);
220 	(void) soaccept(so, nam);
221 	if (uap->name) {
222 #ifdef COMPAT_OLDSOCK
223 		if (uap->compat_43)
224 			mtod(nam, struct osockaddr *)->sa_family =
225 			    mtod(nam, struct sockaddr *)->sa_family;
226 #endif
227 		if (namelen > nam->m_len)
228 			namelen = nam->m_len;
229 		/* SHOULD COPY OUT A CHAIN HERE */
230 		error = copyout(mtod(nam, caddr_t), (caddr_t)uap->name,
231 		    (u_int)namelen);
232 		if (!error)
233 			error = copyout((caddr_t)&namelen,
234 			    (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
235 	}
236 	m_freem(nam);
237 	splx(s);
238 	return (error);
239 }
240 
241 #ifdef COMPAT_OLDSOCK
242 int
243 accept(p, uap, retval)
244 	struct proc *p;
245 	struct accept_args *uap;
246 	int *retval;
247 {
248 
249 	uap->compat_43 = 0;
250 	return (accept1(p, uap, retval));
251 }
252 
253 int
254 oaccept(p, uap, retval)
255 	struct proc *p;
256 	struct accept_args *uap;
257 	int *retval;
258 {
259 
260 	uap->compat_43 = 1;
261 	return (accept1(p, uap, retval));
262 }
263 #endif /* COMPAT_OLDSOCK */
264 
265 struct connect_args {
266 	int	s;
267 	caddr_t	name;
268 	int	namelen;
269 };
270 /* ARGSUSED */
271 int
272 connect(p, uap, retval)
273 	struct proc *p;
274 	register struct connect_args *uap;
275 	int *retval;
276 {
277 	struct file *fp;
278 	register struct socket *so;
279 	struct mbuf *nam;
280 	int error, s;
281 
282 	error = getsock(p->p_fd, uap->s, &fp);
283 	if (error)
284 		return (error);
285 	so = (struct socket *)fp->f_data;
286 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
287 		return (EALREADY);
288 	error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
289 	if (error)
290 		return (error);
291 	error = soconnect(so, nam);
292 	if (error)
293 		goto bad;
294 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
295 		m_freem(nam);
296 		return (EINPROGRESS);
297 	}
298 	s = splnet();
299 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
300 		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
301 		    netcon, 0);
302 		if (error)
303 			break;
304 	}
305 	if (error == 0) {
306 		error = so->so_error;
307 		so->so_error = 0;
308 	}
309 	splx(s);
310 bad:
311 	so->so_state &= ~SS_ISCONNECTING;
312 	m_freem(nam);
313 	if (error == ERESTART)
314 		error = EINTR;
315 	return (error);
316 }
317 
318 struct socketpair_args {
319 	int	domain;
320 	int	type;
321 	int	protocol;
322 	int	*rsv;
323 };
324 int
325 socketpair(p, uap, retval)
326 	struct proc *p;
327 	register struct socketpair_args *uap;
328 	int retval[];
329 {
330 	register 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(uap->domain, &so1, uap->type, uap->protocol);
336 	if (error)
337 		return (error);
338 	error = socreate(uap->domain, &so2, uap->type, uap->protocol);
339 	if (error)
340 		goto free1;
341 	error = falloc(p, &fp1, &fd);
342 	if (error)
343 		goto free2;
344 	sv[0] = fd;
345 	fp1->f_flag = FREAD|FWRITE;
346 	fp1->f_type = DTYPE_SOCKET;
347 	fp1->f_ops = &socketops;
348 	fp1->f_data = (caddr_t)so1;
349 	error = falloc(p, &fp2, &fd);
350 	if (error)
351 		goto free3;
352 	fp2->f_flag = FREAD|FWRITE;
353 	fp2->f_type = DTYPE_SOCKET;
354 	fp2->f_ops = &socketops;
355 	fp2->f_data = (caddr_t)so2;
356 	sv[1] = fd;
357 	error = soconnect2(so1, so2);
358 	if (error)
359 		goto free4;
360 	if (uap->type == SOCK_DGRAM) {
361 		/*
362 		 * Datagram socket connection is asymmetric.
363 		 */
364 		 error = soconnect2(so2, so1);
365 		 if (error)
366 			goto free4;
367 	}
368 	error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
369 	retval[0] = sv[0];		/* XXX ??? */
370 	retval[1] = sv[1];		/* XXX ??? */
371 	return (error);
372 free4:
373 	ffree(fp2);
374 	fdp->fd_ofiles[sv[1]] = 0;
375 free3:
376 	ffree(fp1);
377 	fdp->fd_ofiles[sv[0]] = 0;
378 free2:
379 	(void)soclose(so2);
380 free1:
381 	(void)soclose(so1);
382 	return (error);
383 }
384 
385 int
386 sendit(p, s, mp, flags, retsize)
387 	register struct proc *p;
388 	int s;
389 	register struct msghdr *mp;
390 	int flags, *retsize;
391 {
392 	struct file *fp;
393 	struct uio auio;
394 	register struct iovec *iov;
395 	register int i;
396 	struct mbuf *to, *control;
397 	int len, error;
398 #ifdef KTRACE
399 	struct iovec *ktriov = NULL;
400 #endif
401 
402 	error = getsock(p->p_fd, s, &fp);
403 	if (error)
404 		return (error);
405 	auio.uio_iov = mp->msg_iov;
406 	auio.uio_iovcnt = mp->msg_iovlen;
407 	auio.uio_segflg = UIO_USERSPACE;
408 	auio.uio_rw = UIO_WRITE;
409 	auio.uio_procp = p;
410 	auio.uio_offset = 0;			/* XXX */
411 	auio.uio_resid = 0;
412 	iov = mp->msg_iov;
413 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
414 		if ((auio.uio_resid += iov->iov_len) < 0)
415 			return (EINVAL);
416 	}
417 	if (mp->msg_name) {
418 		error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
419 		if (error)
420 			return (error);
421 	} else
422 		to = 0;
423 	if (mp->msg_control) {
424 		if (mp->msg_controllen < sizeof(struct cmsghdr)
425 #ifdef COMPAT_OLDSOCK
426 		    && mp->msg_flags != MSG_COMPAT
427 #endif
428 		) {
429 			error = EINVAL;
430 			goto bad;
431 		}
432 		error = sockargs(&control, mp->msg_control,
433 		    mp->msg_controllen, MT_CONTROL);
434 		if (error)
435 			goto bad;
436 #ifdef COMPAT_OLDSOCK
437 		if (mp->msg_flags == MSG_COMPAT) {
438 			register struct cmsghdr *cm;
439 
440 			M_PREPEND(control, sizeof(*cm), M_WAIT);
441 			if (control == 0) {
442 				error = ENOBUFS;
443 				goto bad;
444 			} else {
445 				cm = mtod(control, struct cmsghdr *);
446 				cm->cmsg_len = control->m_len;
447 				cm->cmsg_level = SOL_SOCKET;
448 				cm->cmsg_type = SCM_RIGHTS;
449 			}
450 		}
451 #endif
452 	} else
453 		control = 0;
454 #ifdef KTRACE
455 	if (KTRPOINT(p, KTR_GENIO)) {
456 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
457 
458 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
459 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
460 	}
461 #endif
462 	len = auio.uio_resid;
463 	error = sosend((struct socket *)fp->f_data, to, &auio,
464 	    (struct mbuf *)0, control, flags);
465 	if (error) {
466 		if (auio.uio_resid != len && (error == ERESTART ||
467 		    error == EINTR || error == EWOULDBLOCK))
468 			error = 0;
469 		if (error == EPIPE)
470 			psignal(p, SIGPIPE);
471 	}
472 	if (error == 0)
473 		*retsize = len - auio.uio_resid;
474 #ifdef KTRACE
475 	if (ktriov != NULL) {
476 		if (error == 0)
477 			ktrgenio(p->p_tracep, s, UIO_WRITE,
478 				ktriov, *retsize, error);
479 		FREE(ktriov, M_TEMP);
480 	}
481 #endif
482 bad:
483 	if (to)
484 		m_freem(to);
485 	return (error);
486 }
487 
488 struct sendto_args {
489 	int	s;
490 	caddr_t	buf;
491 	size_t	len;
492 	int	flags;
493 	caddr_t	to;
494 	int	tolen;
495 };
496 int
497 sendto(p, uap, retval)
498 	struct proc *p;
499 	register struct sendto_args *uap;
500 	int *retval;
501 {
502 	struct msghdr msg;
503 	struct iovec aiov;
504 
505 	msg.msg_name = uap->to;
506 	msg.msg_namelen = uap->tolen;
507 	msg.msg_iov = &aiov;
508 	msg.msg_iovlen = 1;
509 	msg.msg_control = 0;
510 #ifdef COMPAT_OLDSOCK
511 	msg.msg_flags = 0;
512 #endif
513 	aiov.iov_base = uap->buf;
514 	aiov.iov_len = uap->len;
515 	return (sendit(p, uap->s, &msg, uap->flags, retval));
516 }
517 
518 #ifdef COMPAT_OLDSOCK
519 struct osend_args {
520 	int	s;
521 	caddr_t	buf;
522 	int	len;
523 	int	flags;
524 };
525 int
526 osend(p, uap, retval)
527 	struct proc *p;
528 	register struct osend_args *uap;
529 	int *retval;
530 {
531 	struct msghdr msg;
532 	struct iovec aiov;
533 
534 	msg.msg_name = 0;
535 	msg.msg_namelen = 0;
536 	msg.msg_iov = &aiov;
537 	msg.msg_iovlen = 1;
538 	aiov.iov_base = uap->buf;
539 	aiov.iov_len = uap->len;
540 	msg.msg_control = 0;
541 	msg.msg_flags = 0;
542 	return (sendit(p, uap->s, &msg, uap->flags, retval));
543 }
544 
545 struct osendmsg_args {
546 	int	s;
547 	caddr_t	msg;
548 	int	flags;
549 };
550 int
551 osendmsg(p, uap, retval)
552 	struct proc *p;
553 	register struct osendmsg_args *uap;
554 	int *retval;
555 {
556 	struct msghdr msg;
557 	struct iovec aiov[UIO_SMALLIOV], *iov;
558 	int error;
559 
560 	error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr));
561 	if (error)
562 		return (error);
563 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
564 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
565 			return (EMSGSIZE);
566 		MALLOC(iov, struct iovec *,
567 		      sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
568 		      M_WAITOK);
569 	} else
570 		iov = aiov;
571 	error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
572 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
573 	if (error)
574 		goto done;
575 	msg.msg_flags = MSG_COMPAT;
576 	msg.msg_iov = iov;
577 	error = sendit(p, uap->s, &msg, uap->flags, retval);
578 done:
579 	if (iov != aiov)
580 		FREE(iov, M_IOV);
581 	return (error);
582 }
583 #endif
584 
585 struct sendmsg_args {
586 	int	s;
587 	caddr_t	msg;
588 	int	flags;
589 };
590 int
591 sendmsg(p, uap, retval)
592 	struct proc *p;
593 	register struct sendmsg_args *uap;
594 	int *retval;
595 {
596 	struct msghdr msg;
597 	struct iovec aiov[UIO_SMALLIOV], *iov;
598 	int error;
599 
600 	error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
601 	if (error)
602 		return (error);
603 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
604 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
605 			return (EMSGSIZE);
606 		MALLOC(iov, struct iovec *,
607 		       sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
608 		       M_WAITOK);
609 	} else
610 		iov = aiov;
611 	if (msg.msg_iovlen &&
612 	    (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
613 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
614 		goto done;
615 	msg.msg_iov = iov;
616 #ifdef COMPAT_OLDSOCK
617 	msg.msg_flags = 0;
618 #endif
619 	error = sendit(p, uap->s, &msg, uap->flags, retval);
620 done:
621 	if (iov != aiov)
622 		FREE(iov, M_IOV);
623 	return (error);
624 }
625 
626 struct recvfrom_args {
627 	int	s;
628 	caddr_t	buf;
629 	size_t	len;
630 	int	flags;
631 	caddr_t	from;
632 	int	*fromlenaddr;
633 };
634 
635 int
636 recvit(p, s, mp, namelenp, retsize)
637 	register struct proc *p;
638 	int s;
639 	register struct msghdr *mp;
640 	caddr_t namelenp;
641 	int *retsize;
642 {
643 	struct file *fp;
644 	struct uio auio;
645 	register struct iovec *iov;
646 	register int i;
647 	int len, error;
648 	struct mbuf *from = 0, *control = 0;
649 #ifdef KTRACE
650 	struct iovec *ktriov = NULL;
651 #endif
652 
653 	error = getsock(p->p_fd, s, &fp);
654 	if (error)
655 		return (error);
656 	auio.uio_iov = mp->msg_iov;
657 	auio.uio_iovcnt = mp->msg_iovlen;
658 	auio.uio_segflg = UIO_USERSPACE;
659 	auio.uio_rw = UIO_READ;
660 	auio.uio_procp = p;
661 	auio.uio_offset = 0;			/* XXX */
662 	auio.uio_resid = 0;
663 	iov = mp->msg_iov;
664 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
665 		if ((auio.uio_resid += iov->iov_len) < 0)
666 			return (EINVAL);
667 	}
668 #ifdef KTRACE
669 	if (KTRPOINT(p, KTR_GENIO)) {
670 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
671 
672 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
673 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
674 	}
675 #endif
676 	len = auio.uio_resid;
677 	error = soreceive((struct socket *)fp->f_data, &from, &auio,
678 	    (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
679 	    &mp->msg_flags);
680 	if (error) {
681 		if (auio.uio_resid != len && (error == ERESTART ||
682 		    error == EINTR || error == EWOULDBLOCK))
683 			error = 0;
684 	}
685 #ifdef KTRACE
686 	if (ktriov != NULL) {
687 		if (error == 0)
688 			ktrgenio(p->p_tracep, s, UIO_READ,
689 				ktriov, len - auio.uio_resid, error);
690 		FREE(ktriov, M_TEMP);
691 	}
692 #endif
693 	if (error)
694 		goto out;
695 	*retsize = len - auio.uio_resid;
696 	if (mp->msg_name) {
697 		len = mp->msg_namelen;
698 		if (len <= 0 || from == 0)
699 			len = 0;
700 		else {
701 #ifdef COMPAT_OLDSOCK
702 			if (mp->msg_flags & MSG_COMPAT)
703 				mtod(from, struct osockaddr *)->sa_family =
704 				    mtod(from, struct sockaddr *)->sa_family;
705 #endif
706 			if (len > from->m_len)
707 				len = from->m_len;
708 			/* else if len < from->m_len ??? */
709 			error = copyout(mtod(from, caddr_t),
710 			    (caddr_t)mp->msg_name, (unsigned)len);
711 			if (error)
712 				goto out;
713 		}
714 		mp->msg_namelen = len;
715 		if (namelenp &&
716 		    (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
717 #ifdef COMPAT_OLDSOCK
718 			if (mp->msg_flags & MSG_COMPAT)
719 				error = 0;	/* old recvfrom didn't check */
720 			else
721 #endif
722 			goto out;
723 		}
724 	}
725 	if (mp->msg_control) {
726 #ifdef COMPAT_OLDSOCK
727 		/*
728 		 * We assume that old recvmsg calls won't receive access
729 		 * rights and other control info, esp. as control info
730 		 * is always optional and those options didn't exist in 4.3.
731 		 * If we receive rights, trim the cmsghdr; anything else
732 		 * is tossed.
733 		 */
734 		if (control && mp->msg_flags & MSG_COMPAT) {
735 			if (mtod(control, struct cmsghdr *)->cmsg_level !=
736 			    SOL_SOCKET ||
737 			    mtod(control, struct cmsghdr *)->cmsg_type !=
738 			    SCM_RIGHTS) {
739 				mp->msg_controllen = 0;
740 				goto out;
741 			}
742 			control->m_len -= sizeof (struct cmsghdr);
743 			control->m_data += sizeof (struct cmsghdr);
744 		}
745 #endif
746 		len = mp->msg_controllen;
747 		if (len <= 0 || control == 0)
748 			len = 0;
749 		else {
750 			if (len >= control->m_len)
751 				len = control->m_len;
752 			else
753 				mp->msg_flags |= MSG_CTRUNC;
754 			error = copyout((caddr_t)mtod(control, caddr_t),
755 			    (caddr_t)mp->msg_control, (unsigned)len);
756 		}
757 		mp->msg_controllen = len;
758 	}
759 out:
760 	if (from)
761 		m_freem(from);
762 	if (control)
763 		m_freem(control);
764 	return (error);
765 }
766 
767 struct shutdown_args {
768 	int	s;
769 	int	how;
770 };
771 
772 int
773 recvfrom(p, uap, retval)
774 	struct proc *p;
775 	register struct recvfrom_args *uap;
776 	int *retval;
777 {
778 	struct msghdr msg;
779 	struct iovec aiov;
780 	int error;
781 
782 	if (uap->fromlenaddr) {
783 		error = copyin((caddr_t)uap->fromlenaddr,
784 		    (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen));
785 		if (error)
786 			return (error);
787 	} else
788 		msg.msg_namelen = 0;
789 	msg.msg_name = uap->from;
790 	msg.msg_iov = &aiov;
791 	msg.msg_iovlen = 1;
792 	aiov.iov_base = uap->buf;
793 	aiov.iov_len = uap->len;
794 	msg.msg_control = 0;
795 	msg.msg_flags = uap->flags;
796 	return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
797 }
798 
799 #ifdef COMPAT_OLDSOCK
800 int
801 orecvfrom(p, uap, retval)
802 	struct proc *p;
803 	struct recvfrom_args *uap;
804 	int *retval;
805 {
806 
807 	uap->flags |= MSG_COMPAT;
808 	return (recvfrom(p, uap, retval));
809 }
810 #endif
811 
812 
813 #ifdef COMPAT_OLDSOCK
814 struct orecv_args {
815 	int	s;
816 	caddr_t	buf;
817 	int	len;
818 	int	flags;
819 };
820 int
821 orecv(p, uap, retval)
822 	struct proc *p;
823 	register struct orecv_args *uap;
824 	int *retval;
825 {
826 	struct msghdr msg;
827 	struct iovec aiov;
828 
829 	msg.msg_name = 0;
830 	msg.msg_namelen = 0;
831 	msg.msg_iov = &aiov;
832 	msg.msg_iovlen = 1;
833 	aiov.iov_base = uap->buf;
834 	aiov.iov_len = uap->len;
835 	msg.msg_control = 0;
836 	msg.msg_flags = uap->flags;
837 	return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
838 }
839 
840 /*
841  * Old recvmsg.  This code takes advantage of the fact that the old msghdr
842  * overlays the new one, missing only the flags, and with the (old) access
843  * rights where the control fields are now.
844  */
845 struct orecvmsg_args {
846 	int	s;
847 	struct	omsghdr *msg;
848 	int	flags;
849 };
850 int
851 orecvmsg(p, uap, retval)
852 	struct proc *p;
853 	register struct orecvmsg_args *uap;
854 	int *retval;
855 {
856 	struct msghdr msg;
857 	struct iovec aiov[UIO_SMALLIOV], *iov;
858 	int error;
859 
860 	error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
861 	    sizeof (struct omsghdr));
862 	if (error)
863 		return (error);
864 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
865 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
866 			return (EMSGSIZE);
867 		MALLOC(iov, struct iovec *,
868 		      sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
869 		      M_WAITOK);
870 	} else
871 		iov = aiov;
872 	msg.msg_flags = uap->flags | MSG_COMPAT;
873 	error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
874 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
875 	if (error)
876 		goto done;
877 	msg.msg_iov = iov;
878 	error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
879 
880 	if (msg.msg_controllen && error == 0)
881 		error = copyout((caddr_t)&msg.msg_controllen,
882 		    (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
883 done:
884 	if (iov != aiov)
885 		FREE(iov, M_IOV);
886 	return (error);
887 }
888 #endif
889 
890 struct recvmsg_args {
891 	int	s;
892 	struct	msghdr *msg;
893 	int	flags;
894 };
895 int
896 recvmsg(p, uap, retval)
897 	struct proc *p;
898 	register struct recvmsg_args *uap;
899 	int *retval;
900 {
901 	struct msghdr msg;
902 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
903 	register int error;
904 
905 	error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
906 	if (error)
907 		return (error);
908 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
909 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
910 			return (EMSGSIZE);
911 		MALLOC(iov, struct iovec *,
912 		       sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
913 		       M_WAITOK);
914 	} else
915 		iov = aiov;
916 #ifdef COMPAT_OLDSOCK
917 	msg.msg_flags = uap->flags &~ MSG_COMPAT;
918 #else
919 	msg.msg_flags = uap->flags;
920 #endif
921 	uiov = msg.msg_iov;
922 	msg.msg_iov = iov;
923 	error = copyin((caddr_t)uiov, (caddr_t)iov,
924 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
925 	if (error)
926 		goto done;
927 	error = recvit(p, uap->s, &msg, (caddr_t)0, retval);
928 	if (!error) {
929 		msg.msg_iov = uiov;
930 		error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
931 	}
932 done:
933 	if (iov != aiov)
934 		FREE(iov, M_IOV);
935 	return (error);
936 }
937 /* ARGSUSED */
938 int
939 shutdown(p, uap, retval)
940 	struct proc *p;
941 	register struct shutdown_args *uap;
942 	int *retval;
943 {
944 	struct file *fp;
945 	int error;
946 
947 	error = getsock(p->p_fd, uap->s, &fp);
948 	if (error)
949 		return (error);
950 	return (soshutdown((struct socket *)fp->f_data, uap->how));
951 }
952 
953 struct setsockopt_args {
954 	int	s;
955 	int	level;
956 	int	name;
957 	caddr_t	val;
958 	int	valsize;
959 };
960 /* ARGSUSED */
961 int
962 setsockopt(p, uap, retval)
963 	struct proc *p;
964 	register struct setsockopt_args *uap;
965 	int *retval;
966 {
967 	struct file *fp;
968 	struct mbuf *m = NULL;
969 	int error;
970 
971 	error = getsock(p->p_fd, uap->s, &fp);
972 	if (error)
973 		return (error);
974 	if (uap->valsize > MLEN)
975 		return (EINVAL);
976 	if (uap->val) {
977 		m = m_get(M_WAIT, MT_SOOPTS);
978 		if (m == NULL)
979 			return (ENOBUFS);
980 		error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
981 		if (error) {
982 			(void) m_free(m);
983 			return (error);
984 		}
985 		m->m_len = uap->valsize;
986 	}
987 	return (sosetopt((struct socket *)fp->f_data, uap->level,
988 	    uap->name, m));
989 }
990 
991 struct getsockopt_args {
992 	int	s;
993 	int	level;
994 	int	name;
995 	caddr_t	val;
996 	int	*avalsize;
997 };
998 /* ARGSUSED */
999 int
1000 getsockopt(p, uap, retval)
1001 	struct proc *p;
1002 	register struct getsockopt_args *uap;
1003 	int *retval;
1004 {
1005 	struct file *fp;
1006 	struct mbuf *m = NULL;
1007 	int valsize, error;
1008 
1009 	error = getsock(p->p_fd, uap->s, &fp);
1010 	if (error)
1011 		return (error);
1012 	if (uap->val) {
1013 		error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
1014 		    sizeof (valsize));
1015 		if (error)
1016 			return (error);
1017 	} else
1018 		valsize = 0;
1019 	if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
1020 	    uap->name, &m)) == 0 && uap->val && valsize && m != NULL) {
1021 		if (valsize > m->m_len)
1022 			valsize = m->m_len;
1023 		error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
1024 		if (error == 0)
1025 			error = copyout((caddr_t)&valsize,
1026 			    (caddr_t)uap->avalsize, sizeof (valsize));
1027 	}
1028 	if (m != NULL)
1029 		(void) m_free(m);
1030 	return (error);
1031 }
1032 
1033 struct pipe_args {
1034 	int	dummy;
1035 };
1036 /* ARGSUSED */
1037 int
1038 pipe(p, uap, retval)
1039 	struct proc *p;
1040 	struct pipe_args *uap;
1041 	int retval[];
1042 {
1043 	register struct filedesc *fdp = p->p_fd;
1044 	struct file *rf, *wf;
1045 	struct socket *rso, *wso;
1046 	int fd, error;
1047 
1048 	error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0);
1049 	if (error)
1050 		return (error);
1051 	error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0);
1052 	if (error)
1053 		goto free1;
1054 	error = falloc(p, &rf, &fd);
1055 	if (error)
1056 		goto free2;
1057 	retval[0] = fd;
1058 	rf->f_flag = FREAD;
1059 	rf->f_type = DTYPE_SOCKET;
1060 	rf->f_ops = &socketops;
1061 	rf->f_data = (caddr_t)rso;
1062 	error = falloc(p, &wf, &fd);
1063 	if (error)
1064 		goto free3;
1065 	wf->f_flag = FWRITE;
1066 	wf->f_type = DTYPE_SOCKET;
1067 	wf->f_ops = &socketops;
1068 	wf->f_data = (caddr_t)wso;
1069 	retval[1] = fd;
1070 	error = unp_connect2(wso, rso);
1071 	if (error)
1072 		goto free4;
1073 	return (0);
1074 free4:
1075 	ffree(wf);
1076 	fdp->fd_ofiles[retval[1]] = 0;
1077 free3:
1078 	ffree(rf);
1079 	fdp->fd_ofiles[retval[0]] = 0;
1080 free2:
1081 	(void)soclose(wso);
1082 free1:
1083 	(void)soclose(rso);
1084 	return (error);
1085 }
1086 
1087 /*
1088  * Get socket name.
1089  */
1090 struct getsockname_args {
1091 	int	fdes;
1092 	caddr_t	asa;
1093 	int	*alen;
1094 #ifdef COMPAT_OLDSOCK
1095 	int	compat_43;	/* pseudo */
1096 #endif
1097 };
1098 
1099 #ifndef COMPAT_OLDSOCK
1100 #define	getsockname1	getsockname
1101 #endif
1102 
1103 /* ARGSUSED */
1104 int
1105 getsockname1(p, uap, retval)
1106 	struct proc *p;
1107 	register struct getsockname_args *uap;
1108 	int *retval;
1109 {
1110 	struct file *fp;
1111 	register struct socket *so;
1112 	struct mbuf *m;
1113 	int len, error;
1114 
1115 	error = getsock(p->p_fd, uap->fdes, &fp);
1116 	if (error)
1117 		return (error);
1118 	error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1119 	if (error)
1120 		return (error);
1121 	so = (struct socket *)fp->f_data;
1122 	m = m_getclr(M_WAIT, MT_SONAME);
1123 	if (m == NULL)
1124 		return (ENOBUFS);
1125 	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
1126 	if (error)
1127 		goto bad;
1128 	if (len > m->m_len)
1129 		len = m->m_len;
1130 #ifdef COMPAT_OLDSOCK
1131 	if (uap->compat_43)
1132 		mtod(m, struct osockaddr *)->sa_family =
1133 		    mtod(m, struct sockaddr *)->sa_family;
1134 #endif
1135 	error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1136 	if (error == 0)
1137 		error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1138 		    sizeof (len));
1139 bad:
1140 	m_freem(m);
1141 	return (error);
1142 }
1143 
1144 #ifdef COMPAT_OLDSOCK
1145 int
1146 getsockname(p, uap, retval)
1147 	struct proc *p;
1148 	struct getsockname_args *uap;
1149 	int *retval;
1150 {
1151 
1152 	uap->compat_43 = 0;
1153 	return (getsockname1(p, uap, retval));
1154 }
1155 
1156 int
1157 ogetsockname(p, uap, retval)
1158 	struct proc *p;
1159 	struct getsockname_args *uap;
1160 	int *retval;
1161 {
1162 
1163 	uap->compat_43 = 1;
1164 	return (getsockname1(p, uap, retval));
1165 }
1166 #endif /* COMPAT_OLDSOCK */
1167 
1168 /*
1169  * Get name of peer for connected socket.
1170  */
1171 struct getpeername_args {
1172 	int	fdes;
1173 	caddr_t	asa;
1174 	int	*alen;
1175 #ifdef COMPAT_OLDSOCK
1176 	int	compat_43;	/* pseudo */
1177 #endif
1178 };
1179 
1180 
1181 #ifndef COMPAT_OLDSOCK
1182 #define	getpeername1	getpeername
1183 #endif
1184 
1185 /* ARGSUSED */
1186 int
1187 getpeername1(p, uap, retval)
1188 	struct proc *p;
1189 	register struct getpeername_args *uap;
1190 	int *retval;
1191 {
1192 	struct file *fp;
1193 	register struct socket *so;
1194 	struct mbuf *m;
1195 	int len, error;
1196 
1197 	error = getsock(p->p_fd, uap->fdes, &fp);
1198 	if (error)
1199 		return (error);
1200 	so = (struct socket *)fp->f_data;
1201 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1202 		return (ENOTCONN);
1203 	error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1204 	if (error)
1205 		return (error);
1206 	m = m_getclr(M_WAIT, MT_SONAME);
1207 	if (m == NULL)
1208 		return (ENOBUFS);
1209 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
1210 	if (error)
1211 		goto bad;
1212 	if (len > m->m_len)
1213 		len = m->m_len;
1214 #ifdef COMPAT_OLDSOCK
1215 	if (uap->compat_43)
1216 		mtod(m, struct osockaddr *)->sa_family =
1217 		    mtod(m, struct sockaddr *)->sa_family;
1218 #endif
1219 	error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1220 	if (error)
1221 		goto bad;
1222 	error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1223 bad:
1224 	m_freem(m);
1225 	return (error);
1226 }
1227 
1228 #ifdef COMPAT_OLDSOCK
1229 int
1230 getpeername(p, uap, retval)
1231 	struct proc *p;
1232 	struct getpeername_args *uap;
1233 	int *retval;
1234 {
1235 
1236 	uap->compat_43 = 0;
1237 	return (getpeername1(p, uap, retval));
1238 }
1239 
1240 int
1241 ogetpeername(p, uap, retval)
1242 	struct proc *p;
1243 	struct getpeername_args *uap;
1244 	int *retval;
1245 {
1246 
1247 	uap->compat_43 = 1;
1248 	return (getpeername1(p, uap, retval));
1249 }
1250 #endif /* COMPAT_OLDSOCK */
1251 int
1252 sockargs(mp, buf, buflen, type)
1253 	struct mbuf **mp;
1254 	caddr_t buf;
1255 	int buflen, type;
1256 {
1257 	register struct sockaddr *sa;
1258 	register struct mbuf *m;
1259 	int error;
1260 
1261 	if ((u_int)buflen > MLEN) {
1262 #ifdef COMPAT_OLDSOCK
1263 		if (type == MT_SONAME && (u_int)buflen <= 112)
1264 			buflen = MLEN;		/* unix domain compat. hack */
1265 		else
1266 #endif
1267 		return (EINVAL);
1268 	}
1269 	m = m_get(M_WAIT, type);
1270 	if (m == NULL)
1271 		return (ENOBUFS);
1272 	m->m_len = buflen;
1273 	error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1274 	if (error)
1275 		(void) m_free(m);
1276 	else {
1277 		*mp = m;
1278 		if (type == MT_SONAME) {
1279 			sa = mtod(m, struct sockaddr *);
1280 
1281 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1282 			if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1283 				sa->sa_family = sa->sa_len;
1284 #endif
1285 			sa->sa_len = buflen;
1286 		}
1287 	}
1288 	return (error);
1289 }
1290 
1291 int
1292 getsock(fdp, fdes, fpp)
1293 	struct filedesc *fdp;
1294 	int fdes;
1295 	struct file **fpp;
1296 {
1297 	register struct file *fp;
1298 
1299 	if ((unsigned)fdes >= fdp->fd_nfiles ||
1300 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
1301 		return (EBADF);
1302 	if (fp->f_type != DTYPE_SOCKET)
1303 		return (ENOTSOCK);
1304 	*fpp = fp;
1305 	return (0);
1306 }
1307