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