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