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