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