1 /*	$OpenBSD: uipc_syscalls.c,v 1.61 2005/07/06 20:41:44 krw Exp $	*/
2 /*	$NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/filedesc.h>
38 #include <sys/proc.h>
39 #include <sys/file.h>
40 #include <sys/buf.h>
41 #include <sys/malloc.h>
42 #include <sys/event.h>
43 #include <sys/mbuf.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/signalvar.h>
48 #include <sys/unpcb.h>
49 #include <sys/un.h>
50 #ifdef KTRACE
51 #include <sys/ktrace.h>
52 #endif
53 
54 #include <sys/mount.h>
55 #include <sys/syscallargs.h>
56 
57 /*
58  * System call interface to the socket abstraction.
59  */
60 extern	struct fileops socketops;
61 
62 int
sys_socket(p,v,retval)63 sys_socket(p, v, retval)
64 	struct proc *p;
65 	void *v;
66 	register_t *retval;
67 {
68 	register struct sys_socket_args /* {
69 		syscallarg(int) domain;
70 		syscallarg(int) type;
71 		syscallarg(int) protocol;
72 	} */ *uap = v;
73 	struct filedesc *fdp = p->p_fd;
74 	struct socket *so;
75 	struct file *fp;
76 	int fd, error;
77 
78 	fdplock(fdp, p);
79 
80 	if ((error = falloc(p, &fp, &fd)) != 0)
81 		goto out;
82 	fp->f_flag = FREAD|FWRITE;
83 	fp->f_type = DTYPE_SOCKET;
84 	fp->f_ops = &socketops;
85 	error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
86 			 SCARG(uap, protocol));
87 	if (error) {
88 		fdremove(fdp, fd);
89 		closef(fp, p);
90 	} else {
91 		fp->f_data = so;
92 		FILE_SET_MATURE(fp);
93 		*retval = fd;
94 	}
95 out:
96 	fdpunlock(fdp);
97 	return (error);
98 }
99 
100 /* ARGSUSED */
101 int
sys_bind(p,v,retval)102 sys_bind(p, v, retval)
103 	struct proc *p;
104 	void *v;
105 	register_t *retval;
106 {
107 	register struct sys_bind_args /* {
108 		syscallarg(int) s;
109 		syscallarg(const struct sockaddr *) name;
110 		syscallarg(socklen_t) namelen;
111 	} */ *uap = v;
112 	struct file *fp;
113 	struct mbuf *nam;
114 	int error;
115 
116 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
117 		return (error);
118 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
119 			 MT_SONAME);
120 	if (error == 0) {
121 		error = sobind((struct socket *)fp->f_data, nam);
122 		m_freem(nam);
123 	}
124 	FRELE(fp);
125 	return (error);
126 }
127 
128 /* ARGSUSED */
129 int
sys_listen(p,v,retval)130 sys_listen(p, v, retval)
131 	struct proc *p;
132 	void *v;
133 	register_t *retval;
134 {
135 	register struct sys_listen_args /* {
136 		syscallarg(int) s;
137 		syscallarg(int) backlog;
138 	} */ *uap = v;
139 	struct file *fp;
140 	int error;
141 
142 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
143 		return (error);
144 	error = solisten((struct socket *)fp->f_data, SCARG(uap, backlog));
145 	FRELE(fp);
146 	return (error);
147 }
148 
149 int
sys_accept(p,v,retval)150 sys_accept(p, v, retval)
151 	struct proc *p;
152 	void *v;
153 	register_t *retval;
154 {
155 	struct sys_accept_args /* {
156 		syscallarg(int) s;
157 		syscallarg(struct sockaddr *) name;
158 		syscallarg(socklen_t *) anamelen;
159 	} */ *uap = v;
160 	struct file *fp, *headfp;
161 	struct mbuf *nam;
162 	socklen_t namelen;
163 	int error, s, tmpfd;
164 	struct socket *head, *so;
165 	int nflag;
166 
167 	if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen),
168 	    &namelen, sizeof (namelen))))
169 		return (error);
170 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
171 		return (error);
172 	headfp = fp;
173 	s = splsoftnet();
174 	head = (struct socket *)fp->f_data;
175 	if ((head->so_options & SO_ACCEPTCONN) == 0) {
176 		error = EINVAL;
177 		goto bad;
178 	}
179 	if ((head->so_state & SS_NBIO) && head->so_qlen == 0) {
180 		error = EWOULDBLOCK;
181 		goto bad;
182 	}
183 	while (head->so_qlen == 0 && head->so_error == 0) {
184 		if (head->so_state & SS_CANTRCVMORE) {
185 			head->so_error = ECONNABORTED;
186 			break;
187 		}
188 		error = tsleep(&head->so_timeo, PSOCK | PCATCH, netcon, 0);
189 		if (error) {
190 			goto bad;
191 		}
192 	}
193 	if (head->so_error) {
194 		error = head->so_error;
195 		head->so_error = 0;
196 		goto bad;
197 	}
198 
199 	/*
200 	 * At this point we know that there is at least one connection
201 	 * ready to be accepted. Remove it from the queue prior to
202 	 * allocating the file descriptor for it since falloc() may
203 	 * block allowing another process to accept the connection
204 	 * instead.
205 	 */
206 	so = TAILQ_FIRST(&head->so_q);
207 	if (soqremque(so, 1) == 0)
208 		panic("accept");
209 
210 	/* Take note if socket was non-blocking. */
211 	nflag = (fp->f_flag & FNONBLOCK);
212 
213 	fdplock(p->p_fd, p);
214 	if ((error = falloc(p, &fp, &tmpfd)) != 0) {
215 		/*
216 		 * Probably ran out of file descriptors. Put the
217 		 * unaccepted connection back onto the queue and
218 		 * do another wakeup so some other process might
219 		 * have a chance at it.
220 		 */
221 		so->so_head = head;
222 		head->so_qlen++;
223 		so->so_onq = &head->so_q;
224 		TAILQ_INSERT_HEAD(so->so_onq, so, so_qe);
225 		wakeup_one(&head->so_timeo);
226 		goto bad;
227 	}
228 	*retval = tmpfd;
229 
230 	/* connection has been removed from the listen queue */
231 	KNOTE(&head->so_rcv.sb_sel.si_note, 0);
232 
233 	fp->f_type = DTYPE_SOCKET;
234 	fp->f_flag = FREAD | FWRITE | nflag;
235 	fp->f_ops = &socketops;
236 	fp->f_data = so;
237 	nam = m_get(M_WAIT, MT_SONAME);
238 	error = soaccept(so, nam);
239 	if (!error && SCARG(uap, name)) {
240 		if (namelen > nam->m_len)
241 			namelen = nam->m_len;
242 		/* SHOULD COPY OUT A CHAIN HERE */
243 		if ((error = copyout(mtod(nam, caddr_t),
244 		    SCARG(uap, name), namelen)) == 0)
245 			error = copyout(&namelen, SCARG(uap, anamelen),
246 			    sizeof (*SCARG(uap, anamelen)));
247 	}
248 	/* if an error occurred, free the file descriptor */
249 	if (error) {
250 		fdremove(p->p_fd, tmpfd);
251 		closef(fp, p);
252 	} else {
253 		FILE_SET_MATURE(fp);
254 	}
255 	m_freem(nam);
256 bad:
257 	fdpunlock(p->p_fd);
258 	splx(s);
259 	FRELE(headfp);
260 	return (error);
261 }
262 
263 /* ARGSUSED */
264 int
sys_connect(p,v,retval)265 sys_connect(p, v, retval)
266 	struct proc *p;
267 	void *v;
268 	register_t *retval;
269 {
270 	struct sys_connect_args /* {
271 		syscallarg(int) s;
272 		syscallarg(const struct sockaddr *) name;
273 		syscallarg(socklen_t) namelen;
274 	} */ *uap = v;
275 	struct file *fp;
276 	struct socket *so;
277 	struct mbuf *nam = NULL;
278 	int error, s;
279 
280 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
281 		return (error);
282 	so = (struct socket *)fp->f_data;
283 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
284 		FRELE(fp);
285 		return (EALREADY);
286 	}
287 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
288 			 MT_SONAME);
289 	if (error)
290 		goto bad;
291 	error = soconnect(so, nam);
292 	if (error)
293 		goto bad;
294 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
295 		FRELE(fp);
296 		m_freem(nam);
297 		return (EINPROGRESS);
298 	}
299 	s = splsoftnet();
300 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
301 		error = tsleep(&so->so_timeo, PSOCK | PCATCH,
302 		    netcon, 0);
303 		if (error)
304 			break;
305 	}
306 	if (error == 0) {
307 		error = so->so_error;
308 		so->so_error = 0;
309 	}
310 	splx(s);
311 bad:
312 	so->so_state &= ~SS_ISCONNECTING;
313 	FRELE(fp);
314 	if (nam)
315 		m_freem(nam);
316 	if (error == ERESTART)
317 		error = EINTR;
318 	return (error);
319 }
320 
321 int
sys_socketpair(p,v,retval)322 sys_socketpair(p, v, retval)
323 	struct proc *p;
324 	void *v;
325 	register_t *retval;
326 {
327 	register struct sys_socketpair_args /* {
328 		syscallarg(int) domain;
329 		syscallarg(int) type;
330 		syscallarg(int) protocol;
331 		syscallarg(int *) rsv;
332 	} */ *uap = v;
333 	register struct filedesc *fdp = p->p_fd;
334 	struct file *fp1, *fp2;
335 	struct socket *so1, *so2;
336 	int fd, error, sv[2];
337 
338 	error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
339 			 SCARG(uap, protocol));
340 	if (error)
341 		return (error);
342 	error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
343 			 SCARG(uap, protocol));
344 	if (error)
345 		goto free1;
346 
347 	fdplock(fdp, p);
348 	if ((error = falloc(p, &fp1, &fd)) != 0)
349 		goto free2;
350 	sv[0] = fd;
351 	fp1->f_flag = FREAD|FWRITE;
352 	fp1->f_type = DTYPE_SOCKET;
353 	fp1->f_ops = &socketops;
354 	fp1->f_data = so1;
355 	if ((error = falloc(p, &fp2, &fd)) != 0)
356 		goto free3;
357 	fp2->f_flag = FREAD|FWRITE;
358 	fp2->f_type = DTYPE_SOCKET;
359 	fp2->f_ops = &socketops;
360 	fp2->f_data = so2;
361 	sv[1] = fd;
362 	if ((error = soconnect2(so1, so2)) != 0)
363 		goto free4;
364 	if (SCARG(uap, type) == SOCK_DGRAM) {
365 		/*
366 		 * Datagram socket connection is asymmetric.
367 		 */
368 		 if ((error = soconnect2(so2, so1)) != 0)
369 			goto free4;
370 	}
371 	error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
372 	if (error == 0) {
373 		FILE_SET_MATURE(fp1);
374 		FILE_SET_MATURE(fp2);
375 		fdpunlock(fdp);
376 		return (0);
377 	}
378 free4:
379 	fdremove(fdp, sv[1]);
380 	closef(fp2, p);
381 	so2 = NULL;
382 free3:
383 	fdremove(fdp, sv[0]);
384 	closef(fp1, p);
385 	so1 = NULL;
386 free2:
387 	if (so2 != NULL)
388 		(void)soclose(so2);
389 	fdpunlock(fdp);
390 free1:
391 	if (so1 != NULL)
392 		(void)soclose(so1);
393 	return (error);
394 }
395 
396 int
sys_sendto(p,v,retval)397 sys_sendto(p, v, retval)
398 	struct proc *p;
399 	void *v;
400 	register_t *retval;
401 {
402 	register struct sys_sendto_args /* {
403 		syscallarg(int) s;
404 		syscallarg(const void *) buf;
405 		syscallarg(size_t) len;
406 		syscallarg(int) flags;
407 		syscallarg(const struct sockaddr *) to;
408 		syscallarg(socklen_t) tolen;
409 	} */ *uap = v;
410 	struct msghdr msg;
411 	struct iovec aiov;
412 
413 	msg.msg_name = (caddr_t)SCARG(uap, to);
414 	msg.msg_namelen = SCARG(uap, tolen);
415 	msg.msg_iov = &aiov;
416 	msg.msg_iovlen = 1;
417 	msg.msg_control = 0;
418 #ifdef COMPAT_OLDSOCK
419 	msg.msg_flags = 0;
420 #endif
421 	aiov.iov_base = (char *)SCARG(uap, buf);
422 	aiov.iov_len = SCARG(uap, len);
423 	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
424 }
425 
426 int
sys_sendmsg(p,v,retval)427 sys_sendmsg(p, v, retval)
428 	struct proc *p;
429 	void *v;
430 	register_t *retval;
431 {
432 	register struct sys_sendmsg_args /* {
433 		syscallarg(int) s;
434 		syscallarg(const struct msghdr *) msg;
435 		syscallarg(int) flags;
436 	} */ *uap = v;
437 	struct msghdr msg;
438 	struct iovec aiov[UIO_SMALLIOV], *iov;
439 	int error;
440 
441 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
442 	if (error)
443 		return (error);
444 	if (msg.msg_iovlen > IOV_MAX)
445 		return (EMSGSIZE);
446 	if (msg.msg_iovlen > UIO_SMALLIOV)
447 		iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
448 		    M_IOV, M_WAITOK);
449 	else
450 		iov = aiov;
451 	if (msg.msg_iovlen &&
452 	    (error = copyin(msg.msg_iov, iov,
453 		    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
454 		goto done;
455 	msg.msg_iov = iov;
456 #ifdef COMPAT_OLDSOCK
457 	msg.msg_flags = 0;
458 #endif
459 	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
460 done:
461 	if (iov != aiov)
462 		free(iov, M_IOV);
463 	return (error);
464 }
465 
466 int
sendit(p,s,mp,flags,retsize)467 sendit(p, s, mp, flags, retsize)
468 	struct proc *p;
469 	int s;
470 	struct msghdr *mp;
471 	int flags;
472 	register_t *retsize;
473 {
474 	struct file *fp;
475 	struct uio auio;
476 	struct iovec *iov;
477 	int i;
478 	struct mbuf *to, *control;
479 	int len, error;
480 #ifdef KTRACE
481 	struct iovec *ktriov = NULL;
482 #endif
483 
484 	to = NULL;
485 
486 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
487 		return (error);
488 	auio.uio_iov = mp->msg_iov;
489 	auio.uio_iovcnt = mp->msg_iovlen;
490 	auio.uio_segflg = UIO_USERSPACE;
491 	auio.uio_rw = UIO_WRITE;
492 	auio.uio_procp = p;
493 	auio.uio_offset = 0;			/* XXX */
494 	auio.uio_resid = 0;
495 	iov = mp->msg_iov;
496 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
497 		/* Don't allow sum > SSIZE_MAX */
498 		if (iov->iov_len > SSIZE_MAX ||
499 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
500 			error = EINVAL;
501 			goto bad;
502 		}
503 	}
504 	if (mp->msg_name) {
505 		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
506 				 MT_SONAME);
507 		if (error)
508 			goto bad;
509 	}
510 	if (mp->msg_control) {
511 		if (mp->msg_controllen < sizeof(struct cmsghdr)
512 #ifdef COMPAT_OLDSOCK
513 		    && mp->msg_flags != MSG_COMPAT
514 #endif
515 		) {
516 			error = EINVAL;
517 			goto bad;
518 		}
519 		error = sockargs(&control, mp->msg_control,
520 				 mp->msg_controllen, MT_CONTROL);
521 		if (error)
522 			goto bad;
523 #ifdef COMPAT_OLDSOCK
524 		if (mp->msg_flags == MSG_COMPAT) {
525 			register struct cmsghdr *cm;
526 
527 			M_PREPEND(control, sizeof(*cm), M_WAIT);
528 			cm = mtod(control, struct cmsghdr *);
529 			cm->cmsg_len = control->m_len;
530 			cm->cmsg_level = SOL_SOCKET;
531 			cm->cmsg_type = SCM_RIGHTS;
532 		}
533 #endif
534 	} else
535 		control = 0;
536 #ifdef KTRACE
537 	if (KTRPOINT(p, KTR_GENIO)) {
538 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
539 
540 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
541 		bcopy(auio.uio_iov, ktriov, iovlen);
542 	}
543 #endif
544 	len = auio.uio_resid;
545 	error = sosend((struct socket *)fp->f_data, to, &auio,
546 	    NULL, control, flags);
547 	if (error) {
548 		if (auio.uio_resid != len && (error == ERESTART ||
549 		    error == EINTR || error == EWOULDBLOCK))
550 			error = 0;
551 		if (error == EPIPE)
552 			psignal(p, SIGPIPE);
553 	}
554 	if (error == 0)
555 		*retsize = len - auio.uio_resid;
556 #ifdef KTRACE
557 	if (ktriov != NULL) {
558 		if (error == 0)
559 			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
560 		free(ktriov, M_TEMP);
561 	}
562 #endif
563 bad:
564 	FRELE(fp);
565 	if (to)
566 		m_freem(to);
567 	return (error);
568 }
569 
570 int
sys_recvfrom(p,v,retval)571 sys_recvfrom(p, v, retval)
572 	struct proc *p;
573 	void *v;
574 	register_t *retval;
575 {
576 	register struct sys_recvfrom_args /* {
577 		syscallarg(int) s;
578 		syscallarg(void *) buf;
579 		syscallarg(size_t) len;
580 		syscallarg(int) flags;
581 		syscallarg(struct sockaddr *) from;
582 		syscallarg(socklen_t *) fromlenaddr;
583 	} */ *uap = v;
584 	struct msghdr msg;
585 	struct iovec aiov;
586 	int error;
587 
588 	if (SCARG(uap, fromlenaddr)) {
589 		error = copyin(SCARG(uap, fromlenaddr),
590 		    &msg.msg_namelen, sizeof (msg.msg_namelen));
591 		if (error)
592 			return (error);
593 	} else
594 		msg.msg_namelen = 0;
595 	msg.msg_name = (caddr_t)SCARG(uap, from);
596 	msg.msg_iov = &aiov;
597 	msg.msg_iovlen = 1;
598 	aiov.iov_base = SCARG(uap, buf);
599 	aiov.iov_len = SCARG(uap, len);
600 	msg.msg_control = 0;
601 	msg.msg_flags = SCARG(uap, flags);
602 	return (recvit(p, SCARG(uap, s), &msg,
603 	    (caddr_t)SCARG(uap, fromlenaddr), retval));
604 }
605 
606 int
sys_recvmsg(p,v,retval)607 sys_recvmsg(p, v, retval)
608 	struct proc *p;
609 	void *v;
610 	register_t *retval;
611 {
612 	register struct sys_recvmsg_args /* {
613 		syscallarg(int) s;
614 		syscallarg(struct msghdr *) msg;
615 		syscallarg(int) flags;
616 	} */ *uap = v;
617 	struct msghdr msg;
618 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
619 	int error;
620 
621 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
622 	if (error)
623 		return (error);
624 	if (msg.msg_iovlen > IOV_MAX)
625 		return (EMSGSIZE);
626 	if (msg.msg_iovlen > UIO_SMALLIOV)
627 		iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
628 		    M_IOV, M_WAITOK);
629 	else
630 		iov = aiov;
631 #ifdef COMPAT_OLDSOCK
632 	msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
633 #else
634 	msg.msg_flags = SCARG(uap, flags);
635 #endif
636 	if (msg.msg_iovlen > 0) {
637 		error = copyin(msg.msg_iov, iov,
638 		    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
639 		if (error)
640 			goto done;
641 	}
642 	uiov = msg.msg_iov;
643 	msg.msg_iov = iov;
644 	if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
645 		msg.msg_iov = uiov;
646 		error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
647 	}
648 done:
649 	if (iov != aiov)
650 		free(iov, M_IOV);
651 	return (error);
652 }
653 
654 int
recvit(p,s,mp,namelenp,retsize)655 recvit(p, s, mp, namelenp, retsize)
656 	struct proc *p;
657 	int s;
658 	struct msghdr *mp;
659 	caddr_t namelenp;
660 	register_t *retsize;
661 {
662 	struct file *fp;
663 	struct uio auio;
664 	register struct iovec *iov;
665 	register int i;
666 	size_t len;
667 	int error;
668 	struct mbuf *from = NULL, *control = NULL;
669 #ifdef KTRACE
670 	struct iovec *ktriov = NULL;
671 #endif
672 
673 	if ((error = getsock(p->p_fd, s, &fp)) != 0)
674 		return (error);
675 	auio.uio_iov = mp->msg_iov;
676 	auio.uio_iovcnt = mp->msg_iovlen;
677 	auio.uio_segflg = UIO_USERSPACE;
678 	auio.uio_rw = UIO_READ;
679 	auio.uio_procp = p;
680 	auio.uio_offset = 0;			/* XXX */
681 	auio.uio_resid = 0;
682 	iov = mp->msg_iov;
683 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
684 		/* Don't allow sum > SSIZE_MAX */
685 		if (iov->iov_len > SSIZE_MAX ||
686 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
687 			error = EINVAL;
688 			goto out;
689 		}
690 	}
691 #ifdef KTRACE
692 	if (KTRPOINT(p, KTR_GENIO)) {
693 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
694 
695 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
696 		bcopy(auio.uio_iov, ktriov, iovlen);
697 	}
698 #endif
699 	len = auio.uio_resid;
700 	error = soreceive((struct socket *)fp->f_data, &from, &auio,
701 			  NULL, mp->msg_control ? &control : NULL,
702 			  &mp->msg_flags);
703 	if (error) {
704 		if (auio.uio_resid != len && (error == ERESTART ||
705 		    error == EINTR || error == EWOULDBLOCK))
706 			error = 0;
707 	}
708 #ifdef KTRACE
709 	if (ktriov != NULL) {
710 		if (error == 0)
711 			ktrgenio(p, s, UIO_READ,
712 				ktriov, len - auio.uio_resid, error);
713 		free(ktriov, M_TEMP);
714 	}
715 #endif
716 	if (error)
717 		goto out;
718 	*retsize = len - auio.uio_resid;
719 	if (mp->msg_name) {
720 		socklen_t alen;
721 
722 		if (from == NULL)
723 			alen = 0;
724 		else {
725 			/* save sa_len before it is destroyed by MSG_COMPAT */
726 			alen = mp->msg_namelen;
727 			if (alen > from->m_len)
728 				alen = from->m_len;
729 			/* else if alen < from->m_len ??? */
730 #ifdef COMPAT_OLDSOCK
731 			if (mp->msg_flags & MSG_COMPAT)
732 				mtod(from, struct osockaddr *)->sa_family =
733 				    mtod(from, struct sockaddr *)->sa_family;
734 #endif
735 			error = copyout(mtod(from, caddr_t),
736 			    mp->msg_name, alen);
737 			if (error)
738 				goto out;
739 		}
740 		mp->msg_namelen = alen;
741 		if (namelenp &&
742 		    (error = copyout(&alen, namelenp, sizeof(alen)))) {
743 #ifdef COMPAT_OLDSOCK
744 			if (mp->msg_flags & MSG_COMPAT)
745 				error = 0;	/* old recvfrom didn't check */
746 			else
747 #endif
748 			goto out;
749 		}
750 	}
751 	if (mp->msg_control) {
752 #ifdef COMPAT_OLDSOCK
753 		/*
754 		 * We assume that old recvmsg calls won't receive access
755 		 * rights and other control info, esp. as control info
756 		 * is always optional and those options didn't exist in 4.3.
757 		 * If we receive rights, trim the cmsghdr; anything else
758 		 * is tossed.
759 		 */
760 		if (control && mp->msg_flags & MSG_COMPAT) {
761 			if (mtod(control, struct cmsghdr *)->cmsg_level !=
762 			    SOL_SOCKET ||
763 			    mtod(control, struct cmsghdr *)->cmsg_type !=
764 			    SCM_RIGHTS) {
765 				mp->msg_controllen = 0;
766 				goto out;
767 			}
768 			control->m_len -= sizeof (struct cmsghdr);
769 			control->m_data += sizeof (struct cmsghdr);
770 		}
771 #endif
772 		len = mp->msg_controllen;
773 		if (len <= 0 || control == NULL)
774 			len = 0;
775 		else {
776 			struct mbuf *m = control;
777 			caddr_t p = (caddr_t)mp->msg_control;
778 
779 			do {
780 				i = m->m_len;
781 				if (len < i) {
782 					mp->msg_flags |= MSG_CTRUNC;
783 					i = len;
784 				}
785 				error = copyout(mtod(m, caddr_t), p,
786 				    (unsigned)i);
787 				if (m->m_next)
788 					i = ALIGN(i);
789 				p += i;
790 				len -= i;
791 				if (error != 0 || len <= 0)
792 					break;
793 			} while ((m = m->m_next) != NULL);
794 			len = p - (caddr_t)mp->msg_control;
795 		}
796 		mp->msg_controllen = len;
797 	}
798 out:
799 	FRELE(fp);
800 	if (from)
801 		m_freem(from);
802 	if (control)
803 		m_freem(control);
804 	return (error);
805 }
806 
807 /* ARGSUSED */
808 int
sys_shutdown(p,v,retval)809 sys_shutdown(p, v, retval)
810 	struct proc *p;
811 	void *v;
812 	register_t *retval;
813 {
814 	struct sys_shutdown_args /* {
815 		syscallarg(int) s;
816 		syscallarg(int) how;
817 	} */ *uap = v;
818 	struct file *fp;
819 	int error;
820 
821 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
822 		return (error);
823 	error = soshutdown((struct socket *)fp->f_data, SCARG(uap, how));
824 	FRELE(fp);
825 	return (error);
826 }
827 
828 /* ARGSUSED */
829 int
sys_setsockopt(p,v,retval)830 sys_setsockopt(p, v, retval)
831 	struct proc *p;
832 	void *v;
833 	register_t *retval;
834 {
835 	struct sys_setsockopt_args /* {
836 		syscallarg(int) s;
837 		syscallarg(int) level;
838 		syscallarg(int) name;
839 		syscallarg(const void *) val;
840 		syscallarg(socklen_t) valsize;
841 	} */ *uap = v;
842 	struct file *fp;
843 	struct mbuf *m = NULL;
844 	int error;
845 
846 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
847 		return (error);
848 	if (SCARG(uap, valsize) > MCLBYTES) {
849 		error = EINVAL;
850 		goto bad;
851 	}
852 	if (SCARG(uap, val)) {
853 		m = m_get(M_WAIT, MT_SOOPTS);
854 		if (SCARG(uap, valsize) > MLEN) {
855 			MCLGET(m, M_DONTWAIT);
856 			if ((m->m_flags & M_EXT) == 0) {
857 				error = ENOBUFS;
858 				goto bad;
859 			}
860 		}
861 		if (m == NULL) {
862 			error = ENOBUFS;
863 			goto bad;
864 		}
865 		error = copyin(SCARG(uap, val), mtod(m, caddr_t),
866 		    SCARG(uap, valsize));
867 		if (error) {
868 			goto bad;
869 		}
870 		m->m_len = SCARG(uap, valsize);
871 	}
872 	error = sosetopt((struct socket *)fp->f_data, SCARG(uap, level),
873 			 SCARG(uap, name), m);
874 	m = NULL;
875 bad:
876 	if (m)
877 		m_freem(m);
878 	FRELE(fp);
879 	return (error);
880 }
881 
882 /* ARGSUSED */
883 int
sys_getsockopt(p,v,retval)884 sys_getsockopt(p, v, retval)
885 	struct proc *p;
886 	void *v;
887 	register_t *retval;
888 {
889 	struct sys_getsockopt_args /* {
890 		syscallarg(int) s;
891 		syscallarg(int) level;
892 		syscallarg(int) name;
893 		syscallarg(void *) val;
894 		syscallarg(socklen_t *) avalsize;
895 	} */ *uap = v;
896 	struct file *fp;
897 	struct mbuf *m = NULL;
898 	socklen_t valsize;
899 	int error;
900 
901 	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
902 		return (error);
903 	if (SCARG(uap, val)) {
904 		error = copyin((caddr_t)SCARG(uap, avalsize),
905 		    (caddr_t)&valsize, sizeof (valsize));
906 		if (error)
907 			goto out;
908 	} else
909 		valsize = 0;
910 	if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level),
911 	    SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
912 	    m != NULL) {
913 		if (valsize > m->m_len)
914 			valsize = m->m_len;
915 		error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
916 		if (error == 0)
917 			error = copyout((caddr_t)&valsize,
918 			    (caddr_t)SCARG(uap, avalsize), sizeof (valsize));
919 	}
920 out:
921 	FRELE(fp);
922 	if (m != NULL)
923 		(void) m_free(m);
924 	return (error);
925 }
926 
927 int
sys_pipe(struct proc * p,void * v,register_t * retval)928 sys_pipe(struct proc *p, void *v, register_t *retval)
929 {
930 	register struct sys_pipe_args /* {
931 		syscallarg(int *) fdp;
932 	} */ *uap = v;
933 	int error, fds[2];
934 	register_t rval[2];
935 
936 	if ((error = sys_opipe(p, v, rval)) != 0)
937 		return (error);
938 
939 	fds[0] = rval[0];
940 	fds[1] = rval[1];
941 	error = copyout((caddr_t)fds, (caddr_t)SCARG(uap, fdp),
942 	    2 * sizeof (int));
943 	if (error) {
944 		fdplock(p->p_fd, p);
945 		fdrelease(p, fds[0]);
946 		fdrelease(p, fds[1]);
947 		fdpunlock(p->p_fd);
948 	}
949 	return (error);
950 }
951 
952 /*
953  * Get socket name.
954  */
955 /* ARGSUSED */
956 int
sys_getsockname(p,v,retval)957 sys_getsockname(p, v, retval)
958 	struct proc *p;
959 	void *v;
960 	register_t *retval;
961 {
962 	struct sys_getsockname_args /* {
963 		syscallarg(int) fdes;
964 		syscallarg(struct sockaddr *) asa;
965 		syscallarg(socklen_t *) alen;
966 	} */ *uap = v;
967 	struct file *fp;
968 	struct socket *so;
969 	struct mbuf *m = NULL;
970 	socklen_t len;
971 	int error;
972 
973 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
974 		return (error);
975 	error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len));
976 	if (error)
977 		goto bad;
978 	so = (struct socket *)fp->f_data;
979 	m = m_getclr(M_WAIT, MT_SONAME);
980 	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
981 	if (error)
982 		goto bad;
983 	if (len > m->m_len)
984 		len = m->m_len;
985 	error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len);
986 	if (error == 0)
987 		error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
988 		    sizeof (len));
989 bad:
990 	FRELE(fp);
991 	if (m)
992 		m_freem(m);
993 	return (error);
994 }
995 
996 /*
997  * Get name of peer for connected socket.
998  */
999 /* ARGSUSED */
1000 int
sys_getpeername(p,v,retval)1001 sys_getpeername(p, v, retval)
1002 	struct proc *p;
1003 	void *v;
1004 	register_t *retval;
1005 {
1006 	struct sys_getpeername_args /* {
1007 		syscallarg(int) fdes;
1008 		syscallarg(struct sockaddr *) asa;
1009 		syscallarg(socklen_t *) alen;
1010 	} */ *uap = v;
1011 	struct file *fp;
1012 	register struct socket *so;
1013 	struct mbuf *m = NULL;
1014 	socklen_t len;
1015 	int error;
1016 
1017 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1018 		return (error);
1019 	so = (struct socket *)fp->f_data;
1020 	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
1021 		FRELE(fp);
1022 		return (ENOTCONN);
1023 	}
1024 	error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len));
1025 	if (error)
1026 		goto bad;
1027 	m = m_getclr(M_WAIT, MT_SONAME);
1028 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
1029 	if (error)
1030 		goto bad;
1031 	if (len > m->m_len)
1032 		len = m->m_len;
1033 	error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), len);
1034 	if (error == 0)
1035 		error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
1036 		    sizeof (len));
1037 bad:
1038 	FRELE(fp);
1039 	m_freem(m);
1040 	return (error);
1041 }
1042 
1043 /*
1044  * Get eid of peer for connected socket.
1045  */
1046 /* ARGSUSED */
1047 int
sys_getpeereid(p,v,retval)1048 sys_getpeereid(p, v, retval)
1049 	struct proc *p;
1050 	void *v;
1051 	register_t *retval;
1052 {
1053 	struct sys_getpeereid_args /* {
1054 		syscallarg(int) fdes;
1055 		syscallarg(uid_t *) euid;
1056 		syscallarg(gid_t *) egid;
1057 	} */ *uap = v;
1058 	struct file *fp;
1059 	struct socket *so;
1060 	struct mbuf *m = NULL;
1061 	struct unpcbid *id;
1062 	int error;
1063 
1064 	if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1065 		return (error);
1066 	so = (struct socket *)fp->f_data;
1067 	if (so->so_proto != pffindtype(AF_LOCAL, SOCK_STREAM)) {
1068 		FRELE(fp);
1069 		return (EOPNOTSUPP);
1070 	}
1071 	m = m_getclr(M_WAIT, MT_SONAME);
1072 	if (m == NULL) {
1073 		error = ENOBUFS;
1074 		goto bad;
1075 	}
1076 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEEREID, 0, m, 0);
1077 	if (!error && m->m_len != sizeof(struct unpcbid))
1078 		error = EOPNOTSUPP;
1079 	if (error)
1080 		goto bad;
1081 	id = mtod(m, struct unpcbid *);
1082 	error = copyout((caddr_t)&(id->unp_euid),
1083 		(caddr_t)SCARG(uap, euid), sizeof(uid_t));
1084 	if (error == 0)
1085 		error = copyout((caddr_t)&(id->unp_egid),
1086 		    (caddr_t)SCARG(uap, egid), sizeof(gid_t));
1087 bad:
1088 	FRELE(fp);
1089 	m_freem(m);
1090 	return (error);
1091 }
1092 
1093 int
sockargs(struct mbuf ** mp,const void * buf,size_t buflen,int type)1094 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1095 {
1096 	struct sockaddr *sa;
1097 	struct mbuf *m;
1098 	int error;
1099 
1100 	/*
1101 	 * We can't allow socket names > UCHAR_MAX in length, since that
1102 	 * will overflow sa_len. Also, control data more than MCLBYTES in
1103 	 * length is just too much.
1104 	 */
1105 	if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES))
1106 		return (EINVAL);
1107 
1108 	/* Allocate an mbuf to hold the arguments. */
1109 	m = m_get(M_WAIT, type);
1110 	if ((u_int)buflen > MLEN) {
1111 		MCLGET(m, M_WAITOK);
1112 		if ((m->m_flags & M_EXT) == 0) {
1113 			m_free(m);
1114 			return ENOBUFS;
1115 		}
1116 	}
1117 	m->m_len = buflen;
1118 	error = copyin(buf, mtod(m, caddr_t), buflen);
1119 	if (error) {
1120 		(void) m_free(m);
1121 		return (error);
1122 	}
1123 	*mp = m;
1124 	if (type == MT_SONAME) {
1125 		sa = mtod(m, struct sockaddr *);
1126 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1127 		if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1128 			sa->sa_family = sa->sa_len;
1129 #endif
1130 		sa->sa_len = buflen;
1131 	}
1132 	return (0);
1133 }
1134 
1135 int
getsock(struct filedesc * fdp,int fdes,struct file ** fpp)1136 getsock(struct filedesc *fdp, int fdes, struct file **fpp)
1137 {
1138 	struct file *fp;
1139 
1140 	if ((fp = fd_getfile(fdp, fdes)) == NULL)
1141 		return (EBADF);
1142 	if (fp->f_type != DTYPE_SOCKET)
1143 		return (ENOTSOCK);
1144 	*fpp = fp;
1145 	FREF(fp);
1146 
1147 	return (0);
1148 }
1149