1 /* $OpenBSD: uipc_syscalls.c,v 1.86 2012/05/06 20:25:27 matthew 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 if ((head->so_options & SO_ACCEPTCONN) == 0) { 176 error = EINVAL; 177 goto bad; 178 } 179 if ((head->so_state & SS_NBIO) && head->so_qlen == 0) { 180 if (head->so_state & SS_CANTRCVMORE) 181 error = ECONNABORTED; 182 else 183 error = EWOULDBLOCK; 184 goto bad; 185 } 186 while (head->so_qlen == 0 && head->so_error == 0) { 187 if (head->so_state & SS_CANTRCVMORE) { 188 head->so_error = ECONNABORTED; 189 break; 190 } 191 error = tsleep(&head->so_timeo, PSOCK | PCATCH, "netcon", 0); 192 if (error) { 193 goto bad; 194 } 195 } 196 if (head->so_error) { 197 error = head->so_error; 198 head->so_error = 0; 199 goto bad; 200 } 201 202 /* 203 * At this point we know that there is at least one connection 204 * ready to be accepted. Remove it from the queue prior to 205 * allocating the file descriptor for it since falloc() may 206 * block allowing another process to accept the connection 207 * instead. 208 */ 209 so = TAILQ_FIRST(&head->so_q); 210 if (soqremque(so, 1) == 0) 211 panic("accept"); 212 213 /* Take note if socket was non-blocking. */ 214 nflag = (fp->f_flag & FNONBLOCK); 215 216 fdplock(p->p_fd); 217 error = falloc(p, &fp, &tmpfd); 218 fdpunlock(p->p_fd); 219 if (error != 0) { 220 /* 221 * Probably ran out of file descriptors. Put the 222 * unaccepted connection back onto the queue and 223 * do another wakeup so some other process might 224 * have a chance at it. 225 */ 226 soqinsque(head, so, 1); 227 wakeup_one(&head->so_timeo); 228 goto bad; 229 } 230 231 /* connection has been removed from the listen queue */ 232 KNOTE(&head->so_rcv.sb_sel.si_note, 0); 233 234 fp->f_type = DTYPE_SOCKET; 235 fp->f_flag = FREAD | FWRITE | nflag; 236 fp->f_ops = &socketops; 237 fp->f_data = so; 238 nam = m_get(M_WAIT, MT_SONAME); 239 error = soaccept(so, nam); 240 if (!error && SCARG(uap, name)) { 241 error = copyaddrout(p, nam, SCARG(uap, name), namelen, 242 SCARG(uap, anamelen)); 243 } 244 245 if (error) { 246 /* if an error occurred, free the file descriptor */ 247 fdplock(p->p_fd); 248 fdremove(p->p_fd, tmpfd); 249 closef(fp, p); 250 fdpunlock(p->p_fd); 251 } else { 252 FILE_SET_MATURE(fp, p); 253 *retval = tmpfd; 254 } 255 m_freem(nam); 256 bad: 257 splx(s); 258 FRELE(headfp, p); 259 return (error); 260 } 261 262 /* ARGSUSED */ 263 int 264 sys_connect(struct proc *p, void *v, register_t *retval) 265 { 266 struct sys_connect_args /* { 267 syscallarg(int) s; 268 syscallarg(const struct sockaddr *) name; 269 syscallarg(socklen_t) namelen; 270 } */ *uap = v; 271 struct file *fp; 272 struct socket *so; 273 struct mbuf *nam = NULL; 274 int error, s; 275 276 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 277 return (error); 278 so = fp->f_data; 279 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { 280 FRELE(fp, p); 281 return (EALREADY); 282 } 283 error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), 284 MT_SONAME); 285 if (error) 286 goto bad; 287 #ifdef KTRACE 288 if (KTRPOINT(p, KTR_STRUCT)) 289 ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); 290 #endif 291 error = soconnect(so, nam); 292 if (error) 293 goto bad; 294 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { 295 FRELE(fp, p); 296 m_freem(nam); 297 return (EINPROGRESS); 298 } 299 s = splsoftnet(); 300 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 301 error = tsleep(&so->so_timeo, PSOCK | PCATCH, 302 "netcon2", 0); 303 if (error) 304 break; 305 } 306 if (error == 0) { 307 error = so->so_error; 308 so->so_error = 0; 309 } 310 splx(s); 311 bad: 312 so->so_state &= ~SS_ISCONNECTING; 313 FRELE(fp, p); 314 if (nam) 315 m_freem(nam); 316 if (error == ERESTART) 317 error = EINTR; 318 return (error); 319 } 320 321 int 322 sys_socketpair(struct proc *p, void *v, register_t *retval) 323 { 324 struct sys_socketpair_args /* { 325 syscallarg(int) domain; 326 syscallarg(int) type; 327 syscallarg(int) protocol; 328 syscallarg(int *) rsv; 329 } */ *uap = v; 330 struct filedesc *fdp = p->p_fd; 331 struct file *fp1, *fp2; 332 struct socket *so1, *so2; 333 int fd, error, sv[2]; 334 335 error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type), 336 SCARG(uap, protocol)); 337 if (error) 338 return (error); 339 error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type), 340 SCARG(uap, protocol)); 341 if (error) 342 goto free1; 343 344 fdplock(fdp); 345 if ((error = falloc(p, &fp1, &fd)) != 0) 346 goto free2; 347 sv[0] = fd; 348 fp1->f_flag = FREAD|FWRITE; 349 fp1->f_type = DTYPE_SOCKET; 350 fp1->f_ops = &socketops; 351 fp1->f_data = so1; 352 if ((error = falloc(p, &fp2, &fd)) != 0) 353 goto free3; 354 fp2->f_flag = FREAD|FWRITE; 355 fp2->f_type = DTYPE_SOCKET; 356 fp2->f_ops = &socketops; 357 fp2->f_data = so2; 358 sv[1] = fd; 359 if ((error = soconnect2(so1, so2)) != 0) 360 goto free4; 361 if (SCARG(uap, type) == SOCK_DGRAM) { 362 /* 363 * Datagram socket connection is asymmetric. 364 */ 365 if ((error = soconnect2(so2, so1)) != 0) 366 goto free4; 367 } 368 error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int)); 369 if (error == 0) { 370 FILE_SET_MATURE(fp1, p); 371 FILE_SET_MATURE(fp2, p); 372 fdpunlock(fdp); 373 return (0); 374 } 375 free4: 376 fdremove(fdp, sv[1]); 377 closef(fp2, p); 378 so2 = NULL; 379 free3: 380 fdremove(fdp, sv[0]); 381 closef(fp1, p); 382 so1 = NULL; 383 free2: 384 if (so2 != NULL) 385 (void)soclose(so2); 386 fdpunlock(fdp); 387 free1: 388 if (so1 != NULL) 389 (void)soclose(so1); 390 return (error); 391 } 392 393 int 394 sys_sendto(struct proc *p, void *v, register_t *retval) 395 { 396 struct sys_sendto_args /* { 397 syscallarg(int) s; 398 syscallarg(const void *) buf; 399 syscallarg(size_t) len; 400 syscallarg(int) flags; 401 syscallarg(const struct sockaddr *) to; 402 syscallarg(socklen_t) tolen; 403 } */ *uap = v; 404 struct msghdr msg; 405 struct iovec aiov; 406 407 msg.msg_name = (caddr_t)SCARG(uap, to); 408 msg.msg_namelen = SCARG(uap, tolen); 409 msg.msg_iov = &aiov; 410 msg.msg_iovlen = 1; 411 msg.msg_control = 0; 412 msg.msg_flags = 0; 413 aiov.iov_base = (char *)SCARG(uap, buf); 414 aiov.iov_len = SCARG(uap, len); 415 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval)); 416 } 417 418 int 419 sys_sendmsg(struct proc *p, void *v, register_t *retval) 420 { 421 struct sys_sendmsg_args /* { 422 syscallarg(int) s; 423 syscallarg(const struct msghdr *) msg; 424 syscallarg(int) flags; 425 } */ *uap = v; 426 struct msghdr msg; 427 struct iovec aiov[UIO_SMALLIOV], *iov; 428 int error; 429 430 error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); 431 if (error) 432 return (error); 433 if (msg.msg_iovlen > IOV_MAX) 434 return (EMSGSIZE); 435 if (msg.msg_iovlen > UIO_SMALLIOV) 436 iov = malloc(sizeof(struct iovec) * msg.msg_iovlen, 437 M_IOV, M_WAITOK); 438 else 439 iov = aiov; 440 if (msg.msg_iovlen && 441 (error = copyin(msg.msg_iov, iov, 442 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))) 443 goto done; 444 msg.msg_iov = iov; 445 msg.msg_flags = 0; 446 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 447 done: 448 if (iov != aiov) 449 free(iov, M_IOV); 450 return (error); 451 } 452 453 int 454 sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize) 455 { 456 struct file *fp; 457 struct uio auio; 458 struct iovec *iov; 459 int i; 460 struct mbuf *to, *control; 461 size_t len; 462 int error; 463 #ifdef KTRACE 464 struct iovec *ktriov = NULL; 465 #endif 466 467 to = NULL; 468 469 if ((error = getsock(p->p_fd, s, &fp)) != 0) 470 return (error); 471 auio.uio_iov = mp->msg_iov; 472 auio.uio_iovcnt = mp->msg_iovlen; 473 auio.uio_segflg = UIO_USERSPACE; 474 auio.uio_rw = UIO_WRITE; 475 auio.uio_procp = p; 476 auio.uio_offset = 0; /* XXX */ 477 auio.uio_resid = 0; 478 iov = mp->msg_iov; 479 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 480 /* Don't allow sum > SSIZE_MAX */ 481 if (iov->iov_len > SSIZE_MAX || 482 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { 483 error = EINVAL; 484 goto bad; 485 } 486 } 487 if (mp->msg_name) { 488 error = sockargs(&to, mp->msg_name, mp->msg_namelen, 489 MT_SONAME); 490 if (error) 491 goto bad; 492 #ifdef KTRACE 493 if (KTRPOINT(p, KTR_STRUCT)) 494 ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen); 495 #endif 496 } 497 if (mp->msg_control) { 498 if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) { 499 error = EINVAL; 500 goto bad; 501 } 502 error = sockargs(&control, mp->msg_control, 503 mp->msg_controllen, MT_CONTROL); 504 if (error) 505 goto bad; 506 } else 507 control = 0; 508 #ifdef KTRACE 509 if (KTRPOINT(p, KTR_GENIO)) { 510 int iovlen = auio.uio_iovcnt * sizeof (struct iovec); 511 512 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 513 bcopy(auio.uio_iov, ktriov, iovlen); 514 } 515 #endif 516 len = auio.uio_resid; 517 error = sosend(fp->f_data, to, &auio, NULL, control, flags); 518 if (error) { 519 if (auio.uio_resid != len && (error == ERESTART || 520 error == EINTR || error == EWOULDBLOCK)) 521 error = 0; 522 if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) 523 ptsignal(p, SIGPIPE, STHREAD); 524 } 525 if (error == 0) { 526 *retsize = len - auio.uio_resid; 527 fp->f_wxfer++; 528 fp->f_wbytes += *retsize; 529 } 530 #ifdef KTRACE 531 if (ktriov != NULL) { 532 if (error == 0) 533 ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error); 534 free(ktriov, M_TEMP); 535 } 536 #endif 537 bad: 538 FRELE(fp, p); 539 if (to) 540 m_freem(to); 541 return (error); 542 } 543 544 int 545 sys_recvfrom(struct proc *p, void *v, register_t *retval) 546 { 547 struct sys_recvfrom_args /* { 548 syscallarg(int) s; 549 syscallarg(void *) buf; 550 syscallarg(size_t) len; 551 syscallarg(int) flags; 552 syscallarg(struct sockaddr *) from; 553 syscallarg(socklen_t *) fromlenaddr; 554 } */ *uap = v; 555 struct msghdr msg; 556 struct iovec aiov; 557 int error; 558 559 if (SCARG(uap, fromlenaddr)) { 560 error = copyin(SCARG(uap, fromlenaddr), 561 &msg.msg_namelen, sizeof (msg.msg_namelen)); 562 if (error) 563 return (error); 564 } else 565 msg.msg_namelen = 0; 566 msg.msg_name = (caddr_t)SCARG(uap, from); 567 msg.msg_iov = &aiov; 568 msg.msg_iovlen = 1; 569 aiov.iov_base = SCARG(uap, buf); 570 aiov.iov_len = SCARG(uap, len); 571 msg.msg_control = 0; 572 msg.msg_flags = SCARG(uap, flags); 573 return (recvit(p, SCARG(uap, s), &msg, 574 (caddr_t)SCARG(uap, fromlenaddr), retval)); 575 } 576 577 int 578 sys_recvmsg(struct proc *p, void *v, register_t *retval) 579 { 580 struct sys_recvmsg_args /* { 581 syscallarg(int) s; 582 syscallarg(struct msghdr *) msg; 583 syscallarg(int) flags; 584 } */ *uap = v; 585 struct msghdr msg; 586 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; 587 int error; 588 589 error = copyin(SCARG(uap, msg), &msg, sizeof (msg)); 590 if (error) 591 return (error); 592 if (msg.msg_iovlen > IOV_MAX) 593 return (EMSGSIZE); 594 if (msg.msg_iovlen > UIO_SMALLIOV) 595 iov = malloc(sizeof(struct iovec) * msg.msg_iovlen, 596 M_IOV, M_WAITOK); 597 else 598 iov = aiov; 599 msg.msg_flags = SCARG(uap, flags); 600 if (msg.msg_iovlen > 0) { 601 error = copyin(msg.msg_iov, iov, 602 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); 603 if (error) 604 goto done; 605 } 606 uiov = msg.msg_iov; 607 msg.msg_iov = iov; 608 if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) { 609 msg.msg_iov = uiov; 610 error = copyout(&msg, SCARG(uap, msg), sizeof(msg)); 611 } 612 done: 613 if (iov != aiov) 614 free(iov, M_IOV); 615 return (error); 616 } 617 618 int 619 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, 620 register_t *retsize) 621 { 622 struct file *fp; 623 struct uio auio; 624 struct iovec *iov; 625 int i; 626 size_t len; 627 int error; 628 struct mbuf *from = NULL, *control = NULL; 629 #ifdef KTRACE 630 struct iovec *ktriov = NULL; 631 #endif 632 633 if ((error = getsock(p->p_fd, s, &fp)) != 0) 634 return (error); 635 auio.uio_iov = mp->msg_iov; 636 auio.uio_iovcnt = mp->msg_iovlen; 637 auio.uio_segflg = UIO_USERSPACE; 638 auio.uio_rw = UIO_READ; 639 auio.uio_procp = p; 640 auio.uio_offset = 0; /* XXX */ 641 auio.uio_resid = 0; 642 iov = mp->msg_iov; 643 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 644 /* Don't allow sum > SSIZE_MAX */ 645 if (iov->iov_len > SSIZE_MAX || 646 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { 647 error = EINVAL; 648 goto out; 649 } 650 } 651 #ifdef KTRACE 652 if (KTRPOINT(p, KTR_GENIO)) { 653 int iovlen = auio.uio_iovcnt * sizeof (struct iovec); 654 655 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 656 bcopy(auio.uio_iov, ktriov, iovlen); 657 } 658 #endif 659 len = auio.uio_resid; 660 error = soreceive(fp->f_data, &from, &auio, NULL, 661 mp->msg_control ? &control : NULL, 662 &mp->msg_flags, 663 mp->msg_control ? mp->msg_controllen : 0); 664 if (error) { 665 if (auio.uio_resid != len && (error == ERESTART || 666 error == EINTR || error == EWOULDBLOCK)) 667 error = 0; 668 } 669 #ifdef KTRACE 670 if (ktriov != NULL) { 671 if (error == 0) 672 ktrgenio(p, s, UIO_READ, 673 ktriov, len - auio.uio_resid, error); 674 free(ktriov, M_TEMP); 675 } 676 #endif 677 if (error) 678 goto out; 679 *retsize = len - auio.uio_resid; 680 if (mp->msg_name) { 681 socklen_t alen; 682 683 if (from == NULL) 684 alen = 0; 685 else { 686 alen = from->m_len; 687 error = copyout(mtod(from, caddr_t), mp->msg_name, 688 MIN(alen, mp->msg_namelen)); 689 if (error) 690 goto out; 691 #ifdef KTRACE 692 if (KTRPOINT(p, KTR_STRUCT)) 693 ktrsockaddr(p, mtod(from, caddr_t), alen); 694 #endif 695 } 696 mp->msg_namelen = alen; 697 if (namelenp && 698 (error = copyout(&alen, namelenp, sizeof(alen)))) { 699 goto out; 700 } 701 } 702 if (mp->msg_control) { 703 len = mp->msg_controllen; 704 if (len <= 0 || control == NULL) 705 len = 0; 706 else { 707 struct mbuf *m = control; 708 caddr_t p = mp->msg_control; 709 710 do { 711 i = m->m_len; 712 if (len < i) { 713 mp->msg_flags |= MSG_CTRUNC; 714 i = len; 715 } 716 error = copyout(mtod(m, caddr_t), p, 717 (unsigned)i); 718 if (m->m_next) 719 i = ALIGN(i); 720 p += i; 721 len -= i; 722 if (error != 0 || len <= 0) 723 break; 724 } while ((m = m->m_next) != NULL); 725 len = p - (caddr_t)mp->msg_control; 726 } 727 mp->msg_controllen = len; 728 } 729 if (!error) { 730 fp->f_rxfer++; 731 fp->f_rbytes += *retsize; 732 } 733 out: 734 FRELE(fp, p); 735 if (from) 736 m_freem(from); 737 if (control) 738 m_freem(control); 739 return (error); 740 } 741 742 /* ARGSUSED */ 743 int 744 sys_shutdown(struct proc *p, void *v, register_t *retval) 745 { 746 struct sys_shutdown_args /* { 747 syscallarg(int) s; 748 syscallarg(int) how; 749 } */ *uap = v; 750 struct file *fp; 751 int error; 752 753 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 754 return (error); 755 error = soshutdown(fp->f_data, SCARG(uap, how)); 756 FRELE(fp, p); 757 return (error); 758 } 759 760 /* ARGSUSED */ 761 int 762 sys_setsockopt(struct proc *p, void *v, register_t *retval) 763 { 764 struct sys_setsockopt_args /* { 765 syscallarg(int) s; 766 syscallarg(int) level; 767 syscallarg(int) name; 768 syscallarg(const void *) val; 769 syscallarg(socklen_t) valsize; 770 } */ *uap = v; 771 struct file *fp; 772 struct mbuf *m = NULL; 773 int error; 774 775 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 776 return (error); 777 if (SCARG(uap, valsize) > MCLBYTES) { 778 error = EINVAL; 779 goto bad; 780 } 781 if (SCARG(uap, val)) { 782 m = m_get(M_WAIT, MT_SOOPTS); 783 if (SCARG(uap, valsize) > MLEN) { 784 MCLGET(m, M_DONTWAIT); 785 if ((m->m_flags & M_EXT) == 0) { 786 error = ENOBUFS; 787 goto bad; 788 } 789 } 790 if (m == NULL) { 791 error = ENOBUFS; 792 goto bad; 793 } 794 error = copyin(SCARG(uap, val), mtod(m, caddr_t), 795 SCARG(uap, valsize)); 796 if (error) { 797 goto bad; 798 } 799 m->m_len = SCARG(uap, valsize); 800 } 801 error = sosetopt(fp->f_data, SCARG(uap, level), 802 SCARG(uap, name), m); 803 m = NULL; 804 bad: 805 if (m) 806 m_freem(m); 807 FRELE(fp, p); 808 return (error); 809 } 810 811 /* ARGSUSED */ 812 int 813 sys_getsockopt(struct proc *p, void *v, register_t *retval) 814 { 815 struct sys_getsockopt_args /* { 816 syscallarg(int) s; 817 syscallarg(int) level; 818 syscallarg(int) name; 819 syscallarg(void *) val; 820 syscallarg(socklen_t *) avalsize; 821 } */ *uap = v; 822 struct file *fp; 823 struct mbuf *m = NULL; 824 socklen_t valsize; 825 int error; 826 827 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) 828 return (error); 829 if (SCARG(uap, val)) { 830 error = copyin(SCARG(uap, avalsize), 831 &valsize, sizeof (valsize)); 832 if (error) 833 goto out; 834 } else 835 valsize = 0; 836 if ((error = sogetopt(fp->f_data, SCARG(uap, level), 837 SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize && 838 m != NULL) { 839 if (valsize > m->m_len) 840 valsize = m->m_len; 841 error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize); 842 if (error == 0) 843 error = copyout(&valsize, 844 SCARG(uap, avalsize), sizeof (valsize)); 845 } 846 out: 847 FRELE(fp, p); 848 if (m != NULL) 849 (void)m_free(m); 850 return (error); 851 } 852 853 /* 854 * Get socket name. 855 */ 856 /* ARGSUSED */ 857 int 858 sys_getsockname(struct proc *p, void *v, register_t *retval) 859 { 860 struct sys_getsockname_args /* { 861 syscallarg(int) fdes; 862 syscallarg(struct sockaddr *) asa; 863 syscallarg(socklen_t *) alen; 864 } */ *uap = v; 865 struct file *fp; 866 struct socket *so; 867 struct mbuf *m = NULL; 868 socklen_t len; 869 int error; 870 871 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) 872 return (error); 873 error = copyin(SCARG(uap, alen), &len, sizeof (len)); 874 if (error) 875 goto bad; 876 so = fp->f_data; 877 m = m_getclr(M_WAIT, MT_SONAME); 878 error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p); 879 if (error) 880 goto bad; 881 error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); 882 bad: 883 FRELE(fp, p); 884 if (m) 885 m_freem(m); 886 return (error); 887 } 888 889 /* 890 * Get name of peer for connected socket. 891 */ 892 /* ARGSUSED */ 893 int 894 sys_getpeername(struct proc *p, void *v, register_t *retval) 895 { 896 struct sys_getpeername_args /* { 897 syscallarg(int) fdes; 898 syscallarg(struct sockaddr *) asa; 899 syscallarg(socklen_t *) alen; 900 } */ *uap = v; 901 struct file *fp; 902 struct socket *so; 903 struct mbuf *m = NULL; 904 socklen_t len; 905 int error; 906 907 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) 908 return (error); 909 so = fp->f_data; 910 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { 911 FRELE(fp, p); 912 return (ENOTCONN); 913 } 914 error = copyin(SCARG(uap, alen), &len, sizeof (len)); 915 if (error) 916 goto bad; 917 m = m_getclr(M_WAIT, MT_SONAME); 918 error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p); 919 if (error) 920 goto bad; 921 error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); 922 bad: 923 FRELE(fp, p); 924 m_freem(m); 925 return (error); 926 } 927 928 int 929 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type) 930 { 931 struct sockaddr *sa; 932 struct mbuf *m; 933 int error; 934 935 /* 936 * We can't allow socket names > UCHAR_MAX in length, since that 937 * will overflow sa_len. Also, control data more than MCLBYTES in 938 * length is just too much. 939 */ 940 if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES)) 941 return (EINVAL); 942 943 /* Allocate an mbuf to hold the arguments. */ 944 m = m_get(M_WAIT, type); 945 if ((u_int)buflen > MLEN) { 946 MCLGET(m, M_WAITOK); 947 if ((m->m_flags & M_EXT) == 0) { 948 m_free(m); 949 return ENOBUFS; 950 } 951 } 952 m->m_len = buflen; 953 error = copyin(buf, mtod(m, caddr_t), buflen); 954 if (error) { 955 (void) m_free(m); 956 return (error); 957 } 958 *mp = m; 959 if (type == MT_SONAME) { 960 sa = mtod(m, struct sockaddr *); 961 #if BYTE_ORDER != BIG_ENDIAN 962 if (sa->sa_family == 0 && sa->sa_len < AF_MAX) 963 sa->sa_family = sa->sa_len; 964 #endif 965 sa->sa_len = buflen; 966 } 967 return (0); 968 } 969 970 int 971 getsock(struct filedesc *fdp, int fdes, struct file **fpp) 972 { 973 struct file *fp; 974 975 if ((fp = fd_getfile(fdp, fdes)) == NULL) 976 return (EBADF); 977 if (fp->f_type != DTYPE_SOCKET) 978 return (ENOTSOCK); 979 *fpp = fp; 980 FREF(fp); 981 982 return (0); 983 } 984 985 /* ARGSUSED */ 986 int 987 sys_setrtable(struct proc *p, void *v, register_t *retval) 988 { 989 struct sys_setrtable_args /* { 990 syscallarg(int) rtableid; 991 } */ *uap = v; 992 int rtableid, error; 993 994 rtableid = SCARG(uap, rtableid); 995 996 if (p->p_p->ps_rtableid == (u_int)rtableid) 997 return (0); 998 if (p->p_p->ps_rtableid != 0 && (error = suser(p, 0)) != 0) 999 return (error); 1000 if (rtableid < 0 || !rtable_exists((u_int)rtableid)) 1001 return (EINVAL); 1002 1003 p->p_p->ps_rtableid = (u_int)rtableid; 1004 return (0); 1005 } 1006 1007 /* ARGSUSED */ 1008 int 1009 sys_getrtable(struct proc *p, void *v, register_t *retval) 1010 { 1011 *retval = (int)p->p_p->ps_rtableid; 1012 return (0); 1013 } 1014 1015 int 1016 copyaddrout(struct proc *p, struct mbuf *name, struct sockaddr *sa, 1017 socklen_t buflen, socklen_t *outlen) 1018 { 1019 int error; 1020 socklen_t namelen = name->m_len; 1021 1022 /* SHOULD COPY OUT A CHAIN HERE */ 1023 error = copyout(mtod(name, caddr_t), sa, MIN(buflen, namelen)); 1024 if (error == 0) { 1025 #ifdef KTRACE 1026 if (KTRPOINT(p, KTR_STRUCT)) 1027 ktrsockaddr(p, mtod(name, caddr_t), namelen); 1028 #endif 1029 error = copyout(&namelen, outlen, sizeof(*outlen)); 1030 } 1031 1032 return (error); 1033 } 1034