Home | History | Annotate | Line # | Download | only in netbsd32
netbsd32_socket.c revision 1.44.14.1
      1 /*	$NetBSD: netbsd32_socket.c,v 1.44.14.1 2018/05/21 04:36:04 pgoyette 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.44.14.1 2018/05/21 04:36:04 pgoyette 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, MAX(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 	vlen = SCARG(uap, vlen);
    293 	if (vlen > 1024)
    294 		vlen = 1024;
    295 
    296 	from = NULL;
    297 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
    298 
    299 	for (dg = 0; dg < vlen;) {
    300 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
    301 		if (error)
    302 			break;
    303 
    304 		if ((error = msg_recv_copyin(l, msg32, msg, aiov)) != 0)
    305 			return error;
    306 
    307 		msg->msg_flags = flags & ~MSG_WAITFORONE;
    308 
    309 		if (from != NULL) {
    310 			m_free(from);
    311 			from = NULL;
    312 		}
    313 
    314 		error = do_sys_recvmsg_so(l, s, so, msg, &from,
    315 		    msg->msg_control != NULL ? &control : NULL, retval);
    316 		if (error) {
    317 			if (error == EAGAIN && dg > 0)
    318 				error = 0;
    319 			break;
    320 		}
    321 		error = msg_recv_copyout(l, msg32, msg, NULL,
    322 		    from, control);
    323 		from = NULL;
    324 		if (error)
    325 			break;
    326 
    327 		mmsg32.msg_len = *retval;
    328 
    329 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
    330 		if (error)
    331 			break;
    332 
    333 		dg++;
    334 		if (msg->msg_flags & MSG_OOB)
    335 			break;
    336 
    337 		if (SCARG_P32(uap, timeout)) {
    338 			getnanotime(&now);
    339 			timespecsub(&now, &ts, &now);
    340 			if (now.tv_sec > 0)
    341 				break;
    342 		}
    343 
    344 		if (flags & MSG_WAITFORONE)
    345 			flags |= MSG_DONTWAIT;
    346 
    347 	}
    348 
    349 	if (from != NULL)
    350 		m_free(from);
    351 
    352 	*retval = dg;
    353 	if (error)
    354 		so->so_error = error;
    355 
    356 	fd_putfile(s);
    357 
    358 	/*
    359 	 * If we succeeded at least once, return 0, hopefully so->so_error
    360 	 * will catch it next time.
    361 	 */
    362 	if (dg)
    363 		return 0;
    364 
    365 	return error;
    366 }
    367 
    368 static int
    369 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
    370 {
    371 	/*
    372 	 * Handle cmsg if there is any.
    373 	 */
    374 	struct cmsghdr *cmsg, cmsg32, *cc;
    375 	struct mbuf *ctl_mbuf;
    376 	ssize_t resid = mp->msg_controllen;
    377 	size_t clen, cidx = 0, cspace;
    378 	u_int8_t *control;
    379 	int error;
    380 
    381 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
    382 	clen = MLEN;
    383 	control = mtod(ctl_mbuf, void *);
    384 	memset(control, 0, clen);
    385 
    386 	for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
    387 	{
    388 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
    389 		if (error)
    390 			goto failure;
    391 
    392 		/*
    393 		 * Sanity check the control message length.
    394 		 */
    395 		if (cmsg32.cmsg_len > resid ||
    396 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
    397 			error = EINVAL;
    398 			goto failure;
    399 		}
    400 
    401 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
    402 
    403 		/* Check the buffer is big enough */
    404 		if (__predict_false(cidx + cspace > clen)) {
    405 			u_int8_t *nc;
    406 			size_t nclen;
    407 
    408 			nclen = cidx + cspace;
    409 			if (nclen >= PAGE_SIZE) {
    410 				error = EINVAL;
    411 				goto failure;
    412 			}
    413 			nc = realloc(clen <= MLEN ? NULL : control,
    414 				     nclen, M_TEMP, M_WAITOK);
    415 			if (!nc) {
    416 				error = ENOMEM;
    417 				goto failure;
    418 			}
    419 			if (cidx <= MLEN) {
    420 				/* Old buffer was in mbuf... */
    421 				memcpy(nc, control, cidx);
    422 				memset(nc + cidx, 0, nclen - cidx);
    423 			} else {
    424 				memset(nc + nclen, 0, nclen - clen);
    425 			}
    426 			control = nc;
    427 			clen = nclen;
    428 		}
    429 
    430 		/* Copy header */
    431 		cmsg = (void *)&control[cidx];
    432 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
    433 		cmsg->cmsg_level = cmsg32.cmsg_level;
    434 		cmsg->cmsg_type = cmsg32.cmsg_type;
    435 
    436 		/* Copyin the data */
    437 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
    438 		    cmsg32.cmsg_len - CMSG32_LEN(0));
    439 		if (error)
    440 			goto failure;
    441 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
    442 
    443 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
    444 		cidx += CMSG_ALIGN(cmsg->cmsg_len);
    445 	}
    446 
    447 	/* If we allocated a buffer, attach to mbuf */
    448 	if (cidx > MLEN) {
    449 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
    450 		ctl_mbuf->m_flags |= M_EXT_RW;
    451 	}
    452 	control = NULL;
    453 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
    454 
    455 	mp->msg_control = ctl_mbuf;
    456 	mp->msg_flags |= MSG_CONTROLMBUF;
    457 
    458 
    459 	return 0;
    460 
    461 failure:
    462 	if (control != mtod(ctl_mbuf, void *))
    463 		free(control, M_MBUF);
    464 	m_free(ctl_mbuf);
    465 	return error;
    466 }
    467 
    468 static int
    469 msg_send_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
    470     struct msghdr *msg, struct iovec *aiov)
    471 {
    472 	int error;
    473 	struct iovec *iov = aiov;
    474 	struct netbsd32_iovec *iov32;
    475 	size_t iovsz;
    476 
    477 	netbsd32_to_msghdr(msg32, msg);
    478 	msg->msg_flags = 0;
    479 
    480 	if (CMSG32_FIRSTHDR(msg)) {
    481 		error = copyin32_msg_control(l, msg);
    482 		if (error)
    483 			return error;
    484 		/* From here on, msg->msg_control is allocated */
    485 	} else {
    486 		msg->msg_control = NULL;
    487 		msg->msg_controllen = 0;
    488 	}
    489 
    490 	iovsz = msg->msg_iovlen * sizeof(struct iovec);
    491 	if ((u_int)msg->msg_iovlen > UIO_SMALLIOV) {
    492 		if ((u_int)msg->msg_iovlen > IOV_MAX) {
    493 			error = EMSGSIZE;
    494 			goto out;
    495 		}
    496 		iov = kmem_alloc(iovsz, KM_SLEEP);
    497 	}
    498 
    499 	iov32 = NETBSD32PTR64(msg32->msg_iov);
    500 	error = netbsd32_to_iovecin(iov32, iov, msg->msg_iovlen);
    501 	if (error)
    502 		goto out;
    503 	msg->msg_iov = iov;
    504 	return 0;
    505 out:
    506 	if (msg->msg_control)
    507 		m_free(msg->msg_control);
    508 	if (iov != aiov)
    509 		kmem_free(iov, iovsz);
    510 	return error;
    511 }
    512 
    513 int
    514 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
    515     register_t *retval)
    516 {
    517 	/* {
    518 		syscallarg(int) s;
    519 		syscallarg(const netbsd32_msghdrp_t) msg;
    520 		syscallarg(int) flags;
    521 	} */
    522 	struct msghdr msg;
    523 	struct netbsd32_msghdr msg32;
    524 	struct iovec aiov[UIO_SMALLIOV];
    525 	int error;
    526 
    527 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
    528 	if (error)
    529 		return error;
    530 
    531 	if ((error = msg_send_copyin(l, &msg32, &msg, aiov)) != 0)
    532 		return error;
    533 
    534 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
    535 	    retval);
    536 	/* msg.msg_control freed by do_sys_sendmsg() */
    537 
    538 	if (msg.msg_iov != aiov)
    539 		kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
    540 	return error;
    541 }
    542 
    543 int
    544 netbsd32_sendmmsg(struct lwp *l, const struct netbsd32_sendmmsg_args *uap,
    545     register_t *retval)
    546 {
    547 	/* {
    548 		syscallarg(int)			s;
    549 		syscallarg(const netbsd32_mmsghdr_t)	mmsg;
    550 		syscallarg(unsigned int)	vlen;
    551 		syscallarg(unsigned int)	flags;
    552 	} */
    553 	struct mmsghdr mmsg;
    554 	struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
    555 	struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
    556 	struct socket *so;
    557 	file_t *fp;
    558 	struct msghdr *msg = &mmsg.msg_hdr;
    559 	int error, s;
    560 	unsigned int vlen, flags, dg;
    561 	struct iovec aiov[UIO_SMALLIOV];
    562 
    563 	s = SCARG(uap, s);
    564 	if ((error = fd_getsock1(s, &so, &fp)) != 0)
    565 		return error;
    566 
    567 	vlen = SCARG(uap, vlen);
    568 	if (vlen > 1024)
    569 		vlen = 1024;
    570 
    571 	flags = SCARG(uap, flags) & MSG_USERFLAGS;
    572 
    573 	for (dg = 0; dg < vlen;) {
    574 		error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
    575 		if (error)
    576 			break;
    577 		if ((error = msg_send_copyin(l, msg32, msg, aiov)) != 0)
    578 			break;
    579 
    580 		msg->msg_flags = flags;
    581 
    582 		error = do_sys_sendmsg_so(l, s, so, fp, msg, flags, retval);
    583 		if (msg->msg_iov != aiov) {
    584 			kmem_free(msg->msg_iov,
    585 			    msg->msg_iovlen * sizeof(struct iovec));
    586 		}
    587 		if (error)
    588 			break;
    589 
    590 		ktrkuser("msghdr", msg, sizeof(*msg));
    591 		mmsg.msg_len = *retval;
    592 		netbsd32_from_mmsghdr(&mmsg32, &mmsg);
    593 		error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
    594 		if (error)
    595 			break;
    596 		dg++;
    597 	}
    598 
    599 	*retval = dg;
    600 	if (error)
    601 		so->so_error = error;
    602 
    603 	fd_putfile(s);
    604 
    605 	/*
    606 	 * If we succeeded at least once, return 0, hopefully so->so_error
    607 	 * will catch it next time.
    608 	 */
    609 	if (dg)
    610 		return 0;
    611 	return error;
    612 }
    613 
    614 int
    615 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
    616     register_t *retval)
    617 {
    618 	/* {
    619 		syscallarg(int) s;
    620 		syscallarg(netbsd32_voidp) buf;
    621 		syscallarg(netbsd32_size_t) len;
    622 		syscallarg(int) flags;
    623 		syscallarg(netbsd32_sockaddrp_t) from;
    624 		syscallarg(netbsd32_intp) fromlenaddr;
    625 	} */
    626 	struct msghdr	msg;
    627 	struct iovec	aiov;
    628 	int		error;
    629 	struct mbuf	*from;
    630 
    631 	msg.msg_name = NULL;
    632 	msg.msg_iov = &aiov;
    633 	msg.msg_iovlen = 1;
    634 	aiov.iov_base = SCARG_P32(uap, buf);
    635 	aiov.iov_len = SCARG(uap, len);
    636 	msg.msg_control = NULL;
    637 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
    638 
    639 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
    640 	if (error != 0)
    641 		return error;
    642 
    643 	error = copyout_sockname(SCARG_P32(uap, from),
    644 	    SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
    645 	if (from != NULL)
    646 		m_free(from);
    647 	return error;
    648 }
    649 
    650 int
    651 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
    652     register_t *retval)
    653 {
    654 	/* {
    655 		syscallarg(int) s;
    656 		syscallarg(const netbsd32_voidp) buf;
    657 		syscallarg(netbsd32_size_t) len;
    658 		syscallarg(int) flags;
    659 		syscallarg(const netbsd32_sockaddrp_t) to;
    660 		syscallarg(int) tolen;
    661 	} */
    662 	struct msghdr msg;
    663 	struct iovec aiov;
    664 
    665 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
    666 	msg.msg_namelen = SCARG(uap, tolen);
    667 	msg.msg_iov = &aiov;
    668 	msg.msg_iovlen = 1;
    669 	msg.msg_control = 0;
    670 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
    671 	aiov.iov_len = SCARG(uap, len);
    672 	msg.msg_flags = 0;
    673 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
    674 	    retval);
    675 }
    676