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