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