1 /*	$NetBSD: netbsd32_socket.c,v 1.50 2019/09/26 01:32:09 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 2001 Matthew R. Green
5  * 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.50 2019/09/26 01:32:09 christos Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #define msg __msg /* Don't ask me! */
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/socketvar.h>
39 #include <sys/mbuf.h>
40 #include <sys/ktrace.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/syscallargs.h>
44 #include <sys/proc.h>
45 #include <sys/dirent.h>
46 
47 #include <compat/netbsd32/netbsd32.h>
48 #include <compat/netbsd32/netbsd32_syscallargs.h>
49 #include <compat/netbsd32/netbsd32_conv.h>
50 
51 /*
52  * XXX Assumes that struct sockaddr is compatible.
53  */
54 
55 #define	CMSG32_ALIGN(n)	(((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
56 #define CMSG32_ASIZE	CMSG32_ALIGN(sizeof(struct cmsghdr))
57 #define	CMSG32_DATA(cmsg) (__CASTV(u_char *, cmsg) + CMSG32_ASIZE)
58 #define CMSG32_MSGNEXT(ucmsg, kcmsg) \
59     (__CASTV(char *, kcmsg) + CMSG32_ALIGN((ucmsg)->cmsg_len))
60 #define CMSG32_MSGEND(mhdr) \
61     (__CASTV(char *, (mhdr)->msg_control) + (mhdr)->msg_controllen)
62 
63 #define	CMSG32_NXTHDR(mhdr, ucmsg, kcmsg)	\
64     __CASTV(struct cmsghdr *,  \
65 	CMSG32_MSGNEXT(ucmsg, kcmsg) + \
66 	CMSG32_ASIZE > CMSG32_MSGEND(mhdr) ? 0 : \
67 	CMSG32_MSGNEXT(ucmsg, kcmsg))
68 #define	CMSG32_FIRSTHDR(mhdr) \
69     __CASTV(struct cmsghdr *, \
70 	(mhdr)->msg_controllen < sizeof(struct cmsghdr) ? 0 : \
71 	(mhdr)->msg_control)
72 
73 #define CMSG32_SPACE(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
74 #define CMSG32_LEN(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
75 
76 static int
77 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, u_int *len,
78     struct mbuf *m, char **q, bool *truncated)
79 {
80 	struct cmsghdr *cmsg, cmsg32;
81 	size_t i, j;
82 	int error;
83 
84 	*truncated = false;
85 	cmsg = mtod(m, struct cmsghdr *);
86 	do {
87 		if ((char *)cmsg == mtod(m, char *) + m->m_len)
88 			break;
89 		if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
90 			return EINVAL;
91 		cmsg32 = *cmsg;
92 		j = cmsg->cmsg_len - CMSG_LEN(0);
93 		i = cmsg32.cmsg_len = CMSG32_LEN(j);
94 		if (i > *len) {
95 			mp->msg_flags |= MSG_CTRUNC;
96 			if (cmsg->cmsg_level == SOL_SOCKET
97 			    && cmsg->cmsg_type == SCM_RIGHTS) {
98 				*truncated = true;
99 				return 0;
100 			}
101 			j -= i - *len;
102 			i = *len;
103 		}
104 
105 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
106 		error = copyout(&cmsg32, *q, MIN(i, sizeof(cmsg32)));
107 		if (error)
108 			return (error);
109 		if (i > CMSG32_LEN(0)) {
110 			error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0),
111 			    i - CMSG32_LEN(0));
112 			if (error)
113 				return (error);
114 		}
115 		j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
116 		if (*len >= j) {
117 			*len -= j;
118 			*q += j;
119 		} else {
120 			*q += i;
121 			*len = 0;
122 		}
123 		cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
124 	} while (*len > 0);
125 
126 	return 0;
127 }
128 
129 static int
130 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
131 {
132 	int len, error = 0;
133 	struct mbuf *m;
134 	char *q;
135 	bool truncated;
136 
137 	len = mp->msg_controllen;
138 	if (len <= 0 || control == 0) {
139 		mp->msg_controllen = 0;
140 		free_control_mbuf(l, control, control);
141 		return 0;
142 	}
143 
144 	q = (char *)mp->msg_control;
145 
146 	for (m = control; len > 0 && m != NULL; m = m->m_next) {
147 		error = copyout32_msg_control_mbuf(l, mp, &len, m, &q,
148 		    &truncated);
149 		if (truncated) {
150 			m = control;
151 			break;
152 		}
153 		if (error)
154 			break;
155 	}
156 
157 	free_control_mbuf(l, control, m);
158 
159 	mp->msg_controllen = q - (char *)mp->msg_control;
160 	return error;
161 }
162 
163 static int
164 msg_recv_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
165     struct msghdr *msg, struct iovec *aiov)
166 {
167 	int error;
168 	size_t iovsz;
169 	struct iovec *iov = aiov;
170 
171 	iovsz = msg32->msg_iovlen * sizeof(struct iovec);
172 	if (msg32->msg_iovlen > UIO_SMALLIOV) {
173 		if (msg32->msg_iovlen > IOV_MAX)
174 			return EMSGSIZE;
175 		iov = kmem_alloc(iovsz, KM_SLEEP);
176 	}
177 
178 	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32->msg_iov), iov,
179 	    msg32->msg_iovlen);
180 	if (error)
181 		goto out;
182 
183 	netbsd32_to_msghdr(msg32, msg);
184 	msg->msg_iov = iov;
185 out:
186 	if (iov != aiov)
187 		kmem_free(iov, iovsz);
188 	return error;
189 }
190 
191 static int
192 msg_recv_copyout(struct lwp *l, struct netbsd32_msghdr *msg32,
193     struct msghdr *msg, struct netbsd32_msghdr *arg,
194     struct mbuf *from, struct mbuf *control)
195 {
196 	int error = 0;
197 
198 	if (msg->msg_control != NULL)
199 		error = copyout32_msg_control(l, msg, control);
200 
201 	if (error == 0)
202 		error = copyout_sockname(msg->msg_name, &msg->msg_namelen, 0,
203 			from);
204 
205 	if (from != NULL)
206 		m_free(from);
207 	if (error)
208 		return error;
209 
210 	msg32->msg_namelen = msg->msg_namelen;
211 	msg32->msg_controllen = msg->msg_controllen;
212 	msg32->msg_flags = msg->msg_flags;
213 	ktrkuser("msghdr", msg, sizeof(*msg));
214 	if (arg == NULL)
215 		return 0;
216 	return copyout(msg32, arg, sizeof(*arg));
217 }
218 
219 int
220 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap,
221     register_t *retval)
222 {
223 	/* {
224 		syscallarg(int) s;
225 		syscallarg(netbsd32_msghdrp_t) msg;
226 		syscallarg(int) flags;
227 	} */
228 	struct netbsd32_msghdr	msg32;
229 	struct iovec aiov[UIO_SMALLIOV];
230 	struct msghdr	msg;
231 	int		error;
232 	struct mbuf	*from, *control;
233 
234 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
235 	if (error)
236 		return (error);
237 
238 	if ((error = msg_recv_copyin(l, &msg32, &msg, aiov)) != 0)
239 		return error;
240 
241 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
242 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg,
243 	    &from, msg.msg_control != NULL ? &control : NULL, retval);
244 	if (error != 0)
245 		goto out;
246 
247 	error = msg_recv_copyout(l, &msg32, &msg, SCARG_P32(uap, msg),
248 	    from, control);
249 out:
250 	if (msg.msg_iov != aiov)
251 		kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
252 	return error;
253 }
254 
255 int
256 netbsd32_recvmmsg(struct lwp *l, const struct netbsd32_recvmmsg_args *uap,
257     register_t *retval)
258 {
259 	/* {
260 		syscallarg(int)				s;
261 		syscallarg(netbsd32_mmsghdr_t)		mmsg;
262 		syscallarg(unsigned int)		vlen;
263 		syscallarg(unsigned int)		flags;
264 		syscallarg(netbsd32_timespecp_t)	timeout;
265 	} */
266 	struct mmsghdr mmsg;
267 	struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
268 	struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
269 	struct socket *so;
270 	struct msghdr *msg = &mmsg.msg_hdr;
271 	int error, s;
272 	struct mbuf *from, *control;
273 	struct timespec ts, now;
274 	struct netbsd32_timespec ts32;
275 	unsigned int vlen, flags, dg;
276 	struct iovec aiov[UIO_SMALLIOV];
277 
278 	ts.tv_sec = 0;	// XXX: gcc
279 	ts.tv_nsec = 0;
280 	if (SCARG_P32(uap, timeout)) {
281 		if ((error = copyin(SCARG_P32(uap, timeout), &ts32,
282 		    sizeof(ts32))) != 0)
283 			return error;
284 		getnanotime(&now);
285 		netbsd32_to_timespec(&ts32, &ts);
286 		timespecadd(&now, &ts, &ts);
287 	}
288 
289 	s = SCARG(uap, s);
290 	if ((error = fd_getsock(s, &so)) != 0)
291 		return error;
292 
293 	/*
294 	 * If so->so_rerror holds a deferred error return it now.
295 	 */
296 	if (so->so_rerror) {
297 		error = so->so_rerror;
298 		so->so_rerror = 0;
299 		fd_putfile(s);
300 		return error;
301 	}
302 
303 	vlen = SCARG(uap, vlen);
304 	if (vlen > 1024)
305 		vlen = 1024;
306 
307 	from = NULL;
308 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
309 
310 	for (dg = 0; dg < vlen;) {
311 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
312 		if (error)
313 			break;
314 
315 		if ((error = msg_recv_copyin(l, msg32, msg, aiov)) != 0)
316 			return error;
317 
318 		msg->msg_flags = flags & ~MSG_WAITFORONE;
319 
320 		if (from != NULL) {
321 			m_free(from);
322 			from = NULL;
323 		}
324 
325 		error = do_sys_recvmsg_so(l, s, so, msg, &from,
326 		    msg->msg_control != NULL ? &control : NULL, retval);
327 		if (error) {
328 			if (error == EAGAIN && dg > 0)
329 				error = 0;
330 			break;
331 		}
332 		error = msg_recv_copyout(l, msg32, msg, NULL,
333 		    from, control);
334 		from = NULL;
335 		if (error)
336 			break;
337 
338 		mmsg32.msg_len = *retval;
339 
340 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
341 		if (error)
342 			break;
343 
344 		dg++;
345 		if (msg->msg_flags & MSG_OOB)
346 			break;
347 
348 		if (SCARG_P32(uap, timeout)) {
349 			getnanotime(&now);
350 			timespecsub(&now, &ts, &now);
351 			if (now.tv_sec > 0)
352 				break;
353 		}
354 
355 		if (flags & MSG_WAITFORONE)
356 			flags |= MSG_DONTWAIT;
357 
358 	}
359 
360 	if (from != NULL)
361 		m_free(from);
362 
363 	*retval = dg;
364 
365 	/*
366 	 * If we succeeded at least once, return 0, hopefully so->so_rerror
367 	 * will catch it next time.
368 	 */
369 	if (error && dg > 0) {
370 		so->so_rerror = error;
371 		error = 0;
372 	}
373 
374 	fd_putfile(s);
375 
376 	return error;
377 }
378 
379 static int
380 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
381 {
382 	/*
383 	 * Handle cmsg if there is any.
384 	 */
385 	struct cmsghdr *cmsg, cmsg32, *cc;
386 	struct mbuf *ctl_mbuf;
387 	ssize_t resid = mp->msg_controllen;
388 	size_t clen, cidx = 0, cspace;
389 	u_int8_t *control;
390 	int error;
391 
392 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
393 	clen = MLEN;
394 	control = mtod(ctl_mbuf, void *);
395 	memset(control, 0, clen);
396 
397 	for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
398 	{
399 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
400 		if (error)
401 			goto failure;
402 
403 		/*
404 		 * Sanity check the control message length.
405 		 */
406 		if (cmsg32.cmsg_len > resid ||
407 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
408 			error = EINVAL;
409 			goto failure;
410 		}
411 
412 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
413 
414 		/* Check the buffer is big enough */
415 		if (__predict_false(cidx + cspace > clen)) {
416 			u_int8_t *nc;
417 			size_t nclen;
418 
419 			nclen = cidx + cspace;
420 			if (nclen >= PAGE_SIZE) {
421 				error = EINVAL;
422 				goto failure;
423 			}
424 			nc = realloc(clen <= MLEN ? NULL : control,
425 				     nclen, M_TEMP, M_WAITOK);
426 			if (!nc) {
427 				error = ENOMEM;
428 				goto failure;
429 			}
430 			if (cidx <= MLEN) {
431 				/* Old buffer was in mbuf... */
432 				memcpy(nc, control, cidx);
433 				memset(nc + cidx, 0, nclen - cidx);
434 			} else {
435 				memset(nc + nclen, 0, nclen - clen);
436 			}
437 			control = nc;
438 			clen = nclen;
439 		}
440 
441 		/* Copy header */
442 		cmsg = (void *)&control[cidx];
443 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
444 		cmsg->cmsg_level = cmsg32.cmsg_level;
445 		cmsg->cmsg_type = cmsg32.cmsg_type;
446 
447 		/* Copyin the data */
448 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
449 		    cmsg32.cmsg_len - CMSG32_LEN(0));
450 		if (error)
451 			goto failure;
452 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
453 
454 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
455 		cidx += CMSG_ALIGN(cmsg->cmsg_len);
456 	}
457 
458 	/* If we allocated a buffer, attach to mbuf */
459 	if (cidx > MLEN) {
460 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
461 		ctl_mbuf->m_flags |= M_EXT_RW;
462 	}
463 	control = NULL;
464 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
465 
466 	mp->msg_control = ctl_mbuf;
467 	mp->msg_flags |= MSG_CONTROLMBUF;
468 
469 
470 	return 0;
471 
472 failure:
473 	if (control != mtod(ctl_mbuf, void *))
474 		free(control, M_MBUF);
475 	m_free(ctl_mbuf);
476 	return error;
477 }
478 
479 static int
480 msg_send_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
481     struct msghdr *msg, struct iovec *aiov)
482 {
483 	int error;
484 	struct iovec *iov = aiov;
485 	struct netbsd32_iovec *iov32;
486 	size_t iovsz;
487 
488 	netbsd32_to_msghdr(msg32, msg);
489 	msg->msg_flags = 0;
490 
491 	if (CMSG32_FIRSTHDR(msg)) {
492 		error = copyin32_msg_control(l, msg);
493 		if (error)
494 			return error;
495 		/* From here on, msg->msg_control is allocated */
496 	} else {
497 		msg->msg_control = NULL;
498 		msg->msg_controllen = 0;
499 	}
500 
501 	iovsz = msg->msg_iovlen * sizeof(struct iovec);
502 	if ((u_int)msg->msg_iovlen > UIO_SMALLIOV) {
503 		if ((u_int)msg->msg_iovlen > IOV_MAX) {
504 			error = EMSGSIZE;
505 			goto out;
506 		}
507 		iov = kmem_alloc(iovsz, KM_SLEEP);
508 	}
509 
510 	iov32 = NETBSD32PTR64(msg32->msg_iov);
511 	error = netbsd32_to_iovecin(iov32, iov, msg->msg_iovlen);
512 	if (error)
513 		goto out;
514 	msg->msg_iov = iov;
515 	return 0;
516 out:
517 	if (msg->msg_control)
518 		m_free(msg->msg_control);
519 	if (iov != aiov)
520 		kmem_free(iov, iovsz);
521 	return error;
522 }
523 
524 int
525 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
526     register_t *retval)
527 {
528 	/* {
529 		syscallarg(int) s;
530 		syscallarg(const netbsd32_msghdrp_t) msg;
531 		syscallarg(int) flags;
532 	} */
533 	struct msghdr msg;
534 	struct netbsd32_msghdr msg32;
535 	struct iovec aiov[UIO_SMALLIOV];
536 	int error;
537 
538 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
539 	if (error)
540 		return error;
541 
542 	if ((error = msg_send_copyin(l, &msg32, &msg, aiov)) != 0)
543 		return error;
544 
545 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
546 	    retval);
547 	/* msg.msg_control freed by do_sys_sendmsg() */
548 
549 	if (msg.msg_iov != aiov)
550 		kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
551 	return error;
552 }
553 
554 int
555 netbsd32_sendmmsg(struct lwp *l, const struct netbsd32_sendmmsg_args *uap,
556     register_t *retval)
557 {
558 	/* {
559 		syscallarg(int)			s;
560 		syscallarg(const netbsd32_mmsghdr_t)	mmsg;
561 		syscallarg(unsigned int)	vlen;
562 		syscallarg(unsigned int)	flags;
563 	} */
564 	struct mmsghdr mmsg;
565 	struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
566 	struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
567 	struct socket *so;
568 	file_t *fp;
569 	struct msghdr *msg = &mmsg.msg_hdr;
570 	int error, s;
571 	unsigned int vlen, flags, dg;
572 	struct iovec aiov[UIO_SMALLIOV];
573 
574 	s = SCARG(uap, s);
575 	if ((error = fd_getsock1(s, &so, &fp)) != 0)
576 		return error;
577 
578 	vlen = SCARG(uap, vlen);
579 	if (vlen > 1024)
580 		vlen = 1024;
581 
582 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
583 
584 	for (dg = 0; dg < vlen;) {
585 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
586 		if (error)
587 			break;
588 		if ((error = msg_send_copyin(l, msg32, msg, aiov)) != 0)
589 			break;
590 
591 		msg->msg_flags = flags;
592 
593 		error = do_sys_sendmsg_so(l, s, so, fp, msg, flags, retval);
594 		if (msg->msg_iov != aiov) {
595 			kmem_free(msg->msg_iov,
596 			    msg->msg_iovlen * sizeof(struct iovec));
597 		}
598 		if (error)
599 			break;
600 
601 		ktrkuser("msghdr", msg, sizeof(*msg));
602 		mmsg.msg_len = *retval;
603 		netbsd32_from_mmsghdr(&mmsg32, &mmsg);
604 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
605 		if (error)
606 			break;
607 		dg++;
608 	}
609 
610 	*retval = dg;
611 
612 	fd_putfile(s);
613 
614 	/*
615 	 * If we succeeded at least once, return 0.
616 	 */
617 	if (dg)
618 		return 0;
619 	return error;
620 }
621 
622 int
623 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
624     register_t *retval)
625 {
626 	/* {
627 		syscallarg(int) s;
628 		syscallarg(netbsd32_voidp) buf;
629 		syscallarg(netbsd32_size_t) len;
630 		syscallarg(int) flags;
631 		syscallarg(netbsd32_sockaddrp_t) from;
632 		syscallarg(netbsd32_intp) fromlenaddr;
633 	} */
634 	struct msghdr	msg;
635 	struct iovec	aiov;
636 	int		error;
637 	struct mbuf	*from;
638 
639 	msg.msg_name = NULL;
640 	msg.msg_iov = &aiov;
641 	msg.msg_iovlen = 1;
642 	aiov.iov_base = SCARG_P32(uap, buf);
643 	aiov.iov_len = SCARG(uap, len);
644 	msg.msg_control = NULL;
645 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
646 
647 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
648 	if (error != 0)
649 		return error;
650 
651 	error = copyout_sockname(SCARG_P32(uap, from),
652 	    SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
653 	if (from != NULL)
654 		m_free(from);
655 	return error;
656 }
657 
658 int
659 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
660     register_t *retval)
661 {
662 	/* {
663 		syscallarg(int) s;
664 		syscallarg(const netbsd32_voidp) buf;
665 		syscallarg(netbsd32_size_t) len;
666 		syscallarg(int) flags;
667 		syscallarg(const netbsd32_sockaddrp_t) to;
668 		syscallarg(int) tolen;
669 	} */
670 	struct msghdr msg;
671 	struct iovec aiov;
672 
673 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
674 	msg.msg_namelen = SCARG(uap, tolen);
675 	msg.msg_iov = &aiov;
676 	msg.msg_iovlen = 1;
677 	msg.msg_control = 0;
678 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
679 	aiov.iov_len = SCARG(uap, len);
680 	msg.msg_flags = 0;
681 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
682 	    retval);
683 }
684