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