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