1 /* $OpenBSD: uipc_syscalls.c,v 1.91 2014/07/13 15:00:40 tedu Exp $ */ 2 /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/filedesc.h> 38 #include <sys/proc.h> 39 #include <sys/file.h> 40 #include <sys/buf.h> 41 #include <sys/malloc.h> 42 #include <sys/event.h> 43 #include <sys/mbuf.h> 44 #include <sys/protosw.h> 45 #include <sys/socket.h> 46 #include <sys/socketvar.h> 47 #include <sys/signalvar.h> 48 #include <sys/unpcb.h> 49 #include <sys/un.h> 50 #ifdef KTRACE 51 #include <sys/ktrace.h> 52 #endif 53 54 #include <sys/mount.h> 55 #include <sys/syscallargs.h> 56 57 #include <net/route.h> 58 59 /* 60 * System call interface to the socket abstraction. 61 */ 62 extern struct fileops socketops; 63 64 int copyaddrout(struct proc *, struct mbuf *, struct sockaddr *, socklen_t, 65 socklen_t *); 66 67 int 68 sys_socket(struct proc *p, void *v, register_t *retval) 69 { 70 struct sys_socket_args /* { 71 syscallarg(int) domain; 72 syscallarg(int) type; 73 syscallarg(int) protocol; 74 } */ *uap = v; 75 struct filedesc *fdp = p->p_fd; 76 struct socket *so; 77 struct file *fp; 78 int fd, error; 79 80 fdplock(fdp); 81 error = falloc(p, &fp, &fd); 82 fdpunlock(fdp); 83 if (error != 0) 84 goto out; 85 86 fp->f_flag = FREAD|FWRITE; 87 fp->f_type = DTYPE_SOCKET; 88 fp->f_ops = &socketops; 89 error = socreate(SCARG(uap, domain), &so, SCARG(uap, type), 90 SCARG(uap, protocol)); 91 if (error) { 92 fdplock(fdp); 93 fdremove(fdp, fd); 94 closef(fp, p); 95 fdpunlock(fdp); 96 } else { 97 fp->f_data = so; 98 FILE_SET_MATURE(fp, p); 99 *retval = fd; 100 } 101 out: 102 return (error); 103 } 104 105 /* ARGSUSED */ 106 int 107 sys_bind(struct proc *p, void *v, register_t *retval) 108 { 109 struct sys_bind_args /* { 110 syscallarg(int) s; 111 syscallarg(const struct sockaddr *) name; 112 syscallarg(socklen_t) namelen; 113 } */ *uap = v; 114 struct file *fp; 115 struct mbuf *nam; 116 int error; 117 118 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 119 return (error); 120 error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), 121 MT_SONAME); 122 if (error == 0) { 123 #ifdef KTRACE 124 if (KTRPOINT(p, KTR_STRUCT)) 125 ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); 126 #endif 127 error = sobind(fp->f_data, nam, p); 128 m_freem(nam); 129 } 130 FRELE(fp, p); 131 return (error); 132 } 133 134 /* ARGSUSED */ 135 int 136 sys_listen(struct proc *p, void *v, register_t *retval) 137 { 138 struct sys_listen_args /* { 139 syscallarg(int) s; 140 syscallarg(int) backlog; 141 } */ *uap = v; 142 struct file *fp; 143 int error; 144 145 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 146 return (error); 147 error = solisten(fp->f_data, SCARG(uap, backlog)); 148 FRELE(fp, p); 149 return (error); 150 } 151 152 int 153 sys_accept(struct proc *p, void *v, register_t *retval) 154 { 155 struct sys_accept_args /* { 156 syscallarg(int) s; 157 syscallarg(struct sockaddr *) name; 158 syscallarg(socklen_t *) anamelen; 159 } */ *uap = v; 160 struct file *fp, *headfp; 161 struct mbuf *nam; 162 socklen_t namelen; 163 int error, s, tmpfd; 164 struct socket *head, *so; 165 int nflag; 166 167 if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen), 168 &namelen, sizeof (namelen)))) 169 return (error); 170 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 171 return (error); 172 headfp = fp; 173 s = splsoftnet(); 174 head = fp->f_data; 175 redo: 176 if ((head->so_options & SO_ACCEPTCONN) == 0) { 177 error = EINVAL; 178 goto bad; 179 } 180 if ((head->so_state & SS_NBIO) && head->so_qlen == 0) { 181 if (head->so_state & SS_CANTRCVMORE) 182 error = ECONNABORTED; 183 else 184 error = EWOULDBLOCK; 185 goto bad; 186 } 187 while (head->so_qlen == 0 && head->so_error == 0) { 188 if (head->so_state & SS_CANTRCVMORE) { 189 head->so_error = ECONNABORTED; 190 break; 191 } 192 error = tsleep(&head->so_timeo, PSOCK | PCATCH, "netcon", 0); 193 if (error) { 194 goto bad; 195 } 196 } 197 if (head->so_error) { 198 error = head->so_error; 199 head->so_error = 0; 200 goto bad; 201 } 202 203 /* Take note if socket was non-blocking. */ 204 nflag = (headfp->f_flag & FNONBLOCK); 205 206 fdplock(p->p_fd); 207 error = falloc(p, &fp, &tmpfd); 208 fdpunlock(p->p_fd); 209 if (error != 0) { 210 /* 211 * Probably ran out of file descriptors. Wakeup 212 * so some other process might have a chance at it. 213 */ 214 wakeup_one(&head->so_timeo); 215 goto bad; 216 } 217 218 nam = m_get(M_WAIT, MT_SONAME); 219 220 /* 221 * Check whether the queue emptied while we slept: falloc() or 222 * m_get() may have blocked, allowing the connection to be reset 223 * or another thread or process to accept it. If so, start over. 224 */ 225 if (head->so_qlen == 0) { 226 m_freem(nam); 227 fdplock(p->p_fd); 228 fdremove(p->p_fd, tmpfd); 229 closef(fp, p); 230 fdpunlock(p->p_fd); 231 goto redo; 232 } 233 234 /* 235 * Do not sleep after we have taken the socket out of the queue. 236 */ 237 so = TAILQ_FIRST(&head->so_q); 238 if (soqremque(so, 1) == 0) 239 panic("accept"); 240 241 /* connection has been removed from the listen queue */ 242 KNOTE(&head->so_rcv.sb_sel.si_note, 0); 243 244 fp->f_type = DTYPE_SOCKET; 245 fp->f_flag = FREAD | FWRITE | nflag; 246 fp->f_ops = &socketops; 247 fp->f_data = so; 248 error = soaccept(so, nam); 249 if (!error && SCARG(uap, name)) { 250 error = copyaddrout(p, nam, SCARG(uap, name), namelen, 251 SCARG(uap, anamelen)); 252 } 253 254 if (error) { 255 /* if an error occurred, free the file descriptor */ 256 fdplock(p->p_fd); 257 fdremove(p->p_fd, tmpfd); 258 closef(fp, p); 259 fdpunlock(p->p_fd); 260 } else { 261 FILE_SET_MATURE(fp, p); 262 *retval = tmpfd; 263 } 264 m_freem(nam); 265 bad: 266 splx(s); 267 FRELE(headfp, p); 268 return (error); 269 } 270 271 /* ARGSUSED */ 272 int 273 sys_connect(struct proc *p, void *v, register_t *retval) 274 { 275 struct sys_connect_args /* { 276 syscallarg(int) s; 277 syscallarg(const struct sockaddr *) name; 278 syscallarg(socklen_t) namelen; 279 } */ *uap = v; 280 struct file *fp; 281 struct socket *so; 282 struct mbuf *nam = NULL; 283 int error, s; 284 285 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 286 return (error); 287 so = fp->f_data; 288 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { 289 FRELE(fp, p); 290 return (EALREADY); 291 } 292 error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), 293 MT_SONAME); 294 if (error) 295 goto bad; 296 #ifdef KTRACE 297 if (KTRPOINT(p, KTR_STRUCT)) 298 ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); 299 #endif 300 error = soconnect(so, nam); 301 if (error) 302 goto bad; 303 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { 304 FRELE(fp, p); 305 m_freem(nam); 306 return (EINPROGRESS); 307 } 308 s = splsoftnet(); 309 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 310 error = tsleep(&so->so_timeo, PSOCK | PCATCH, "netcon2", 0); 311 if (error) 312 break; 313 } 314 if (error == 0) { 315 error = so->so_error; 316 so->so_error = 0; 317 } 318 splx(s); 319 bad: 320 so->so_state &= ~SS_ISCONNECTING; 321 FRELE(fp, p); 322 if (nam) 323 m_freem(nam); 324 if (error == ERESTART) 325 error = EINTR; 326 return (error); 327 } 328 329 int 330 sys_socketpair(struct proc *p, void *v, register_t *retval) 331 { 332 struct sys_socketpair_args /* { 333 syscallarg(int) domain; 334 syscallarg(int) type; 335 syscallarg(int) protocol; 336 syscallarg(int *) rsv; 337 } */ *uap = v; 338 struct filedesc *fdp = p->p_fd; 339 struct file *fp1, *fp2; 340 struct socket *so1, *so2; 341 int fd, error, sv[2]; 342 343 error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type), 344 SCARG(uap, protocol)); 345 if (error) 346 return (error); 347 error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type), 348 SCARG(uap, protocol)); 349 if (error) 350 goto free1; 351 352 fdplock(fdp); 353 if ((error = falloc(p, &fp1, &fd)) != 0) 354 goto free2; 355 sv[0] = fd; 356 fp1->f_flag = FREAD|FWRITE; 357 fp1->f_type = DTYPE_SOCKET; 358 fp1->f_ops = &socketops; 359 fp1->f_data = so1; 360 if ((error = falloc(p, &fp2, &fd)) != 0) 361 goto free3; 362 fp2->f_flag = FREAD|FWRITE; 363 fp2->f_type = DTYPE_SOCKET; 364 fp2->f_ops = &socketops; 365 fp2->f_data = so2; 366 sv[1] = fd; 367 if ((error = soconnect2(so1, so2)) != 0) 368 goto free4; 369 if (SCARG(uap, type) == SOCK_DGRAM) { 370 /* 371 * Datagram socket connection is asymmetric. 372 */ 373 if ((error = soconnect2(so2, so1)) != 0) 374 goto free4; 375 } 376 error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int)); 377 if (error == 0) { 378 FILE_SET_MATURE(fp1, p); 379 FILE_SET_MATURE(fp2, p); 380 fdpunlock(fdp); 381 return (0); 382 } 383 free4: 384 fdremove(fdp, sv[1]); 385 closef(fp2, p); 386 so2 = NULL; 387 free3: 388 fdremove(fdp, sv[0]); 389 closef(fp1, p); 390 so1 = NULL; 391 free2: 392 if (so2 != NULL) 393 (void)soclose(so2); 394 fdpunlock(fdp); 395 free1: 396 if (so1 != NULL) 397 (void)soclose(so1); 398 return (error); 399 } 400 401 int 402 sys_sendto(struct proc *p, void *v, register_t *retval) 403 { 404 struct sys_sendto_args /* { 405 syscallarg(int) s; 406 syscallarg(const void *) buf; 407 syscallarg(size_t) len; 408 syscallarg(int) flags; 409 syscallarg(const struct sockaddr *) to; 410 syscallarg(socklen_t) tolen; 411 } */ *uap = v; 412 struct msghdr msg; 413 struct iovec aiov; 414 415 msg.msg_name = (caddr_t)SCARG(uap, to); 416 msg.msg_namelen = SCARG(uap, tolen); 417 msg.msg_iov = &aiov; 418 msg.msg_iovlen = 1; 419 msg.msg_control = 0; 420 msg.msg_flags = 0; 421 aiov.iov_base = (char *)SCARG(uap, buf); 422 aiov.iov_len = SCARG(uap, len); 423 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); 424 } 425 426 int 427 sys_sendmsg(struct proc *p, void *v, register_t *retval) 428 { 429 struct sys_sendmsg_args /* { 430 syscallarg(int) s; 431 syscallarg(const struct msghdr *) msg; 432 syscallarg(int) flags; 433 } */ *uap = v; 434 struct msghdr msg; 435 struct iovec aiov[UIO_SMALLIOV], *iov; 436 int error; 437 438 error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); 439 if (error) 440 return (error); 441 if (msg.msg_iovlen > IOV_MAX) 442 return (EMSGSIZE); 443 if (msg.msg_iovlen > UIO_SMALLIOV) 444 iov = malloc(sizeof(struct iovec) * msg.msg_iovlen, 445 M_IOV, M_WAITOK); 446 else 447 iov = aiov; 448 if (msg.msg_iovlen && 449 (error = copyin(msg.msg_iov, iov, 450 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))) 451 goto done; 452 msg.msg_iov = iov; 453 msg.msg_flags = 0; 454 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 455 done: 456 if (iov != aiov) 457 free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen); 458 return (error); 459 } 460 461 int 462 sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize) 463 { 464 struct file *fp; 465 struct uio auio; 466 struct iovec *iov; 467 int i; 468 struct mbuf *to, *control; 469 size_t len; 470 int error; 471 #ifdef KTRACE 472 struct iovec *ktriov = NULL; 473 int iovlen = 0; 474 #endif 475 476 to = NULL; 477 478 if ((error = getsock(p->p_fd, s, &fp)) != 0) 479 return (error); 480 auio.uio_iov = mp->msg_iov; 481 auio.uio_iovcnt = mp->msg_iovlen; 482 auio.uio_segflg = UIO_USERSPACE; 483 auio.uio_rw = UIO_WRITE; 484 auio.uio_procp = p; 485 auio.uio_offset = 0; /* XXX */ 486 auio.uio_resid = 0; 487 iov = mp->msg_iov; 488 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 489 /* Don't allow sum > SSIZE_MAX */ 490 if (iov->iov_len > SSIZE_MAX || 491 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { 492 error = EINVAL; 493 goto bad; 494 } 495 } 496 if (mp->msg_name) { 497 error = sockargs(&to, mp->msg_name, mp->msg_namelen, 498 MT_SONAME); 499 if (error) 500 goto bad; 501 #ifdef KTRACE 502 if (KTRPOINT(p, KTR_STRUCT)) 503 ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen); 504 #endif 505 } 506 if (mp->msg_control) { 507 if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) { 508 error = EINVAL; 509 goto bad; 510 } 511 error = sockargs(&control, mp->msg_control, 512 mp->msg_controllen, MT_CONTROL); 513 if (error) 514 goto bad; 515 } else 516 control = 0; 517 #ifdef KTRACE 518 if (KTRPOINT(p, KTR_GENIO)) { 519 iovlen = auio.uio_iovcnt * sizeof (struct iovec); 520 521 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 522 bcopy(auio.uio_iov, ktriov, iovlen); 523 } 524 #endif 525 len = auio.uio_resid; 526 error = sosend(fp->f_data, to, &auio, NULL, control, flags); 527 if (error) { 528 if (auio.uio_resid != len && (error == ERESTART || 529 error == EINTR || error == EWOULDBLOCK)) 530 error = 0; 531 if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) 532 ptsignal(p, SIGPIPE, STHREAD); 533 } 534 if (error == 0) { 535 *retsize = len - auio.uio_resid; 536 fp->f_wxfer++; 537 fp->f_wbytes += *retsize; 538 } 539 #ifdef KTRACE 540 if (ktriov != NULL) { 541 if (error == 0) 542 ktrgenio(p, s, UIO_WRITE, ktriov, *retsize); 543 free(ktriov, M_TEMP, iovlen); 544 } 545 #endif 546 bad: 547 FRELE(fp, p); 548 if (to) 549 m_freem(to); 550 return (error); 551 } 552 553 int 554 sys_recvfrom(struct proc *p, void *v, register_t *retval) 555 { 556 struct sys_recvfrom_args /* { 557 syscallarg(int) s; 558 syscallarg(void *) buf; 559 syscallarg(size_t) len; 560 syscallarg(int) flags; 561 syscallarg(struct sockaddr *) from; 562 syscallarg(socklen_t *) fromlenaddr; 563 } */ *uap = v; 564 struct msghdr msg; 565 struct iovec aiov; 566 int error; 567 568 if (SCARG(uap, fromlenaddr)) { 569 error = copyin(SCARG(uap, fromlenaddr), 570 &msg.msg_namelen, sizeof (msg.msg_namelen)); 571 if (error) 572 return (error); 573 } else 574 msg.msg_namelen = 0; 575 msg.msg_name = (caddr_t)SCARG(uap, from); 576 msg.msg_iov = &aiov; 577 msg.msg_iovlen = 1; 578 aiov.iov_base = SCARG(uap, buf); 579 aiov.iov_len = SCARG(uap, len); 580 msg.msg_control = 0; 581 msg.msg_flags = SCARG(uap, flags); 582 return (recvit(p, SCARG(uap, s), &msg, 583 (caddr_t)SCARG(uap, fromlenaddr), retval)); 584 } 585 586 int 587 sys_recvmsg(struct proc *p, void *v, register_t *retval) 588 { 589 struct sys_recvmsg_args /* { 590 syscallarg(int) s; 591 syscallarg(struct msghdr *) msg; 592 syscallarg(int) flags; 593 } */ *uap = v; 594 struct msghdr msg; 595 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; 596 int error; 597 598 error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); 599 if (error) 600 return (error); 601 if (msg.msg_iovlen > IOV_MAX) 602 return (EMSGSIZE); 603 if (msg.msg_iovlen > UIO_SMALLIOV) 604 iov = malloc(sizeof(struct iovec) * msg.msg_iovlen, 605 M_IOV, M_WAITOK); 606 else 607 iov = aiov; 608 msg.msg_flags = SCARG(uap, flags); 609 if (msg.msg_iovlen > 0) { 610 error = copyin(msg.msg_iov, iov, 611 msg.msg_iovlen * sizeof(struct iovec)); 612 if (error) 613 goto done; 614 } 615 uiov = msg.msg_iov; 616 msg.msg_iov = iov; 617 if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) { 618 msg.msg_iov = uiov; 619 error = copyout(&msg, SCARG(uap, msg), sizeof(msg)); 620 } 621 done: 622 if (iov != aiov) 623 free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen); 624 return (error); 625 } 626 627 int 628 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, 629 register_t *retsize) 630 { 631 struct file *fp; 632 struct uio auio; 633 struct iovec *iov; 634 int i; 635 size_t len; 636 int error; 637 struct mbuf *from = NULL, *control = NULL; 638 #ifdef KTRACE 639 struct iovec *ktriov = NULL; 640 int iovlen = 0; 641 #endif 642 643 if ((error = getsock(p->p_fd, s, &fp)) != 0) 644 return (error); 645 auio.uio_iov = mp->msg_iov; 646 auio.uio_iovcnt = mp->msg_iovlen; 647 auio.uio_segflg = UIO_USERSPACE; 648 auio.uio_rw = UIO_READ; 649 auio.uio_procp = p; 650 auio.uio_offset = 0; /* XXX */ 651 auio.uio_resid = 0; 652 iov = mp->msg_iov; 653 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 654 /* Don't allow sum > SSIZE_MAX */ 655 if (iov->iov_len > SSIZE_MAX || 656 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { 657 error = EINVAL; 658 goto out; 659 } 660 } 661 #ifdef KTRACE 662 if (KTRPOINT(p, KTR_GENIO)) { 663 iovlen = auio.uio_iovcnt * sizeof (struct iovec); 664 665 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 666 bcopy(auio.uio_iov, ktriov, iovlen); 667 } 668 #endif 669 len = auio.uio_resid; 670 error = soreceive(fp->f_data, &from, &auio, NULL, 671 mp->msg_control ? &control : NULL, 672 &mp->msg_flags, 673 mp->msg_control ? mp->msg_controllen : 0); 674 if (error) { 675 if (auio.uio_resid != len && (error == ERESTART || 676 error == EINTR || error == EWOULDBLOCK)) 677 error = 0; 678 } 679 #ifdef KTRACE 680 if (ktriov != NULL) { 681 if (error == 0) 682 ktrgenio(p, s, UIO_READ, ktriov, len - auio.uio_resid); 683 free(ktriov, M_TEMP, iovlen); 684 } 685 #endif 686 if (error) 687 goto out; 688 *retsize = len - auio.uio_resid; 689 if (mp->msg_name) { 690 socklen_t alen; 691 692 if (from == NULL) 693 alen = 0; 694 else { 695 alen = from->m_len; 696 error = copyout(mtod(from, caddr_t), mp->msg_name, 697 MIN(alen, mp->msg_namelen)); 698 if (error) 699 goto out; 700 #ifdef KTRACE 701 if (KTRPOINT(p, KTR_STRUCT)) 702 ktrsockaddr(p, mtod(from, caddr_t), alen); 703 #endif 704 } 705 mp->msg_namelen = alen; 706 if (namelenp && 707 (error = copyout(&alen, namelenp, sizeof(alen)))) { 708 goto out; 709 } 710 } 711 if (mp->msg_control) { 712 len = mp->msg_controllen; 713 if (len <= 0 || control == NULL) 714 len = 0; 715 else { 716 struct mbuf *m = control; 717 caddr_t p = mp->msg_control; 718 719 do { 720 i = m->m_len; 721 if (len < i) { 722 mp->msg_flags |= MSG_CTRUNC; 723 i = len; 724 } 725 error = copyout(mtod(m, caddr_t), p, i); 726 if (m->m_next) 727 i = ALIGN(i); 728 p += i; 729 len -= i; 730 if (error != 0 || len <= 0) 731 break; 732 } while ((m = m->m_next) != NULL); 733 len = p - (caddr_t)mp->msg_control; 734 } 735 mp->msg_controllen = len; 736 } 737 if (!error) { 738 fp->f_rxfer++; 739 fp->f_rbytes += *retsize; 740 } 741 out: 742 FRELE(fp, p); 743 if (from) 744 m_freem(from); 745 if (control) 746 m_freem(control); 747 return (error); 748 } 749 750 /* ARGSUSED */ 751 int 752 sys_shutdown(struct proc *p, void *v, register_t *retval) 753 { 754 struct sys_shutdown_args /* { 755 syscallarg(int) s; 756 syscallarg(int) how; 757 } */ *uap = v; 758 struct file *fp; 759 int error; 760 761 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 762 return (error); 763 error = soshutdown(fp->f_data, SCARG(uap, how)); 764 FRELE(fp, p); 765 return (error); 766 } 767 768 /* ARGSUSED */ 769 int 770 sys_setsockopt(struct proc *p, void *v, register_t *retval) 771 { 772 struct sys_setsockopt_args /* { 773 syscallarg(int) s; 774 syscallarg(int) level; 775 syscallarg(int) name; 776 syscallarg(const void *) val; 777 syscallarg(socklen_t) valsize; 778 } */ *uap = v; 779 struct file *fp; 780 struct mbuf *m = NULL; 781 int error; 782 783 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 784 return (error); 785 if (SCARG(uap, valsize) > MCLBYTES) { 786 error = EINVAL; 787 goto bad; 788 } 789 if (SCARG(uap, val)) { 790 m = m_get(M_WAIT, MT_SOOPTS); 791 if (SCARG(uap, valsize) > MLEN) { 792 MCLGET(m, M_DONTWAIT); 793 if ((m->m_flags & M_EXT) == 0) { 794 error = ENOBUFS; 795 goto bad; 796 } 797 } 798 if (m == NULL) { 799 error = ENOBUFS; 800 goto bad; 801 } 802 error = copyin(SCARG(uap, val), mtod(m, caddr_t), 803 SCARG(uap, valsize)); 804 if (error) { 805 goto bad; 806 } 807 m->m_len = SCARG(uap, valsize); 808 } 809 error = sosetopt(fp->f_data, SCARG(uap, level), SCARG(uap, name), m); 810 m = NULL; 811 bad: 812 if (m) 813 m_freem(m); 814 FRELE(fp, p); 815 return (error); 816 } 817 818 /* ARGSUSED */ 819 int 820 sys_getsockopt(struct proc *p, void *v, register_t *retval) 821 { 822 struct sys_getsockopt_args /* { 823 syscallarg(int) s; 824 syscallarg(int) level; 825 syscallarg(int) name; 826 syscallarg(void *) val; 827 syscallarg(socklen_t *) avalsize; 828 } */ *uap = v; 829 struct file *fp; 830 struct mbuf *m = NULL; 831 socklen_t valsize; 832 int error; 833 834 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 835 return (error); 836 if (SCARG(uap, val)) { 837 error = copyin(SCARG(uap, avalsize), 838 &valsize, sizeof (valsize)); 839 if (error) 840 goto out; 841 } else 842 valsize = 0; 843 if ((error = sogetopt(fp->f_data, SCARG(uap, level), 844 SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize && 845 m != NULL) { 846 if (valsize > m->m_len) 847 valsize = m->m_len; 848 error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize); 849 if (error == 0) 850 error = copyout(&valsize, 851 SCARG(uap, avalsize), sizeof (valsize)); 852 } 853 out: 854 FRELE(fp, p); 855 if (m != NULL) 856 (void)m_free(m); 857 return (error); 858 } 859 860 /* 861 * Get socket name. 862 */ 863 /* ARGSUSED */ 864 int 865 sys_getsockname(struct proc *p, void *v, register_t *retval) 866 { 867 struct sys_getsockname_args /* { 868 syscallarg(int) fdes; 869 syscallarg(struct sockaddr *) asa; 870 syscallarg(socklen_t *) alen; 871 } */ *uap = v; 872 struct file *fp; 873 struct socket *so; 874 struct mbuf *m = NULL; 875 socklen_t len; 876 int error; 877 878 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) 879 return (error); 880 error = copyin(SCARG(uap, alen), &len, sizeof (len)); 881 if (error) 882 goto bad; 883 so = fp->f_data; 884 m = m_getclr(M_WAIT, MT_SONAME); 885 error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p); 886 if (error) 887 goto bad; 888 error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); 889 bad: 890 FRELE(fp, p); 891 if (m) 892 m_freem(m); 893 return (error); 894 } 895 896 /* 897 * Get name of peer for connected socket. 898 */ 899 /* ARGSUSED */ 900 int 901 sys_getpeername(struct proc *p, void *v, register_t *retval) 902 { 903 struct sys_getpeername_args /* { 904 syscallarg(int) fdes; 905 syscallarg(struct sockaddr *) asa; 906 syscallarg(socklen_t *) alen; 907 } */ *uap = v; 908 struct file *fp; 909 struct socket *so; 910 struct mbuf *m = NULL; 911 socklen_t len; 912 int error; 913 914 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) 915 return (error); 916 so = fp->f_data; 917 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { 918 FRELE(fp, p); 919 return (ENOTCONN); 920 } 921 error = copyin(SCARG(uap, alen), &len, sizeof (len)); 922 if (error) 923 goto bad; 924 m = m_getclr(M_WAIT, MT_SONAME); 925 error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p); 926 if (error) 927 goto bad; 928 error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); 929 bad: 930 FRELE(fp, p); 931 m_freem(m); 932 return (error); 933 } 934 935 int 936 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type) 937 { 938 struct sockaddr *sa; 939 struct mbuf *m; 940 int error; 941 942 /* 943 * We can't allow socket names > UCHAR_MAX in length, since that 944 * will overflow sa_len. Also, control data more than MCLBYTES in 945 * length is just too much. 946 */ 947 if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES)) 948 return (EINVAL); 949 950 /* Allocate an mbuf to hold the arguments. */ 951 m = m_get(M_WAIT, type); 952 if ((u_int)buflen > MLEN) { 953 MCLGET(m, M_WAITOK); 954 if ((m->m_flags & M_EXT) == 0) { 955 m_free(m); 956 return ENOBUFS; 957 } 958 } 959 m->m_len = buflen; 960 error = copyin(buf, mtod(m, caddr_t), buflen); 961 if (error) { 962 (void) m_free(m); 963 return (error); 964 } 965 *mp = m; 966 if (type == MT_SONAME) { 967 sa = mtod(m, struct sockaddr *); 968 #if BYTE_ORDER != BIG_ENDIAN 969 if (sa->sa_family == 0 && sa->sa_len < AF_MAX) 970 sa->sa_family = sa->sa_len; 971 #endif 972 sa->sa_len = buflen; 973 } 974 return (0); 975 } 976 977 int 978 getsock(struct filedesc *fdp, int fdes, struct file **fpp) 979 { 980 struct file *fp; 981 982 if ((fp = fd_getfile(fdp, fdes)) == NULL) 983 return (EBADF); 984 if (fp->f_type != DTYPE_SOCKET) 985 return (ENOTSOCK); 986 *fpp = fp; 987 FREF(fp); 988 989 return (0); 990 } 991 992 /* ARGSUSED */ 993 int 994 sys_setrtable(struct proc *p, void *v, register_t *retval) 995 { 996 struct sys_setrtable_args /* { 997 syscallarg(int) rtableid; 998 } */ *uap = v; 999 int rtableid, error; 1000 1001 rtableid = SCARG(uap, rtableid); 1002 1003 if (p->p_p->ps_rtableid == (u_int)rtableid) 1004 return (0); 1005 if (p->p_p->ps_rtableid != 0 && (error = suser(p, 0)) != 0) 1006 return (error); 1007 if (rtableid < 0 || !rtable_exists((u_int)rtableid)) 1008 return (EINVAL); 1009 1010 p->p_p->ps_rtableid = (u_int)rtableid; 1011 return (0); 1012 } 1013 1014 /* ARGSUSED */ 1015 int 1016 sys_getrtable(struct proc *p, void *v, register_t *retval) 1017 { 1018 *retval = (int)p->p_p->ps_rtableid; 1019 return (0); 1020 } 1021 1022 int 1023 copyaddrout(struct proc *p, struct mbuf *name, struct sockaddr *sa, 1024 socklen_t buflen, socklen_t *outlen) 1025 { 1026 int error; 1027 socklen_t namelen = name->m_len; 1028 1029 /* SHOULD COPY OUT A CHAIN HERE */ 1030 error = copyout(mtod(name, caddr_t), sa, MIN(buflen, namelen)); 1031 if (error == 0) { 1032 #ifdef KTRACE 1033 if (KTRPOINT(p, KTR_STRUCT)) 1034 ktrsockaddr(p, mtod(name, caddr_t), namelen); 1035 #endif 1036 error = copyout(&namelen, outlen, sizeof(*outlen)); 1037 } 1038 1039 return (error); 1040 } 1041