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