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