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