xref: /original-bsd/sys/kern/uipc_syscalls.c (revision deff14a8)
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.5 (Berkeley) 07/07/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 	size_t	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 (auio.uio_resid + iov->iov_len < auio.uio_resid)
483 			return (EINVAL);
484 		auio.uio_resid += iov->iov_len;
485 	}
486 	if (mp->msg_name) {
487 		if (error = sockargs(&to, mp->msg_name, mp->msg_namelen,
488 		    MT_SONAME))
489 			return (error);
490 	} else
491 		to = 0;
492 	if (mp->msg_control) {
493 		if (mp->msg_controllen < sizeof(struct cmsghdr)
494 #ifdef COMPAT_OLDSOCK
495 		    && mp->msg_flags != MSG_COMPAT
496 #endif
497 		) {
498 			error = EINVAL;
499 			goto bad;
500 		}
501 		if (error = sockargs(&control, mp->msg_control,
502 		    mp->msg_controllen, MT_CONTROL))
503 			goto bad;
504 #ifdef COMPAT_OLDSOCK
505 		if (mp->msg_flags == MSG_COMPAT) {
506 			register struct cmsghdr *cm;
507 
508 			M_PREPEND(control, sizeof(*cm), M_WAIT);
509 			if (control == 0) {
510 				error = ENOBUFS;
511 				goto bad;
512 			} else {
513 				cm = mtod(control, struct cmsghdr *);
514 				cm->cmsg_len = control->m_len;
515 				cm->cmsg_level = SOL_SOCKET;
516 				cm->cmsg_type = SCM_RIGHTS;
517 			}
518 		}
519 #endif
520 	} else
521 		control = 0;
522 #ifdef KTRACE
523 	if (KTRPOINT(p, KTR_GENIO)) {
524 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
525 
526 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
527 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
528 	}
529 #endif
530 	len = auio.uio_resid;
531 	if (error = sosend((struct socket *)fp->f_data, to, &auio,
532 	    (struct mbuf *)0, control, flags)) {
533 		if (auio.uio_resid != len && (error == ERESTART ||
534 		    error == EINTR || error == EWOULDBLOCK))
535 			error = 0;
536 		if (error == EPIPE)
537 			psignal(p, SIGPIPE);
538 	}
539 	if (error == 0)
540 		*retsize = len - auio.uio_resid;
541 #ifdef KTRACE
542 	if (ktriov != NULL) {
543 		if (error == 0)
544 			ktrgenio(p->p_tracep, s, UIO_WRITE,
545 				ktriov, *retsize, error);
546 		FREE(ktriov, M_TEMP);
547 	}
548 #endif
549 bad:
550 	if (to)
551 		m_freem(to);
552 	return (error);
553 }
554 
555 struct recvfrom_args {
556 	int	s;
557 	caddr_t	buf;
558 	size_t	len;
559 	int	flags;
560 	caddr_t	from;
561 	int	*fromlenaddr;
562 };
563 
564 #ifdef COMPAT_OLDSOCK
565 orecvfrom(p, uap, retval)
566 	struct proc *p;
567 	struct recvfrom_args *uap;
568 	int *retval;
569 {
570 
571 	uap->flags |= MSG_COMPAT;
572 	return (recvfrom(p, uap, retval));
573 }
574 #endif
575 
576 recvfrom(p, uap, retval)
577 	struct proc *p;
578 	register struct recvfrom_args *uap;
579 	int *retval;
580 {
581 	struct msghdr msg;
582 	struct iovec aiov;
583 	int error;
584 
585 	if (uap->fromlenaddr) {
586 		if (error = copyin((caddr_t)uap->fromlenaddr,
587 		    (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen)))
588 			return (error);
589 	} else
590 		msg.msg_namelen = 0;
591 	msg.msg_name = uap->from;
592 	msg.msg_iov = &aiov;
593 	msg.msg_iovlen = 1;
594 	aiov.iov_base = uap->buf;
595 	aiov.iov_len = uap->len;
596 	msg.msg_control = 0;
597 	msg.msg_flags = uap->flags;
598 	return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
599 }
600 
601 #ifdef COMPAT_OLDSOCK
602 struct orecv_args {
603 	int	s;
604 	caddr_t	buf;
605 	int	len;
606 	int	flags;
607 };
608 orecv(p, uap, retval)
609 	struct proc *p;
610 	register struct orecv_args *uap;
611 	int *retval;
612 {
613 	struct msghdr msg;
614 	struct iovec aiov;
615 
616 	msg.msg_name = 0;
617 	msg.msg_namelen = 0;
618 	msg.msg_iov = &aiov;
619 	msg.msg_iovlen = 1;
620 	aiov.iov_base = uap->buf;
621 	aiov.iov_len = uap->len;
622 	msg.msg_control = 0;
623 	msg.msg_flags = uap->flags;
624 	return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
625 }
626 
627 /*
628  * Old recvmsg.  This code takes advantage of the fact that the old msghdr
629  * overlays the new one, missing only the flags, and with the (old) access
630  * rights where the control fields are now.
631  */
632 struct orecvmsg_args {
633 	int	s;
634 	struct	omsghdr *msg;
635 	int	flags;
636 };
637 orecvmsg(p, uap, retval)
638 	struct proc *p;
639 	register struct orecvmsg_args *uap;
640 	int *retval;
641 {
642 	struct msghdr msg;
643 	struct iovec aiov[UIO_SMALLIOV], *iov;
644 	int error;
645 
646 	if (error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
647 	    sizeof (struct omsghdr)))
648 		return (error);
649 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
650 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
651 			return (EMSGSIZE);
652 		MALLOC(iov, struct iovec *,
653 		      sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
654 		      M_WAITOK);
655 	} else
656 		iov = aiov;
657 	msg.msg_flags = uap->flags | MSG_COMPAT;
658 	if (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
659 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
660 		goto done;
661 	msg.msg_iov = iov;
662 	error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
663 
664 	if (msg.msg_controllen && error == 0)
665 		error = copyout((caddr_t)&msg.msg_controllen,
666 		    (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
667 done:
668 	if (iov != aiov)
669 		FREE(iov, M_IOV);
670 	return (error);
671 }
672 #endif
673 
674 struct recvmsg_args {
675 	int	s;
676 	struct	msghdr *msg;
677 	int	flags;
678 };
679 recvmsg(p, uap, retval)
680 	struct proc *p;
681 	register struct recvmsg_args *uap;
682 	int *retval;
683 {
684 	struct msghdr msg;
685 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
686 	register int error;
687 
688 	if (error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)))
689 		return (error);
690 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
691 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
692 			return (EMSGSIZE);
693 		MALLOC(iov, struct iovec *,
694 		       sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
695 		       M_WAITOK);
696 	} else
697 		iov = aiov;
698 #ifdef COMPAT_OLDSOCK
699 	msg.msg_flags = uap->flags &~ MSG_COMPAT;
700 #else
701 	msg.msg_flags = uap->flags;
702 #endif
703 	uiov = msg.msg_iov;
704 	msg.msg_iov = iov;
705 	if (error = copyin((caddr_t)uiov, (caddr_t)iov,
706 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
707 		goto done;
708 	if ((error = recvit(p, uap->s, &msg, (caddr_t)0, retval)) == 0) {
709 		msg.msg_iov = uiov;
710 		error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
711 	}
712 done:
713 	if (iov != aiov)
714 		FREE(iov, M_IOV);
715 	return (error);
716 }
717 
718 recvit(p, s, mp, namelenp, retsize)
719 	register struct proc *p;
720 	int s;
721 	register struct msghdr *mp;
722 	caddr_t namelenp;
723 	int *retsize;
724 {
725 	struct file *fp;
726 	struct uio auio;
727 	register struct iovec *iov;
728 	register int i;
729 	int len, error;
730 	struct mbuf *from = 0, *control = 0;
731 #ifdef KTRACE
732 	struct iovec *ktriov = NULL;
733 #endif
734 
735 	if (error = getsock(p->p_fd, s, &fp))
736 		return (error);
737 	auio.uio_iov = mp->msg_iov;
738 	auio.uio_iovcnt = mp->msg_iovlen;
739 	auio.uio_segflg = UIO_USERSPACE;
740 	auio.uio_rw = UIO_READ;
741 	auio.uio_procp = p;
742 	auio.uio_offset = 0;			/* XXX */
743 	auio.uio_resid = 0;
744 	iov = mp->msg_iov;
745 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
746 		if (auio.uio_resid + iov->iov_len < auio.uio_resid)
747 			return (EINVAL);
748 		auio.uio_resid += iov->iov_len;
749 	}
750 #ifdef KTRACE
751 	if (KTRPOINT(p, KTR_GENIO)) {
752 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
753 
754 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
755 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
756 	}
757 #endif
758 	len = auio.uio_resid;
759 	if (error = soreceive((struct socket *)fp->f_data, &from, &auio,
760 	    (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
761 	    &mp->msg_flags)) {
762 		if (auio.uio_resid != len && (error == ERESTART ||
763 		    error == EINTR || error == EWOULDBLOCK))
764 			error = 0;
765 	}
766 #ifdef KTRACE
767 	if (ktriov != NULL) {
768 		if (error == 0)
769 			ktrgenio(p->p_tracep, s, UIO_READ,
770 				ktriov, len - auio.uio_resid, error);
771 		FREE(ktriov, M_TEMP);
772 	}
773 #endif
774 	if (error)
775 		goto out;
776 	*retsize = len - auio.uio_resid;
777 	if (mp->msg_name) {
778 		len = mp->msg_namelen;
779 		if (len <= 0 || from == 0)
780 			len = 0;
781 		else {
782 #ifdef COMPAT_OLDSOCK
783 			if (mp->msg_flags & MSG_COMPAT)
784 				mtod(from, struct osockaddr *)->sa_family =
785 				    mtod(from, struct sockaddr *)->sa_family;
786 #endif
787 			if (len > from->m_len)
788 				len = from->m_len;
789 			/* else if len < from->m_len ??? */
790 			if (error = copyout(mtod(from, caddr_t),
791 			    (caddr_t)mp->msg_name, (unsigned)len))
792 				goto out;
793 		}
794 		mp->msg_namelen = len;
795 		if (namelenp &&
796 		    (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
797 #ifdef COMPAT_OLDSOCK
798 			if (mp->msg_flags & MSG_COMPAT)
799 				error = 0;	/* old recvfrom didn't check */
800 			else
801 #endif
802 			goto out;
803 		}
804 	}
805 	if (mp->msg_control) {
806 #ifdef COMPAT_OLDSOCK
807 		/*
808 		 * We assume that old recvmsg calls won't receive access
809 		 * rights and other control info, esp. as control info
810 		 * is always optional and those options didn't exist in 4.3.
811 		 * If we receive rights, trim the cmsghdr; anything else
812 		 * is tossed.
813 		 */
814 		if (control && mp->msg_flags & MSG_COMPAT) {
815 			if (mtod(control, struct cmsghdr *)->cmsg_level !=
816 			    SOL_SOCKET ||
817 			    mtod(control, struct cmsghdr *)->cmsg_type !=
818 			    SCM_RIGHTS) {
819 				mp->msg_controllen = 0;
820 				goto out;
821 			}
822 			control->m_len -= sizeof (struct cmsghdr);
823 			control->m_data += sizeof (struct cmsghdr);
824 		}
825 #endif
826 		len = mp->msg_controllen;
827 		if (len <= 0 || control == 0)
828 			len = 0;
829 		else {
830 			if (len >= control->m_len)
831 				len = control->m_len;
832 			else
833 				mp->msg_flags |= MSG_CTRUNC;
834 			error = copyout((caddr_t)mtod(control, caddr_t),
835 			    (caddr_t)mp->msg_control, (unsigned)len);
836 		}
837 		mp->msg_controllen = len;
838 	}
839 out:
840 	if (from)
841 		m_freem(from);
842 	if (control)
843 		m_freem(control);
844 	return (error);
845 }
846 
847 struct shutdown_args {
848 	int	s;
849 	int	how;
850 };
851 /* ARGSUSED */
852 shutdown(p, uap, retval)
853 	struct proc *p;
854 	register struct shutdown_args *uap;
855 	int *retval;
856 {
857 	struct file *fp;
858 	int error;
859 
860 	if (error = getsock(p->p_fd, uap->s, &fp))
861 		return (error);
862 	return (soshutdown((struct socket *)fp->f_data, uap->how));
863 }
864 
865 struct setsockopt_args {
866 	int	s;
867 	int	level;
868 	int	name;
869 	caddr_t	val;
870 	int	valsize;
871 };
872 /* ARGSUSED */
873 setsockopt(p, uap, retval)
874 	struct proc *p;
875 	register struct setsockopt_args *uap;
876 	int *retval;
877 {
878 	struct file *fp;
879 	struct mbuf *m = NULL;
880 	int error;
881 
882 	if (error = getsock(p->p_fd, uap->s, &fp))
883 		return (error);
884 	if (uap->valsize > MLEN)
885 		return (EINVAL);
886 	if (uap->val) {
887 		m = m_get(M_WAIT, MT_SOOPTS);
888 		if (m == NULL)
889 			return (ENOBUFS);
890 		if (error = copyin(uap->val, mtod(m, caddr_t),
891 		    (u_int)uap->valsize)) {
892 			(void) m_free(m);
893 			return (error);
894 		}
895 		m->m_len = uap->valsize;
896 	}
897 	return (sosetopt((struct socket *)fp->f_data, uap->level,
898 	    uap->name, m));
899 }
900 
901 struct getsockopt_args {
902 	int	s;
903 	int	level;
904 	int	name;
905 	caddr_t	val;
906 	int	*avalsize;
907 };
908 /* ARGSUSED */
909 getsockopt(p, uap, retval)
910 	struct proc *p;
911 	register struct getsockopt_args *uap;
912 	int *retval;
913 {
914 	struct file *fp;
915 	struct mbuf *m = NULL;
916 	int valsize, error;
917 
918 	if (error = getsock(p->p_fd, uap->s, &fp))
919 		return (error);
920 	if (uap->val) {
921 		if (error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
922 		    sizeof (valsize)))
923 			return (error);
924 	} else
925 		valsize = 0;
926 	if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
927 	    uap->name, &m)) == 0 && uap->val && valsize && m != NULL) {
928 		if (valsize > m->m_len)
929 			valsize = m->m_len;
930 		error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
931 		if (error == 0)
932 			error = copyout((caddr_t)&valsize,
933 			    (caddr_t)uap->avalsize, sizeof (valsize));
934 	}
935 	if (m != NULL)
936 		(void) m_free(m);
937 	return (error);
938 }
939 
940 struct pipe_args {
941 	int	dummy;
942 };
943 /* ARGSUSED */
944 pipe(p, uap, retval)
945 	struct proc *p;
946 	struct pipe_args *uap;
947 	int retval[];
948 {
949 	register struct filedesc *fdp = p->p_fd;
950 	struct file *rf, *wf;
951 	struct socket *rso, *wso;
952 	int fd, error;
953 
954 	if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0))
955 		return (error);
956 	if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0))
957 		goto free1;
958 	if (error = falloc(p, &rf, &fd))
959 		goto free2;
960 	retval[0] = fd;
961 	rf->f_flag = FREAD;
962 	rf->f_type = DTYPE_SOCKET;
963 	rf->f_ops = &socketops;
964 	rf->f_data = (caddr_t)rso;
965 	if (error = falloc(p, &wf, &fd))
966 		goto free3;
967 	wf->f_flag = FWRITE;
968 	wf->f_type = DTYPE_SOCKET;
969 	wf->f_ops = &socketops;
970 	wf->f_data = (caddr_t)wso;
971 	retval[1] = fd;
972 	if (error = unp_connect2(wso, rso))
973 		goto free4;
974 	return (0);
975 free4:
976 	ffree(wf);
977 	fdp->fd_ofiles[retval[1]] = 0;
978 free3:
979 	ffree(rf);
980 	fdp->fd_ofiles[retval[0]] = 0;
981 free2:
982 	(void)soclose(wso);
983 free1:
984 	(void)soclose(rso);
985 	return (error);
986 }
987 
988 /*
989  * Get socket name.
990  */
991 struct getsockname_args {
992 	int	fdes;
993 	caddr_t	asa;
994 	int	*alen;
995 #ifdef COMPAT_OLDSOCK
996 	int	compat_43;	/* pseudo */
997 #endif
998 };
999 #ifdef COMPAT_OLDSOCK
1000 getsockname(p, uap, retval)
1001 	struct proc *p;
1002 	struct getsockname_args *uap;
1003 	int *retval;
1004 {
1005 
1006 	uap->compat_43 = 0;
1007 	return (getsockname1(p, uap, retval));
1008 }
1009 
1010 ogetsockname(p, uap, retval)
1011 	struct proc *p;
1012 	struct getsockname_args *uap;
1013 	int *retval;
1014 {
1015 
1016 	uap->compat_43 = 1;
1017 	return (getsockname1(p, uap, retval));
1018 }
1019 #else /* COMPAT_OLDSOCK */
1020 
1021 #define	getsockname1	getsockname
1022 #endif
1023 
1024 /* ARGSUSED */
1025 getsockname1(p, uap, retval)
1026 	struct proc *p;
1027 	register struct getsockname_args *uap;
1028 	int *retval;
1029 {
1030 	struct file *fp;
1031 	register struct socket *so;
1032 	struct mbuf *m;
1033 	int len, error;
1034 
1035 	if (error = getsock(p->p_fd, uap->fdes, &fp))
1036 		return (error);
1037 	if (error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)))
1038 		return (error);
1039 	so = (struct socket *)fp->f_data;
1040 	m = m_getclr(M_WAIT, MT_SONAME);
1041 	if (m == NULL)
1042 		return (ENOBUFS);
1043 	if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0))
1044 		goto bad;
1045 	if (len > m->m_len)
1046 		len = m->m_len;
1047 #ifdef COMPAT_OLDSOCK
1048 	if (uap->compat_43)
1049 		mtod(m, struct osockaddr *)->sa_family =
1050 		    mtod(m, struct sockaddr *)->sa_family;
1051 #endif
1052 	error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1053 	if (error == 0)
1054 		error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1055 		    sizeof (len));
1056 bad:
1057 	m_freem(m);
1058 	return (error);
1059 }
1060 
1061 /*
1062  * Get name of peer for connected socket.
1063  */
1064 struct getpeername_args {
1065 	int	fdes;
1066 	caddr_t	asa;
1067 	int	*alen;
1068 #ifdef COMPAT_OLDSOCK
1069 	int	compat_43;	/* pseudo */
1070 #endif
1071 };
1072 
1073 #ifdef COMPAT_OLDSOCK
1074 getpeername(p, uap, retval)
1075 	struct proc *p;
1076 	struct getpeername_args *uap;
1077 	int *retval;
1078 {
1079 
1080 	uap->compat_43 = 0;
1081 	return (getpeername1(p, uap, retval));
1082 }
1083 
1084 ogetpeername(p, uap, retval)
1085 	struct proc *p;
1086 	struct getpeername_args *uap;
1087 	int *retval;
1088 {
1089 
1090 	uap->compat_43 = 1;
1091 	return (getpeername1(p, uap, retval));
1092 }
1093 #else /* COMPAT_OLDSOCK */
1094 
1095 #define	getpeername1	getpeername
1096 #endif
1097 
1098 /* ARGSUSED */
1099 getpeername1(p, uap, retval)
1100 	struct proc *p;
1101 	register struct getpeername_args *uap;
1102 	int *retval;
1103 {
1104 	struct file *fp;
1105 	register struct socket *so;
1106 	struct mbuf *m;
1107 	int len, error;
1108 
1109 	if (error = getsock(p->p_fd, uap->fdes, &fp))
1110 		return (error);
1111 	so = (struct socket *)fp->f_data;
1112 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1113 		return (ENOTCONN);
1114 	if (error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)))
1115 		return (error);
1116 	m = m_getclr(M_WAIT, MT_SONAME);
1117 	if (m == NULL)
1118 		return (ENOBUFS);
1119 	if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0))
1120 		goto bad;
1121 	if (len > m->m_len)
1122 		len = m->m_len;
1123 #ifdef COMPAT_OLDSOCK
1124 	if (uap->compat_43)
1125 		mtod(m, struct osockaddr *)->sa_family =
1126 		    mtod(m, struct sockaddr *)->sa_family;
1127 #endif
1128 	if (error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len))
1129 		goto bad;
1130 	error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1131 bad:
1132 	m_freem(m);
1133 	return (error);
1134 }
1135 
1136 sockargs(mp, buf, buflen, type)
1137 	struct mbuf **mp;
1138 	caddr_t buf;
1139 	int buflen, type;
1140 {
1141 	register struct sockaddr *sa;
1142 	register struct mbuf *m;
1143 	int error;
1144 
1145 	if ((u_int)buflen > MLEN) {
1146 #ifdef COMPAT_OLDSOCK
1147 		if (type == MT_SONAME && (u_int)buflen <= 112)
1148 			buflen = MLEN;		/* unix domain compat. hack */
1149 		else
1150 #endif
1151 		return (EINVAL);
1152 	}
1153 	m = m_get(M_WAIT, type);
1154 	if (m == NULL)
1155 		return (ENOBUFS);
1156 	m->m_len = buflen;
1157 	error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1158 	if (error)
1159 		(void) m_free(m);
1160 	else {
1161 		*mp = m;
1162 		if (type == MT_SONAME) {
1163 			sa = mtod(m, struct sockaddr *);
1164 
1165 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1166 			if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1167 				sa->sa_family = sa->sa_len;
1168 #endif
1169 			sa->sa_len = buflen;
1170 		}
1171 	}
1172 	return (error);
1173 }
1174 
1175 getsock(fdp, fdes, fpp)
1176 	struct filedesc *fdp;
1177 	int fdes;
1178 	struct file **fpp;
1179 {
1180 	register struct file *fp;
1181 
1182 	if ((unsigned)fdes >= fdp->fd_nfiles ||
1183 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
1184 		return (EBADF);
1185 	if (fp->f_type != DTYPE_SOCKET)
1186 		return (ENOTSOCK);
1187 	*fpp = fp;
1188 	return (0);
1189 }
1190