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