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