xref: /netbsd-src/sys/compat/netbsd32/netbsd32_socket.c (revision 3daa70af17ad7a67b7babd8df4dd08e95df8444b)
1*3daa70afSsimonb /*	$NetBSD: netbsd32_socket.c,v 1.56 2021/01/19 03:41:22 simonb Exp $	*/
2da9e4bd3Smrg 
3da9e4bd3Smrg /*
4da9e4bd3Smrg  * Copyright (c) 1998, 2001 Matthew R. Green
5da9e4bd3Smrg  * All rights reserved.
6da9e4bd3Smrg  *
7da9e4bd3Smrg  * Redistribution and use in source and binary forms, with or without
8da9e4bd3Smrg  * modification, are permitted provided that the following conditions
9da9e4bd3Smrg  * are met:
10da9e4bd3Smrg  * 1. Redistributions of source code must retain the above copyright
11da9e4bd3Smrg  *    notice, this list of conditions and the following disclaimer.
12da9e4bd3Smrg  * 2. Redistributions in binary form must reproduce the above copyright
13da9e4bd3Smrg  *    notice, this list of conditions and the following disclaimer in the
14da9e4bd3Smrg  *    documentation and/or other materials provided with the distribution.
15da9e4bd3Smrg  *
16da9e4bd3Smrg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17da9e4bd3Smrg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18da9e4bd3Smrg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19da9e4bd3Smrg  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20da9e4bd3Smrg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21da9e4bd3Smrg  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22da9e4bd3Smrg  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23da9e4bd3Smrg  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24da9e4bd3Smrg  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25da9e4bd3Smrg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26da9e4bd3Smrg  * SUCH DAMAGE.
27da9e4bd3Smrg  */
28da9e4bd3Smrg 
29dab6ef8bSlukem #include <sys/cdefs.h>
30*3daa70afSsimonb __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.56 2021/01/19 03:41:22 simonb Exp $");
31da9e4bd3Smrg 
32da9e4bd3Smrg #include <sys/param.h>
33da9e4bd3Smrg #include <sys/systm.h>
34da9e4bd3Smrg #define msg __msg /* Don't ask me! */
35da9e4bd3Smrg #include <sys/mount.h>
36da9e4bd3Smrg #include <sys/socket.h>
37da9e4bd3Smrg #include <sys/sockio.h>
38da9e4bd3Smrg #include <sys/socketvar.h>
39da9e4bd3Smrg #include <sys/mbuf.h>
40da9e4bd3Smrg #include <sys/ktrace.h>
41da9e4bd3Smrg #include <sys/file.h>
42da9e4bd3Smrg #include <sys/filedesc.h>
43da9e4bd3Smrg #include <sys/syscallargs.h>
44da9e4bd3Smrg #include <sys/proc.h>
45b041fac9Schristos #include <sys/dirent.h>
46da9e4bd3Smrg 
47da9e4bd3Smrg #include <compat/netbsd32/netbsd32.h>
48da9e4bd3Smrg #include <compat/netbsd32/netbsd32_syscallargs.h>
49da9e4bd3Smrg #include <compat/netbsd32/netbsd32_conv.h>
50da9e4bd3Smrg 
51d00df284Srmind /*
52e8bec33bSjoerg  * XXX Assumes that struct sockaddr is compatible.
53d00df284Srmind  */
54e8bec33bSjoerg 
55e8bec33bSjoerg #define	CMSG32_ALIGN(n)	(((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
56331cb3c9Schristos #define CMSG32_ASIZE	CMSG32_ALIGN(sizeof(struct cmsghdr))
57331cb3c9Schristos #define	CMSG32_DATA(cmsg) (__CASTV(u_char *, cmsg) + CMSG32_ASIZE)
58331cb3c9Schristos #define CMSG32_MSGNEXT(ucmsg, kcmsg) \
59331cb3c9Schristos     (__CASTV(char *, kcmsg) + CMSG32_ALIGN((ucmsg)->cmsg_len))
60331cb3c9Schristos #define CMSG32_MSGEND(mhdr) \
61331cb3c9Schristos     (__CASTV(char *, (mhdr)->msg_control) + (mhdr)->msg_controllen)
62e8bec33bSjoerg 
63331cb3c9Schristos #define	CMSG32_NXTHDR(mhdr, ucmsg, kcmsg)	\
64331cb3c9Schristos     __CASTV(struct cmsghdr *,  \
65331cb3c9Schristos 	CMSG32_MSGNEXT(ucmsg, kcmsg) + \
66331cb3c9Schristos 	CMSG32_ASIZE > CMSG32_MSGEND(mhdr) ? 0 : \
67331cb3c9Schristos 	CMSG32_MSGNEXT(ucmsg, kcmsg))
68e8bec33bSjoerg #define	CMSG32_FIRSTHDR(mhdr) \
69331cb3c9Schristos     __CASTV(struct cmsghdr *, \
70331cb3c9Schristos 	(mhdr)->msg_controllen < sizeof(struct cmsghdr) ? 0 : \
71331cb3c9Schristos 	(mhdr)->msg_control)
72e8bec33bSjoerg 
73e8bec33bSjoerg #define CMSG32_SPACE(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
74e8bec33bSjoerg #define CMSG32_LEN(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
75e8bec33bSjoerg 
76e8bec33bSjoerg static int
copyout32_msg_control_mbuf(struct lwp * l,struct msghdr * mp,u_int * len,struct mbuf * m,char ** q,bool * truncated)7731383432Schristos copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, u_int *len,
78331cb3c9Schristos     struct mbuf *m, char **q, bool *truncated)
79e8bec33bSjoerg {
80e8bec33bSjoerg 	struct cmsghdr *cmsg, cmsg32;
8131383432Schristos 	size_t i, j;
8231383432Schristos 	int error;
83e8bec33bSjoerg 
84e8bec33bSjoerg 	*truncated = false;
85e8bec33bSjoerg 	cmsg = mtod(m, struct cmsghdr *);
86e8bec33bSjoerg 	do {
87e8bec33bSjoerg 		if ((char *)cmsg == mtod(m, char *) + m->m_len)
88e8bec33bSjoerg 			break;
89e8bec33bSjoerg 		if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
90e8bec33bSjoerg 			return EINVAL;
91e8bec33bSjoerg 		cmsg32 = *cmsg;
92e8bec33bSjoerg 		j = cmsg->cmsg_len - CMSG_LEN(0);
93e8bec33bSjoerg 		i = cmsg32.cmsg_len = CMSG32_LEN(j);
94e8bec33bSjoerg 		if (i > *len) {
95e8bec33bSjoerg 			mp->msg_flags |= MSG_CTRUNC;
96e8bec33bSjoerg 			if (cmsg->cmsg_level == SOL_SOCKET
97e8bec33bSjoerg 			    && cmsg->cmsg_type == SCM_RIGHTS) {
98e8bec33bSjoerg 				*truncated = true;
99e8bec33bSjoerg 				return 0;
100e8bec33bSjoerg 			}
101e8bec33bSjoerg 			j -= i - *len;
102e8bec33bSjoerg 			i = *len;
103e8bec33bSjoerg 		}
104e8bec33bSjoerg 
105331cb3c9Schristos 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
10652b3c203Smaxv 		error = copyout(&cmsg32, *q, MIN(i, sizeof(cmsg32)));
107e8bec33bSjoerg 		if (error)
108650cb29cSsimonb 			return error;
109e8bec33bSjoerg 		if (i > CMSG32_LEN(0)) {
110331cb3c9Schristos 			error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0),
111331cb3c9Schristos 			    i - CMSG32_LEN(0));
112e8bec33bSjoerg 			if (error)
113650cb29cSsimonb 				return error;
114e8bec33bSjoerg 		}
115e8bec33bSjoerg 		j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
116e8bec33bSjoerg 		if (*len >= j) {
117e8bec33bSjoerg 			*len -= j;
118e8bec33bSjoerg 			*q += j;
119e8bec33bSjoerg 		} else {
120e8bec33bSjoerg 			*q += i;
121e8bec33bSjoerg 			*len = 0;
122e8bec33bSjoerg 		}
123e8bec33bSjoerg 		cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
124e8bec33bSjoerg 	} while (*len > 0);
125e8bec33bSjoerg 
126e8bec33bSjoerg 	return 0;
127e8bec33bSjoerg }
128e8bec33bSjoerg 
129e8bec33bSjoerg static int
copyout32_msg_control(struct lwp * l,struct msghdr * mp,struct mbuf * control)130e8bec33bSjoerg copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
131e8bec33bSjoerg {
132e8bec33bSjoerg 	int len, error = 0;
133e8bec33bSjoerg 	struct mbuf *m;
134e8bec33bSjoerg 	char *q;
135e8bec33bSjoerg 	bool truncated;
136e8bec33bSjoerg 
137e8bec33bSjoerg 	len = mp->msg_controllen;
138e8bec33bSjoerg 	if (len <= 0 || control == 0) {
139e8bec33bSjoerg 		mp->msg_controllen = 0;
140e8bec33bSjoerg 		free_control_mbuf(l, control, control);
141e8bec33bSjoerg 		return 0;
142e8bec33bSjoerg 	}
143e8bec33bSjoerg 
144e8bec33bSjoerg 	q = (char *)mp->msg_control;
145e8bec33bSjoerg 
146130ede3aSmatt 	for (m = control; len > 0 && m != NULL; m = m->m_next) {
147331cb3c9Schristos 		error = copyout32_msg_control_mbuf(l, mp, &len, m, &q,
148331cb3c9Schristos 		    &truncated);
149e8bec33bSjoerg 		if (truncated) {
150e8bec33bSjoerg 			m = control;
151e8bec33bSjoerg 			break;
152e8bec33bSjoerg 		}
153e8bec33bSjoerg 		if (error)
154e8bec33bSjoerg 			break;
155e8bec33bSjoerg 	}
156e8bec33bSjoerg 
157e8bec33bSjoerg 	free_control_mbuf(l, control, m);
158e8bec33bSjoerg 
159e8bec33bSjoerg 	mp->msg_controllen = q - (char *)mp->msg_control;
160e8bec33bSjoerg 	return error;
161e8bec33bSjoerg }
162e8bec33bSjoerg 
163255beb6cSchristos static int
msg_recv_copyin(struct lwp * l,const struct netbsd32_msghdr * msg32,struct msghdr * msg,struct iovec * aiov)164255beb6cSchristos msg_recv_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
165255beb6cSchristos     struct msghdr *msg, struct iovec *aiov)
166255beb6cSchristos {
167255beb6cSchristos 	int error;
168255beb6cSchristos 	size_t iovsz;
169255beb6cSchristos 	struct iovec *iov = aiov;
170255beb6cSchristos 
171255beb6cSchristos 	iovsz = msg32->msg_iovlen * sizeof(struct iovec);
172255beb6cSchristos 	if (msg32->msg_iovlen > UIO_SMALLIOV) {
173255beb6cSchristos 		if (msg32->msg_iovlen > IOV_MAX)
174255beb6cSchristos 			return EMSGSIZE;
175255beb6cSchristos 		iov = kmem_alloc(iovsz, KM_SLEEP);
176255beb6cSchristos 	}
177255beb6cSchristos 
178255beb6cSchristos 	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32->msg_iov), iov,
179255beb6cSchristos 	    msg32->msg_iovlen);
180255beb6cSchristos 	if (error)
181255beb6cSchristos 		goto out;
182255beb6cSchristos 
183255beb6cSchristos 	netbsd32_to_msghdr(msg32, msg);
184255beb6cSchristos 	msg->msg_iov = iov;
185255beb6cSchristos out:
186255beb6cSchristos 	if (iov != aiov)
187255beb6cSchristos 		kmem_free(iov, iovsz);
188255beb6cSchristos 	return error;
189255beb6cSchristos }
190255beb6cSchristos 
191255beb6cSchristos static int
msg_recv_copyout(struct lwp * l,struct netbsd32_msghdr * msg32,struct msghdr * msg,struct netbsd32_msghdr * arg,struct mbuf * from,struct mbuf * control)192255beb6cSchristos msg_recv_copyout(struct lwp *l, struct netbsd32_msghdr *msg32,
193255beb6cSchristos     struct msghdr *msg, struct netbsd32_msghdr *arg,
194255beb6cSchristos     struct mbuf *from, struct mbuf *control)
195255beb6cSchristos {
196255beb6cSchristos 	int error = 0;
197255beb6cSchristos 
198255beb6cSchristos 	if (msg->msg_control != NULL)
199255beb6cSchristos 		error = copyout32_msg_control(l, msg, control);
200255beb6cSchristos 
201255beb6cSchristos 	if (error == 0)
202255beb6cSchristos 		error = copyout_sockname(msg->msg_name, &msg->msg_namelen, 0,
203255beb6cSchristos 			from);
204255beb6cSchristos 
205255beb6cSchristos 	if (from != NULL)
206255beb6cSchristos 		m_free(from);
207255beb6cSchristos 	if (error)
208255beb6cSchristos 		return error;
209255beb6cSchristos 
210255beb6cSchristos 	msg32->msg_namelen = msg->msg_namelen;
211255beb6cSchristos 	msg32->msg_controllen = msg->msg_controllen;
212255beb6cSchristos 	msg32->msg_flags = msg->msg_flags;
213255beb6cSchristos 	ktrkuser("msghdr", msg, sizeof(*msg));
214255beb6cSchristos 	if (arg == NULL)
215255beb6cSchristos 		return 0;
216255beb6cSchristos 	return copyout(msg32, arg, sizeof(*arg));
217255beb6cSchristos }
218255beb6cSchristos 
219da9e4bd3Smrg int
netbsd32_recvmsg(struct lwp * l,const struct netbsd32_recvmsg_args * uap,register_t * retval)220331cb3c9Schristos netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap,
221331cb3c9Schristos     register_t *retval)
222da9e4bd3Smrg {
2237e2790cfSdsl 	/* {
224da9e4bd3Smrg 		syscallarg(int) s;
225da9e4bd3Smrg 		syscallarg(netbsd32_msghdrp_t) msg;
226da9e4bd3Smrg 		syscallarg(int) flags;
2277e2790cfSdsl 	} */
228ccdd2301Sjoerg 	struct netbsd32_msghdr	msg32;
229255beb6cSchristos 	struct iovec aiov[UIO_SMALLIOV];
230ccdd2301Sjoerg 	struct msghdr	msg;
231da9e4bd3Smrg 	int		error;
232ccdd2301Sjoerg 	struct mbuf	*from, *control;
233da9e4bd3Smrg 
234ccdd2301Sjoerg 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
235da9e4bd3Smrg 	if (error)
236650cb29cSsimonb 		return error;
237ccdd2301Sjoerg 
238255beb6cSchristos 	if ((error = msg_recv_copyin(l, &msg32, &msg, aiov)) != 0)
239255beb6cSchristos 		return error;
240ccdd2301Sjoerg 
241ccdd2301Sjoerg 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
242331cb3c9Schristos 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg,
2431766e4eeSmartin 	    &from, msg.msg_control != NULL ? &control : NULL, retval);
244ccdd2301Sjoerg 	if (error != 0)
245255beb6cSchristos 		goto out;
246ccdd2301Sjoerg 
247255beb6cSchristos 	error = msg_recv_copyout(l, &msg32, &msg, SCARG_P32(uap, msg),
248255beb6cSchristos 	    from, control);
249255beb6cSchristos out:
250255beb6cSchristos 	if (msg.msg_iov != aiov)
251255beb6cSchristos 		kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
252255beb6cSchristos 	return error;
253da9e4bd3Smrg }
254ccdd2301Sjoerg 
255255beb6cSchristos int
netbsd32_recvmmsg(struct lwp * l,const struct netbsd32_recvmmsg_args * uap,register_t * retval)256255beb6cSchristos netbsd32_recvmmsg(struct lwp *l, const struct netbsd32_recvmmsg_args *uap,
257255beb6cSchristos     register_t *retval)
258255beb6cSchristos {
259255beb6cSchristos 	/* {
260255beb6cSchristos 		syscallarg(int)				s;
261255beb6cSchristos 		syscallarg(netbsd32_mmsghdr_t)		mmsg;
262255beb6cSchristos 		syscallarg(unsigned int)		vlen;
263255beb6cSchristos 		syscallarg(unsigned int)		flags;
264255beb6cSchristos 		syscallarg(netbsd32_timespecp_t)	timeout;
265255beb6cSchristos 	} */
266255beb6cSchristos 	struct mmsghdr mmsg;
267255beb6cSchristos 	struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
268255beb6cSchristos 	struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
269255beb6cSchristos 	struct socket *so;
270255beb6cSchristos 	struct msghdr *msg = &mmsg.msg_hdr;
271255beb6cSchristos 	int error, s;
272255beb6cSchristos 	struct mbuf *from, *control;
273255beb6cSchristos 	struct timespec ts, now;
274255beb6cSchristos 	struct netbsd32_timespec ts32;
275255beb6cSchristos 	unsigned int vlen, flags, dg;
276255beb6cSchristos 	struct iovec aiov[UIO_SMALLIOV];
277255beb6cSchristos 
278255beb6cSchristos 	ts.tv_sec = 0;	// XXX: gcc
279255beb6cSchristos 	ts.tv_nsec = 0;
280255beb6cSchristos 	if (SCARG_P32(uap, timeout)) {
281255beb6cSchristos 		if ((error = copyin(SCARG_P32(uap, timeout), &ts32,
282255beb6cSchristos 		    sizeof(ts32))) != 0)
283255beb6cSchristos 			return error;
284255beb6cSchristos 		getnanotime(&now);
285255beb6cSchristos 		netbsd32_to_timespec(&ts32, &ts);
286255beb6cSchristos 		timespecadd(&now, &ts, &ts);
287255beb6cSchristos 	}
288255beb6cSchristos 
289255beb6cSchristos 	s = SCARG(uap, s);
290255beb6cSchristos 	if ((error = fd_getsock(s, &so)) != 0)
291255beb6cSchristos 		return error;
292255beb6cSchristos 
293d22a72beShannken 	/*
294d22a72beShannken 	 * If so->so_rerror holds a deferred error return it now.
295d22a72beShannken 	 */
296d22a72beShannken 	if (so->so_rerror) {
297d22a72beShannken 		error = so->so_rerror;
298d22a72beShannken 		so->so_rerror = 0;
299d22a72beShannken 		fd_putfile(s);
300d22a72beShannken 		return error;
301d22a72beShannken 	}
302d22a72beShannken 
303255beb6cSchristos 	vlen = SCARG(uap, vlen);
304255beb6cSchristos 	if (vlen > 1024)
305255beb6cSchristos 		vlen = 1024;
306255beb6cSchristos 
307255beb6cSchristos 	from = NULL;
308255beb6cSchristos 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
309255beb6cSchristos 
310255beb6cSchristos 	for (dg = 0; dg < vlen;) {
311255beb6cSchristos 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
312255beb6cSchristos 		if (error)
313255beb6cSchristos 			break;
314255beb6cSchristos 
315255beb6cSchristos 		if ((error = msg_recv_copyin(l, msg32, msg, aiov)) != 0)
316255beb6cSchristos 			return error;
317255beb6cSchristos 
318255beb6cSchristos 		msg->msg_flags = flags & ~MSG_WAITFORONE;
319255beb6cSchristos 
320255beb6cSchristos 		if (from != NULL) {
321255beb6cSchristos 			m_free(from);
322255beb6cSchristos 			from = NULL;
323255beb6cSchristos 		}
324255beb6cSchristos 
325255beb6cSchristos 		error = do_sys_recvmsg_so(l, s, so, msg, &from,
326255beb6cSchristos 		    msg->msg_control != NULL ? &control : NULL, retval);
327255beb6cSchristos 		if (error) {
328255beb6cSchristos 			if (error == EAGAIN && dg > 0)
329255beb6cSchristos 				error = 0;
330255beb6cSchristos 			break;
331255beb6cSchristos 		}
332255beb6cSchristos 		error = msg_recv_copyout(l, msg32, msg, NULL,
333255beb6cSchristos 		    from, control);
334255beb6cSchristos 		from = NULL;
335255beb6cSchristos 		if (error)
336255beb6cSchristos 			break;
337255beb6cSchristos 
338255beb6cSchristos 		mmsg32.msg_len = *retval;
339255beb6cSchristos 
340255beb6cSchristos 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
341255beb6cSchristos 		if (error)
342255beb6cSchristos 			break;
343255beb6cSchristos 
344255beb6cSchristos 		dg++;
345255beb6cSchristos 		if (msg->msg_flags & MSG_OOB)
346255beb6cSchristos 			break;
347255beb6cSchristos 
348255beb6cSchristos 		if (SCARG_P32(uap, timeout)) {
349255beb6cSchristos 			getnanotime(&now);
350255beb6cSchristos 			timespecsub(&now, &ts, &now);
351255beb6cSchristos 			if (now.tv_sec > 0)
352255beb6cSchristos 				break;
353255beb6cSchristos 		}
354255beb6cSchristos 
355255beb6cSchristos 		if (flags & MSG_WAITFORONE)
356255beb6cSchristos 			flags |= MSG_DONTWAIT;
357255beb6cSchristos 
358255beb6cSchristos 	}
359255beb6cSchristos 
360255beb6cSchristos 	if (from != NULL)
361255beb6cSchristos 		m_free(from);
362255beb6cSchristos 
363255beb6cSchristos 	*retval = dg;
364255beb6cSchristos 
365255beb6cSchristos 	/*
366d22a72beShannken 	 * If we succeeded at least once, return 0, hopefully so->so_rerror
367255beb6cSchristos 	 * will catch it next time.
368255beb6cSchristos 	 */
369d22a72beShannken 	if (error && dg > 0) {
370d22a72beShannken 		so->so_rerror = error;
371d22a72beShannken 		error = 0;
372d22a72beShannken 	}
373d22a72beShannken 
374d22a72beShannken 	fd_putfile(s);
375255beb6cSchristos 
376255beb6cSchristos 	return error;
377da9e4bd3Smrg }
378da9e4bd3Smrg 
379e8bec33bSjoerg static int
copyin32_msg_control(struct lwp * l,struct msghdr * mp)380e8bec33bSjoerg copyin32_msg_control(struct lwp *l, struct msghdr *mp)
381e8bec33bSjoerg {
382e8bec33bSjoerg 	/*
383e8bec33bSjoerg 	 * Handle cmsg if there is any.
384e8bec33bSjoerg 	 */
385e8bec33bSjoerg 	struct cmsghdr *cmsg, cmsg32, *cc;
386e8bec33bSjoerg 	struct mbuf *ctl_mbuf;
387e8bec33bSjoerg 	ssize_t resid = mp->msg_controllen;
388e8bec33bSjoerg 	size_t clen, cidx = 0, cspace;
389ec694a92Ssimonb 	uint8_t *control;
390e8bec33bSjoerg 	int error;
391e8bec33bSjoerg 
392e8bec33bSjoerg 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
393e8bec33bSjoerg 	clen = MLEN;
394e8bec33bSjoerg 	control = mtod(ctl_mbuf, void *);
395e8bec33bSjoerg 	memset(control, 0, clen);
396e8bec33bSjoerg 
397331cb3c9Schristos 	for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
398331cb3c9Schristos 	{
399e8bec33bSjoerg 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
400e8bec33bSjoerg 		if (error)
401e8bec33bSjoerg 			goto failure;
402e8bec33bSjoerg 
403e8bec33bSjoerg 		/*
404e8bec33bSjoerg 		 * Sanity check the control message length.
405e8bec33bSjoerg 		 */
406ac4fabcaSmlelstv 		if (resid < 0 ||
407ac4fabcaSmlelstv 		    cmsg32.cmsg_len > (size_t)resid ||
408e8bec33bSjoerg 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
409e8bec33bSjoerg 			error = EINVAL;
410e8bec33bSjoerg 			goto failure;
411e8bec33bSjoerg 		}
412e8bec33bSjoerg 
413e8bec33bSjoerg 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
414e8bec33bSjoerg 
415e8bec33bSjoerg 		/* Check the buffer is big enough */
416e8bec33bSjoerg 		if (__predict_false(cidx + cspace > clen)) {
417ec694a92Ssimonb 			uint8_t *nc;
418e8bec33bSjoerg 			size_t nclen;
419e8bec33bSjoerg 
420e8bec33bSjoerg 			nclen = cidx + cspace;
4210735f45fSmlelstv 			if (nclen >= (size_t)PAGE_SIZE) {
422e8bec33bSjoerg 				error = EINVAL;
423e8bec33bSjoerg 				goto failure;
424e8bec33bSjoerg 			}
425e8bec33bSjoerg 			nc = realloc(clen <= MLEN ? NULL : control,
426e8bec33bSjoerg 				     nclen, M_TEMP, M_WAITOK);
427e8bec33bSjoerg 			if (!nc) {
428e8bec33bSjoerg 				error = ENOMEM;
429e8bec33bSjoerg 				goto failure;
430e8bec33bSjoerg 			}
431e8bec33bSjoerg 			if (cidx <= MLEN) {
432e8bec33bSjoerg 				/* Old buffer was in mbuf... */
433e8bec33bSjoerg 				memcpy(nc, control, cidx);
434e8bec33bSjoerg 				memset(nc + cidx, 0, nclen - cidx);
435e8bec33bSjoerg 			} else {
436e8bec33bSjoerg 				memset(nc + nclen, 0, nclen - clen);
437e8bec33bSjoerg 			}
438e8bec33bSjoerg 			control = nc;
439e8bec33bSjoerg 			clen = nclen;
440e8bec33bSjoerg 		}
441e8bec33bSjoerg 
442e8bec33bSjoerg 		/* Copy header */
443e8bec33bSjoerg 		cmsg = (void *)&control[cidx];
444e8bec33bSjoerg 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
445e8bec33bSjoerg 		cmsg->cmsg_level = cmsg32.cmsg_level;
446e8bec33bSjoerg 		cmsg->cmsg_type = cmsg32.cmsg_type;
447e8bec33bSjoerg 
448e8bec33bSjoerg 		/* Copyin the data */
449e8bec33bSjoerg 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
450e8bec33bSjoerg 		    cmsg32.cmsg_len - CMSG32_LEN(0));
451e8bec33bSjoerg 		if (error)
452e8bec33bSjoerg 			goto failure;
453331cb3c9Schristos 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
454e8bec33bSjoerg 
455e8bec33bSjoerg 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
456331cb3c9Schristos 		cidx += CMSG_ALIGN(cmsg->cmsg_len);
457331cb3c9Schristos 	}
458e8bec33bSjoerg 
459e8bec33bSjoerg 	/* If we allocated a buffer, attach to mbuf */
460e8bec33bSjoerg 	if (cidx > MLEN) {
461e8bec33bSjoerg 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
462e8bec33bSjoerg 		ctl_mbuf->m_flags |= M_EXT_RW;
463e8bec33bSjoerg 	}
464e8bec33bSjoerg 	control = NULL;
465e8bec33bSjoerg 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
466e8bec33bSjoerg 
467e8bec33bSjoerg 	mp->msg_control = ctl_mbuf;
468e8bec33bSjoerg 	mp->msg_flags |= MSG_CONTROLMBUF;
469e8bec33bSjoerg 
470e8bec33bSjoerg 
471e8bec33bSjoerg 	return 0;
472e8bec33bSjoerg 
473e8bec33bSjoerg failure:
474e8bec33bSjoerg 	if (control != mtod(ctl_mbuf, void *))
475e8bec33bSjoerg 		free(control, M_MBUF);
476e8bec33bSjoerg 	m_free(ctl_mbuf);
477e8bec33bSjoerg 	return error;
478e8bec33bSjoerg }
479e8bec33bSjoerg 
480255beb6cSchristos static int
msg_send_copyin(struct lwp * l,const struct netbsd32_msghdr * msg32,struct msghdr * msg,struct iovec * aiov)481255beb6cSchristos msg_send_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
482255beb6cSchristos     struct msghdr *msg, struct iovec *aiov)
483255beb6cSchristos {
484255beb6cSchristos 	int error;
485255beb6cSchristos 	struct iovec *iov = aiov;
486255beb6cSchristos 	struct netbsd32_iovec *iov32;
487255beb6cSchristos 	size_t iovsz;
488255beb6cSchristos 
489255beb6cSchristos 	netbsd32_to_msghdr(msg32, msg);
490255beb6cSchristos 	msg->msg_flags = 0;
491255beb6cSchristos 
492255beb6cSchristos 	if (CMSG32_FIRSTHDR(msg)) {
493255beb6cSchristos 		error = copyin32_msg_control(l, msg);
494255beb6cSchristos 		if (error)
495255beb6cSchristos 			return error;
496255beb6cSchristos 		/* From here on, msg->msg_control is allocated */
497255beb6cSchristos 	} else {
498255beb6cSchristos 		msg->msg_control = NULL;
499255beb6cSchristos 		msg->msg_controllen = 0;
500255beb6cSchristos 	}
501255beb6cSchristos 
502255beb6cSchristos 	iovsz = msg->msg_iovlen * sizeof(struct iovec);
503255beb6cSchristos 	if ((u_int)msg->msg_iovlen > UIO_SMALLIOV) {
504255beb6cSchristos 		if ((u_int)msg->msg_iovlen > IOV_MAX) {
505255beb6cSchristos 			error = EMSGSIZE;
506255beb6cSchristos 			goto out;
507255beb6cSchristos 		}
508255beb6cSchristos 		iov = kmem_alloc(iovsz, KM_SLEEP);
509255beb6cSchristos 	}
510255beb6cSchristos 
511255beb6cSchristos 	iov32 = NETBSD32PTR64(msg32->msg_iov);
512255beb6cSchristos 	error = netbsd32_to_iovecin(iov32, iov, msg->msg_iovlen);
513255beb6cSchristos 	if (error)
514255beb6cSchristos 		goto out;
515255beb6cSchristos 	msg->msg_iov = iov;
5162bd1a590Schristos 	return 0;
517255beb6cSchristos out:
518255beb6cSchristos 	if (msg->msg_control)
519255beb6cSchristos 		m_free(msg->msg_control);
520255beb6cSchristos 	if (iov != aiov)
521255beb6cSchristos 		kmem_free(iov, iovsz);
522255beb6cSchristos 	return error;
523255beb6cSchristos }
524255beb6cSchristos 
525da9e4bd3Smrg int
netbsd32_sendmsg(struct lwp * l,const struct netbsd32_sendmsg_args * uap,register_t * retval)526331cb3c9Schristos netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
527331cb3c9Schristos     register_t *retval)
528da9e4bd3Smrg {
5297e2790cfSdsl 	/* {
530da9e4bd3Smrg 		syscallarg(int) s;
531da9e4bd3Smrg 		syscallarg(const netbsd32_msghdrp_t) msg;
532da9e4bd3Smrg 		syscallarg(int) flags;
5337e2790cfSdsl 	} */
534da9e4bd3Smrg 	struct msghdr msg;
535da9e4bd3Smrg 	struct netbsd32_msghdr msg32;
536255beb6cSchristos 	struct iovec aiov[UIO_SMALLIOV];
537da9e4bd3Smrg 	int error;
538da9e4bd3Smrg 
539d364d308Sdsl 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
540da9e4bd3Smrg 	if (error)
541255beb6cSchristos 		return error;
542e8bec33bSjoerg 
543255beb6cSchristos 	if ((error = msg_send_copyin(l, &msg32, &msg, aiov)) != 0)
544255beb6cSchristos 		return error;
545d7f93c5cSdsl 
5461766e4eeSmartin 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
547331cb3c9Schristos 	    retval);
5481e2d60e1Smaxv 	/* msg.msg_control freed by do_sys_sendmsg() */
5491e2d60e1Smaxv 
550255beb6cSchristos 	if (msg.msg_iov != aiov)
551255beb6cSchristos 		kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
552255beb6cSchristos 	return error;
553255beb6cSchristos }
5541e2d60e1Smaxv 
555255beb6cSchristos int
netbsd32_sendmmsg(struct lwp * l,const struct netbsd32_sendmmsg_args * uap,register_t * retval)556255beb6cSchristos netbsd32_sendmmsg(struct lwp *l, const struct netbsd32_sendmmsg_args *uap,
557255beb6cSchristos     register_t *retval)
558255beb6cSchristos {
559255beb6cSchristos 	/* {
560255beb6cSchristos 		syscallarg(int)			s;
561255beb6cSchristos 		syscallarg(const netbsd32_mmsghdr_t)	mmsg;
562255beb6cSchristos 		syscallarg(unsigned int)	vlen;
563255beb6cSchristos 		syscallarg(unsigned int)	flags;
564255beb6cSchristos 	} */
565255beb6cSchristos 	struct mmsghdr mmsg;
566255beb6cSchristos 	struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
567255beb6cSchristos 	struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
568255beb6cSchristos 	struct socket *so;
569255beb6cSchristos 	file_t *fp;
570255beb6cSchristos 	struct msghdr *msg = &mmsg.msg_hdr;
571255beb6cSchristos 	int error, s;
572255beb6cSchristos 	unsigned int vlen, flags, dg;
573255beb6cSchristos 	struct iovec aiov[UIO_SMALLIOV];
574255beb6cSchristos 
575255beb6cSchristos 	s = SCARG(uap, s);
576255beb6cSchristos 	if ((error = fd_getsock1(s, &so, &fp)) != 0)
577255beb6cSchristos 		return error;
578255beb6cSchristos 
579255beb6cSchristos 	vlen = SCARG(uap, vlen);
580255beb6cSchristos 	if (vlen > 1024)
581255beb6cSchristos 		vlen = 1024;
582255beb6cSchristos 
583255beb6cSchristos 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
584255beb6cSchristos 
585255beb6cSchristos 	for (dg = 0; dg < vlen;) {
586255beb6cSchristos 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
587255beb6cSchristos 		if (error)
588255beb6cSchristos 			break;
589255beb6cSchristos 		if ((error = msg_send_copyin(l, msg32, msg, aiov)) != 0)
590255beb6cSchristos 			break;
591255beb6cSchristos 
592255beb6cSchristos 		msg->msg_flags = flags;
593255beb6cSchristos 
594255beb6cSchristos 		error = do_sys_sendmsg_so(l, s, so, fp, msg, flags, retval);
595255beb6cSchristos 		if (msg->msg_iov != aiov) {
596255beb6cSchristos 			kmem_free(msg->msg_iov,
597255beb6cSchristos 			    msg->msg_iovlen * sizeof(struct iovec));
598255beb6cSchristos 		}
599255beb6cSchristos 		if (error)
600255beb6cSchristos 			break;
601255beb6cSchristos 
602255beb6cSchristos 		ktrkuser("msghdr", msg, sizeof(*msg));
603255beb6cSchristos 		mmsg.msg_len = *retval;
604255beb6cSchristos 		netbsd32_from_mmsghdr(&mmsg32, &mmsg);
605255beb6cSchristos 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
606255beb6cSchristos 		if (error)
607255beb6cSchristos 			break;
608255beb6cSchristos 		dg++;
609255beb6cSchristos 	}
610255beb6cSchristos 
611255beb6cSchristos 	*retval = dg;
612255beb6cSchristos 
613255beb6cSchristos 	fd_putfile(s);
614255beb6cSchristos 
615255beb6cSchristos 	/*
616d22a72beShannken 	 * If we succeeded at least once, return 0.
617255beb6cSchristos 	 */
618255beb6cSchristos 	if (dg)
619255beb6cSchristos 		return 0;
6201e2d60e1Smaxv 	return error;
621da9e4bd3Smrg }
622da9e4bd3Smrg 
623da9e4bd3Smrg int
netbsd32_recvfrom(struct lwp * l,const struct netbsd32_recvfrom_args * uap,register_t * retval)624331cb3c9Schristos netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
625331cb3c9Schristos     register_t *retval)
626da9e4bd3Smrg {
6277e2790cfSdsl 	/* {
628da9e4bd3Smrg 		syscallarg(int) s;
629da9e4bd3Smrg 		syscallarg(netbsd32_voidp) buf;
630da9e4bd3Smrg 		syscallarg(netbsd32_size_t) len;
631da9e4bd3Smrg 		syscallarg(int) flags;
632da9e4bd3Smrg 		syscallarg(netbsd32_sockaddrp_t) from;
633da9e4bd3Smrg 		syscallarg(netbsd32_intp) fromlenaddr;
6347e2790cfSdsl 	} */
635ccdd2301Sjoerg 	struct msghdr	msg;
636da9e4bd3Smrg 	struct iovec	aiov;
637da9e4bd3Smrg 	int		error;
638ccdd2301Sjoerg 	struct mbuf	*from;
639da9e4bd3Smrg 
640*3daa70afSsimonb 	if (SCARG(uap, len) > NETBSD32_SSIZE_MAX)
641*3daa70afSsimonb 		return EINVAL;
642*3daa70afSsimonb 
643ccdd2301Sjoerg 	msg.msg_name = NULL;
644ccdd2301Sjoerg 	msg.msg_iov = &aiov;
645da9e4bd3Smrg 	msg.msg_iovlen = 1;
646d364d308Sdsl 	aiov.iov_base = SCARG_P32(uap, buf);
647ccdd2301Sjoerg 	aiov.iov_len = SCARG(uap, len);
648ccdd2301Sjoerg 	msg.msg_control = NULL;
649ccdd2301Sjoerg 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
650ccdd2301Sjoerg 
651331cb3c9Schristos 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
652ccdd2301Sjoerg 	if (error != 0)
653ccdd2301Sjoerg 		return error;
654ccdd2301Sjoerg 
655331cb3c9Schristos 	error = copyout_sockname(SCARG_P32(uap, from),
656331cb3c9Schristos 	    SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
657ccdd2301Sjoerg 	if (from != NULL)
658ccdd2301Sjoerg 		m_free(from);
659ccdd2301Sjoerg 	return error;
660da9e4bd3Smrg }
661da9e4bd3Smrg 
662da9e4bd3Smrg int
netbsd32_sendto(struct lwp * l,const struct netbsd32_sendto_args * uap,register_t * retval)663331cb3c9Schristos netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
664331cb3c9Schristos     register_t *retval)
665da9e4bd3Smrg {
6667e2790cfSdsl 	/* {
667da9e4bd3Smrg 		syscallarg(int) s;
668da9e4bd3Smrg 		syscallarg(const netbsd32_voidp) buf;
669da9e4bd3Smrg 		syscallarg(netbsd32_size_t) len;
670da9e4bd3Smrg 		syscallarg(int) flags;
671da9e4bd3Smrg 		syscallarg(const netbsd32_sockaddrp_t) to;
672da9e4bd3Smrg 		syscallarg(int) tolen;
6737e2790cfSdsl 	} */
674da9e4bd3Smrg 	struct msghdr msg;
675da9e4bd3Smrg 	struct iovec aiov;
676da9e4bd3Smrg 
677*3daa70afSsimonb 	if (SCARG(uap, len) > NETBSD32_SSIZE_MAX)
678*3daa70afSsimonb 		return EINVAL;
679*3daa70afSsimonb 
680d364d308Sdsl 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
681da9e4bd3Smrg 	msg.msg_namelen = SCARG(uap, tolen);
682da9e4bd3Smrg 	msg.msg_iov = &aiov;
683da9e4bd3Smrg 	msg.msg_iovlen = 1;
684da9e4bd3Smrg 	msg.msg_control = 0;
685d364d308Sdsl 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
686da9e4bd3Smrg 	aiov.iov_len = SCARG(uap, len);
687d7f93c5cSdsl 	msg.msg_flags = 0;
6881766e4eeSmartin 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
689331cb3c9Schristos 	    retval);
690da9e4bd3Smrg }
691