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