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