kern_sendfile.c revision 28317
1/* 2 * Copyright (c) 1982, 1986, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 34 * $Id: uipc_syscalls.c,v 1.27 1997/08/16 19:15:06 wollman Exp $ 35 */ 36 37#include "opt_ktrace.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/sysproto.h> 42#include <sys/filedesc.h> 43#include <sys/proc.h> 44#include <sys/fcntl.h> 45#include <sys/file.h> 46#include <sys/buf.h> 47#include <sys/malloc.h> 48#include <sys/mbuf.h> 49#include <sys/protosw.h> 50#include <sys/stat.h> 51#include <sys/socket.h> 52#include <sys/socketvar.h> 53#include <sys/signalvar.h> 54#include <sys/un.h> 55#ifdef KTRACE 56#include <sys/ktrace.h> 57#endif 58 59#include <vm/vm.h> 60#include <vm/vm_param.h> 61#include <vm/pmap.h> 62 63extern int sendit __P((struct proc *p, int s, struct msghdr *mp, int flags, 64 int *retsize)); 65extern int recvit __P((struct proc *p, int s, struct msghdr *mp, 66 caddr_t namelenp, int *retsize)); 67 68static int accept1 __P((struct proc *p, struct accept_args *uap, int *retval, 69 int compat)); 70static int getsockname1 __P((struct proc *p, struct getsockname_args *uap, 71 int *retval, int compat)); 72static int getpeername1 __P((struct proc *p, struct getpeername_args *uap, 73 int *retval, int compat)); 74 75/* 76 * System call interface to the socket abstraction. 77 */ 78#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 79#define COMPAT_OLDSOCK 80#endif 81 82extern struct fileops socketops; 83 84int 85socket(p, uap, retval) 86 struct proc *p; 87 register struct socket_args /* { 88 int domain; 89 int type; 90 int protocol; 91 } */ *uap; 92 int *retval; 93{ 94 struct filedesc *fdp = p->p_fd; 95 struct socket *so; 96 struct file *fp; 97 int fd, error; 98 99 error = falloc(p, &fp, &fd); 100 if (error) 101 return (error); 102 fp->f_flag = FREAD|FWRITE; 103 fp->f_type = DTYPE_SOCKET; 104 fp->f_ops = &socketops; 105 error = socreate(uap->domain, &so, uap->type, uap->protocol, p); 106 if (error) { 107 fdp->fd_ofiles[fd] = 0; 108 ffree(fp); 109 } else { 110 fp->f_data = (caddr_t)so; 111 *retval = fd; 112 } 113 return (error); 114} 115 116/* ARGSUSED */ 117int 118bind(p, uap, retval) 119 struct proc *p; 120 register struct bind_args /* { 121 int s; 122 caddr_t name; 123 int namelen; 124 } */ *uap; 125 int *retval; 126{ 127 struct file *fp; 128 struct sockaddr *sa; 129 int error; 130 131 error = getsock(p->p_fd, uap->s, &fp); 132 if (error) 133 return (error); 134 error = getsockaddr(&sa, uap->name, uap->namelen); 135 if (error) 136 return (error); 137 error = sobind((struct socket *)fp->f_data, sa, p); 138 FREE(sa, M_SONAME); 139 return (error); 140} 141 142/* ARGSUSED */ 143int 144listen(p, uap, retval) 145 struct proc *p; 146 register struct listen_args /* { 147 int s; 148 int backlog; 149 } */ *uap; 150 int *retval; 151{ 152 struct file *fp; 153 int error; 154 155 error = getsock(p->p_fd, uap->s, &fp); 156 if (error) 157 return (error); 158 return (solisten((struct socket *)fp->f_data, uap->backlog, p)); 159} 160 161static int 162accept1(p, uap, retval, compat) 163 struct proc *p; 164 register struct accept_args /* { 165 int s; 166 caddr_t name; 167 int *anamelen; 168 } */ *uap; 169 int *retval; 170 int compat; 171{ 172 struct file *fp; 173 struct sockaddr *sa; 174 int namelen, error, s; 175 struct socket *head, *so; 176 short fflag; /* type must match fp->f_flag */ 177 178 if (uap->name) { 179 error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen, 180 sizeof (namelen)); 181 if(error) 182 return (error); 183 } 184 error = getsock(p->p_fd, uap->s, &fp); 185 if (error) 186 return (error); 187 s = splnet(); 188 head = (struct socket *)fp->f_data; 189 if ((head->so_options & SO_ACCEPTCONN) == 0) { 190 splx(s); 191 return (EINVAL); 192 } 193 if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) { 194 splx(s); 195 return (EWOULDBLOCK); 196 } 197 while (head->so_comp.tqh_first == NULL && head->so_error == 0) { 198 if (head->so_state & SS_CANTRCVMORE) { 199 head->so_error = ECONNABORTED; 200 break; 201 } 202 error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH, 203 "accept", 0); 204 if (error) { 205 splx(s); 206 return (error); 207 } 208 } 209 if (head->so_error) { 210 error = head->so_error; 211 head->so_error = 0; 212 splx(s); 213 return (error); 214 } 215 216 /* 217 * At this point we know that there is at least one connection 218 * ready to be accepted. Remove it from the queue prior to 219 * allocating the file descriptor for it since falloc() may 220 * block allowing another process to accept the connection 221 * instead. 222 */ 223 so = head->so_comp.tqh_first; 224 TAILQ_REMOVE(&head->so_comp, so, so_list); 225 head->so_qlen--; 226 227 fflag = fp->f_flag; 228 error = falloc(p, &fp, retval); 229 if (error) { 230 /* 231 * Probably ran out of file descriptors. Put the 232 * unaccepted connection back onto the queue and 233 * do another wakeup so some other process might 234 * have a chance at it. 235 */ 236 TAILQ_INSERT_HEAD(&head->so_comp, so, so_list); 237 head->so_qlen++; 238 wakeup_one(&head->so_timeo); 239 splx(s); 240 return (error); 241 } 242 243 so->so_state &= ~SS_COMP; 244 so->so_head = NULL; 245 246 fp->f_type = DTYPE_SOCKET; 247 fp->f_flag = fflag; 248 fp->f_ops = &socketops; 249 fp->f_data = (caddr_t)so; 250 sa = 0; 251 (void) soaccept(so, &sa); 252 if (sa == 0) { 253 namelen = 0; 254 if (uap->name) 255 goto gotnoname; 256 return 0; 257 } 258 if ((u_long)sa < KERNBASE) { 259 panic("accept1 bad sa"); 260 } 261 if (uap->name) { 262#ifdef COMPAT_OLDSOCK 263 if (compat) 264 ((struct osockaddr *)sa)->sa_family = 265 sa->sa_family; 266#endif 267 if (namelen > sa->sa_len) 268 namelen = sa->sa_len; 269 error = copyout(sa, (caddr_t)uap->name, (u_int)namelen); 270 if (!error) 271gotnoname: 272 error = copyout((caddr_t)&namelen, 273 (caddr_t)uap->anamelen, sizeof (*uap->anamelen)); 274 } 275 FREE(sa, M_SONAME); 276 splx(s); 277 return (error); 278} 279 280int 281accept(p, uap, retval) 282 struct proc *p; 283 struct accept_args *uap; 284 int *retval; 285{ 286 287 return (accept1(p, uap, retval, 0)); 288} 289 290#ifdef COMPAT_OLDSOCK 291int 292oaccept(p, uap, retval) 293 struct proc *p; 294 struct accept_args *uap; 295 int *retval; 296{ 297 298 return (accept1(p, uap, retval, 1)); 299} 300#endif /* COMPAT_OLDSOCK */ 301 302/* ARGSUSED */ 303int 304connect(p, uap, retval) 305 struct proc *p; 306 register struct connect_args /* { 307 int s; 308 caddr_t name; 309 int namelen; 310 } */ *uap; 311 int *retval; 312{ 313 struct file *fp; 314 register struct socket *so; 315 struct sockaddr *sa; 316 int error, s; 317 318 error = getsock(p->p_fd, uap->s, &fp); 319 if (error) 320 return (error); 321 so = (struct socket *)fp->f_data; 322 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) 323 return (EALREADY); 324 error = getsockaddr(&sa, uap->name, uap->namelen); 325 if (error) 326 return (error); 327 error = soconnect(so, sa, p); 328 if (error) 329 goto bad; 330 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { 331 FREE(sa, M_SONAME); 332 return (EINPROGRESS); 333 } 334 s = splnet(); 335 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 336 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, 337 "connec", 0); 338 if (error) 339 break; 340 } 341 if (error == 0) { 342 error = so->so_error; 343 so->so_error = 0; 344 } 345 splx(s); 346bad: 347 so->so_state &= ~SS_ISCONNECTING; 348 FREE(sa, M_SONAME); 349 if (error == ERESTART) 350 error = EINTR; 351 return (error); 352} 353 354int 355socketpair(p, uap, retval) 356 struct proc *p; 357 register struct socketpair_args /* { 358 int domain; 359 int type; 360 int protocol; 361 int *rsv; 362 } */ *uap; 363 int retval[]; 364{ 365 register struct filedesc *fdp = p->p_fd; 366 struct file *fp1, *fp2; 367 struct socket *so1, *so2; 368 int fd, error, sv[2]; 369 370 error = socreate(uap->domain, &so1, uap->type, uap->protocol, p); 371 if (error) 372 return (error); 373 error = socreate(uap->domain, &so2, uap->type, uap->protocol, p); 374 if (error) 375 goto free1; 376 error = falloc(p, &fp1, &fd); 377 if (error) 378 goto free2; 379 sv[0] = fd; 380 fp1->f_flag = FREAD|FWRITE; 381 fp1->f_type = DTYPE_SOCKET; 382 fp1->f_ops = &socketops; 383 fp1->f_data = (caddr_t)so1; 384 error = falloc(p, &fp2, &fd); 385 if (error) 386 goto free3; 387 fp2->f_flag = FREAD|FWRITE; 388 fp2->f_type = DTYPE_SOCKET; 389 fp2->f_ops = &socketops; 390 fp2->f_data = (caddr_t)so2; 391 sv[1] = fd; 392 error = soconnect2(so1, so2); 393 if (error) 394 goto free4; 395 if (uap->type == SOCK_DGRAM) { 396 /* 397 * Datagram socket connection is asymmetric. 398 */ 399 error = soconnect2(so2, so1); 400 if (error) 401 goto free4; 402 } 403 error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int)); 404#if 0 /* old pipe(2) syscall compatability, unused these days */ 405 retval[0] = sv[0]; /* XXX ??? */ 406 retval[1] = sv[1]; /* XXX ??? */ 407#endif 408 return (error); 409free4: 410 ffree(fp2); 411 fdp->fd_ofiles[sv[1]] = 0; 412free3: 413 ffree(fp1); 414 fdp->fd_ofiles[sv[0]] = 0; 415free2: 416 (void)soclose(so2); 417free1: 418 (void)soclose(so1); 419 return (error); 420} 421 422int 423sendit(p, s, mp, flags, retsize) 424 register struct proc *p; 425 int s; 426 register struct msghdr *mp; 427 int flags, *retsize; 428{ 429 struct file *fp; 430 struct uio auio; 431 register struct iovec *iov; 432 register int i; 433 struct mbuf *control; 434 struct sockaddr *to; 435 int len, error; 436 struct socket *so; 437#ifdef KTRACE 438 struct iovec *ktriov = NULL; 439#endif 440 441 error = getsock(p->p_fd, s, &fp); 442 if (error) 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 if ((auio.uio_resid += iov->iov_len) < 0) 454 return (EINVAL); 455 } 456 if (mp->msg_name) { 457 error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); 458 if (error) 459 return (error); 460 } else 461 to = 0; 462 if (mp->msg_control) { 463 if (mp->msg_controllen < sizeof(struct cmsghdr) 464#ifdef COMPAT_OLDSOCK 465 && mp->msg_flags != MSG_COMPAT 466#endif 467 ) { 468 error = EINVAL; 469 goto bad; 470 } 471 error = sockargs(&control, mp->msg_control, 472 mp->msg_controllen, MT_CONTROL); 473 if (error) 474 goto bad; 475#ifdef COMPAT_OLDSOCK 476 if (mp->msg_flags == MSG_COMPAT) { 477 register struct cmsghdr *cm; 478 479 M_PREPEND(control, sizeof(*cm), M_WAIT); 480 if (control == 0) { 481 error = ENOBUFS; 482 goto bad; 483 } else { 484 cm = mtod(control, struct cmsghdr *); 485 cm->cmsg_len = control->m_len; 486 cm->cmsg_level = SOL_SOCKET; 487 cm->cmsg_type = SCM_RIGHTS; 488 } 489 } 490#endif 491 } else 492 control = 0; 493#ifdef KTRACE 494 if (KTRPOINT(p, KTR_GENIO)) { 495 int iovlen = auio.uio_iovcnt * sizeof (struct iovec); 496 497 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 498 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); 499 } 500#endif 501 len = auio.uio_resid; 502 so = (struct socket *)fp->f_data; 503 error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control, 504 flags, p); 505 if (error) { 506 if (auio.uio_resid != len && (error == ERESTART || 507 error == EINTR || error == EWOULDBLOCK)) 508 error = 0; 509 if (error == EPIPE) 510 psignal(p, SIGPIPE); 511 } 512 if (error == 0) 513 *retsize = len - auio.uio_resid; 514#ifdef KTRACE 515 if (ktriov != NULL) { 516 if (error == 0) 517 ktrgenio(p->p_tracep, s, UIO_WRITE, 518 ktriov, *retsize, error); 519 FREE(ktriov, M_TEMP); 520 } 521#endif 522bad: 523 if (to) 524 FREE(to, M_SONAME); 525 return (error); 526} 527 528int 529sendto(p, uap, retval) 530 struct proc *p; 531 register struct sendto_args /* { 532 int s; 533 caddr_t buf; 534 size_t len; 535 int flags; 536 caddr_t to; 537 int tolen; 538 } */ *uap; 539 int *retval; 540{ 541 struct msghdr msg; 542 struct iovec aiov; 543 544 msg.msg_name = uap->to; 545 msg.msg_namelen = uap->tolen; 546 msg.msg_iov = &aiov; 547 msg.msg_iovlen = 1; 548 msg.msg_control = 0; 549#ifdef COMPAT_OLDSOCK 550 msg.msg_flags = 0; 551#endif 552 aiov.iov_base = uap->buf; 553 aiov.iov_len = uap->len; 554 return (sendit(p, uap->s, &msg, uap->flags, retval)); 555} 556 557#ifdef COMPAT_OLDSOCK 558int 559osend(p, uap, retval) 560 struct proc *p; 561 register struct osend_args /* { 562 int s; 563 caddr_t buf; 564 int len; 565 int flags; 566 } */ *uap; 567 int *retval; 568{ 569 struct msghdr msg; 570 struct iovec aiov; 571 572 msg.msg_name = 0; 573 msg.msg_namelen = 0; 574 msg.msg_iov = &aiov; 575 msg.msg_iovlen = 1; 576 aiov.iov_base = uap->buf; 577 aiov.iov_len = uap->len; 578 msg.msg_control = 0; 579 msg.msg_flags = 0; 580 return (sendit(p, uap->s, &msg, uap->flags, retval)); 581} 582 583int 584osendmsg(p, uap, retval) 585 struct proc *p; 586 register struct osendmsg_args /* { 587 int s; 588 caddr_t msg; 589 int flags; 590 } */ *uap; 591 int *retval; 592{ 593 struct msghdr msg; 594 struct iovec aiov[UIO_SMALLIOV], *iov; 595 int error; 596 597 error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr)); 598 if (error) 599 return (error); 600 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { 601 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) 602 return (EMSGSIZE); 603 MALLOC(iov, struct iovec *, 604 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 605 M_WAITOK); 606 } else 607 iov = aiov; 608 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov, 609 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); 610 if (error) 611 goto done; 612 msg.msg_flags = MSG_COMPAT; 613 msg.msg_iov = iov; 614 error = sendit(p, uap->s, &msg, uap->flags, retval); 615done: 616 if (iov != aiov) 617 FREE(iov, M_IOV); 618 return (error); 619} 620#endif 621 622int 623sendmsg(p, uap, retval) 624 struct proc *p; 625 register struct sendmsg_args /* { 626 int s; 627 caddr_t msg; 628 int flags; 629 } */ *uap; 630 int *retval; 631{ 632 struct msghdr msg; 633 struct iovec aiov[UIO_SMALLIOV], *iov; 634 int error; 635 636 error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)); 637 if (error) 638 return (error); 639 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { 640 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) 641 return (EMSGSIZE); 642 MALLOC(iov, struct iovec *, 643 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 644 M_WAITOK); 645 } else 646 iov = aiov; 647 if (msg.msg_iovlen && 648 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov, 649 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))) 650 goto done; 651 msg.msg_iov = iov; 652#ifdef COMPAT_OLDSOCK 653 msg.msg_flags = 0; 654#endif 655 error = sendit(p, uap->s, &msg, uap->flags, retval); 656done: 657 if (iov != aiov) 658 FREE(iov, M_IOV); 659 return (error); 660} 661 662int 663recvit(p, s, mp, namelenp, retsize) 664 register struct proc *p; 665 int s; 666 register struct msghdr *mp; 667 caddr_t namelenp; 668 int *retsize; 669{ 670 struct file *fp; 671 struct uio auio; 672 register struct iovec *iov; 673 register int i; 674 int len, error; 675 struct mbuf *m, *control = 0; 676 caddr_t ctlbuf; 677 struct socket *so; 678 struct sockaddr *fromsa = 0; 679#ifdef KTRACE 680 struct iovec *ktriov = NULL; 681#endif 682 683 error = getsock(p->p_fd, s, &fp); 684 if (error) 685 return (error); 686 auio.uio_iov = mp->msg_iov; 687 auio.uio_iovcnt = mp->msg_iovlen; 688 auio.uio_segflg = UIO_USERSPACE; 689 auio.uio_rw = UIO_READ; 690 auio.uio_procp = p; 691 auio.uio_offset = 0; /* XXX */ 692 auio.uio_resid = 0; 693 iov = mp->msg_iov; 694 for (i = 0; i < mp->msg_iovlen; i++, iov++) { 695 if ((auio.uio_resid += iov->iov_len) < 0) 696 return (EINVAL); 697 } 698#ifdef KTRACE 699 if (KTRPOINT(p, KTR_GENIO)) { 700 int iovlen = auio.uio_iovcnt * sizeof (struct iovec); 701 702 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 703 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); 704 } 705#endif 706 len = auio.uio_resid; 707 so = (struct socket *)fp->f_data; 708 error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio, 709 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0, 710 &mp->msg_flags); 711 if (error) { 712 if (auio.uio_resid != len && (error == ERESTART || 713 error == EINTR || error == EWOULDBLOCK)) 714 error = 0; 715 } 716#ifdef KTRACE 717 if (ktriov != NULL) { 718 if (error == 0) 719 ktrgenio(p->p_tracep, s, UIO_READ, 720 ktriov, len - auio.uio_resid, error); 721 FREE(ktriov, M_TEMP); 722 } 723#endif 724 if (error) 725 goto out; 726 *retsize = len - auio.uio_resid; 727 if (mp->msg_name) { 728 len = mp->msg_namelen; 729 if (len <= 0 || fromsa == 0) 730 len = 0; 731 else { 732#ifdef COMPAT_OLDSOCK 733 if (mp->msg_flags & MSG_COMPAT) 734 ((struct osockaddr *)fromsa)->sa_family = 735 fromsa->sa_family; 736#endif 737#ifndef MIN 738#define MIN(a,b) ((a)>(b)?(b):(a)) 739#endif 740 len = MIN(len, fromsa->sa_len); 741 error = copyout(fromsa, 742 (caddr_t)mp->msg_name, (unsigned)len); 743 if (error) 744 goto out; 745 } 746 mp->msg_namelen = len; 747 if (namelenp && 748 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) { 749#ifdef COMPAT_OLDSOCK 750 if (mp->msg_flags & MSG_COMPAT) 751 error = 0; /* old recvfrom didn't check */ 752 else 753#endif 754 goto out; 755 } 756 } 757 if (mp->msg_control) { 758#ifdef COMPAT_OLDSOCK 759 /* 760 * We assume that old recvmsg calls won't receive access 761 * rights and other control info, esp. as control info 762 * is always optional and those options didn't exist in 4.3. 763 * If we receive rights, trim the cmsghdr; anything else 764 * is tossed. 765 */ 766 if (control && mp->msg_flags & MSG_COMPAT) { 767 if (mtod(control, struct cmsghdr *)->cmsg_level != 768 SOL_SOCKET || 769 mtod(control, struct cmsghdr *)->cmsg_type != 770 SCM_RIGHTS) { 771 mp->msg_controllen = 0; 772 goto out; 773 } 774 control->m_len -= sizeof (struct cmsghdr); 775 control->m_data += sizeof (struct cmsghdr); 776 } 777#endif 778 len = mp->msg_controllen; 779 m = control; 780 mp->msg_controllen = 0; 781 ctlbuf = (caddr_t) mp->msg_control; 782 783 while (m && len > 0) { 784 unsigned int tocopy; 785 786 if (len >= m->m_len) 787 tocopy = m->m_len; 788 else { 789 mp->msg_flags |= MSG_CTRUNC; 790 tocopy = len; 791 } 792 793 if (error = copyout((caddr_t)mtod(m, caddr_t), 794 ctlbuf, tocopy)) 795 goto out; 796 797 ctlbuf += tocopy; 798 len -= tocopy; 799 m = m->m_next; 800 } 801 mp->msg_controllen = ctlbuf - mp->msg_control; 802 } 803out: 804 if (fromsa) 805 FREE(fromsa, M_SONAME); 806 if (control) 807 m_freem(control); 808 return (error); 809} 810 811int 812recvfrom(p, uap, retval) 813 struct proc *p; 814 register struct recvfrom_args /* { 815 int s; 816 caddr_t buf; 817 size_t len; 818 int flags; 819 caddr_t from; 820 int *fromlenaddr; 821 } */ *uap; 822 int *retval; 823{ 824 struct msghdr msg; 825 struct iovec aiov; 826 int error; 827 828 if (uap->fromlenaddr) { 829 error = copyin((caddr_t)uap->fromlenaddr, 830 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen)); 831 if (error) 832 return (error); 833 } else 834 msg.msg_namelen = 0; 835 msg.msg_name = uap->from; 836 msg.msg_iov = &aiov; 837 msg.msg_iovlen = 1; 838 aiov.iov_base = uap->buf; 839 aiov.iov_len = uap->len; 840 msg.msg_control = 0; 841 msg.msg_flags = uap->flags; 842 return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval)); 843} 844 845#ifdef COMPAT_OLDSOCK 846int 847orecvfrom(p, uap, retval) 848 struct proc *p; 849 struct recvfrom_args *uap; 850 int *retval; 851{ 852 853 uap->flags |= MSG_COMPAT; 854 return (recvfrom(p, uap, retval)); 855} 856#endif 857 858 859#ifdef COMPAT_OLDSOCK 860int 861orecv(p, uap, retval) 862 struct proc *p; 863 register struct orecv_args /* { 864 int s; 865 caddr_t buf; 866 int len; 867 int flags; 868 } */ *uap; 869 int *retval; 870{ 871 struct msghdr msg; 872 struct iovec aiov; 873 874 msg.msg_name = 0; 875 msg.msg_namelen = 0; 876 msg.msg_iov = &aiov; 877 msg.msg_iovlen = 1; 878 aiov.iov_base = uap->buf; 879 aiov.iov_len = uap->len; 880 msg.msg_control = 0; 881 msg.msg_flags = uap->flags; 882 return (recvit(p, uap->s, &msg, (caddr_t)0, retval)); 883} 884 885/* 886 * Old recvmsg. This code takes advantage of the fact that the old msghdr 887 * overlays the new one, missing only the flags, and with the (old) access 888 * rights where the control fields are now. 889 */ 890int 891orecvmsg(p, uap, retval) 892 struct proc *p; 893 register struct orecvmsg_args /* { 894 int s; 895 struct omsghdr *msg; 896 int flags; 897 } */ *uap; 898 int *retval; 899{ 900 struct msghdr msg; 901 struct iovec aiov[UIO_SMALLIOV], *iov; 902 int error; 903 904 error = copyin((caddr_t)uap->msg, (caddr_t)&msg, 905 sizeof (struct omsghdr)); 906 if (error) 907 return (error); 908 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { 909 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) 910 return (EMSGSIZE); 911 MALLOC(iov, struct iovec *, 912 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 913 M_WAITOK); 914 } else 915 iov = aiov; 916 msg.msg_flags = uap->flags | MSG_COMPAT; 917 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov, 918 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); 919 if (error) 920 goto done; 921 msg.msg_iov = iov; 922 error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval); 923 924 if (msg.msg_controllen && error == 0) 925 error = copyout((caddr_t)&msg.msg_controllen, 926 (caddr_t)&uap->msg->msg_accrightslen, sizeof (int)); 927done: 928 if (iov != aiov) 929 FREE(iov, M_IOV); 930 return (error); 931} 932#endif 933 934int 935recvmsg(p, uap, retval) 936 struct proc *p; 937 register struct recvmsg_args /* { 938 int s; 939 struct msghdr *msg; 940 int flags; 941 } */ *uap; 942 int *retval; 943{ 944 struct msghdr msg; 945 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; 946 register int error; 947 948 error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)); 949 if (error) 950 return (error); 951 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { 952 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) 953 return (EMSGSIZE); 954 MALLOC(iov, struct iovec *, 955 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, 956 M_WAITOK); 957 } else 958 iov = aiov; 959#ifdef COMPAT_OLDSOCK 960 msg.msg_flags = uap->flags &~ MSG_COMPAT; 961#else 962 msg.msg_flags = uap->flags; 963#endif 964 uiov = msg.msg_iov; 965 msg.msg_iov = iov; 966 error = copyin((caddr_t)uiov, (caddr_t)iov, 967 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); 968 if (error) 969 goto done; 970 error = recvit(p, uap->s, &msg, (caddr_t)0, retval); 971 if (!error) { 972 msg.msg_iov = uiov; 973 error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg)); 974 } 975done: 976 if (iov != aiov) 977 FREE(iov, M_IOV); 978 return (error); 979} 980 981/* ARGSUSED */ 982int 983shutdown(p, uap, retval) 984 struct proc *p; 985 register struct shutdown_args /* { 986 int s; 987 int how; 988 } */ *uap; 989 int *retval; 990{ 991 struct file *fp; 992 int error; 993 994 error = getsock(p->p_fd, uap->s, &fp); 995 if (error) 996 return (error); 997 return (soshutdown((struct socket *)fp->f_data, uap->how)); 998} 999 1000/* ARGSUSED */ 1001int 1002setsockopt(p, uap, retval) 1003 struct proc *p; 1004 register struct setsockopt_args /* { 1005 int s; 1006 int level; 1007 int name; 1008 caddr_t val; 1009 int valsize; 1010 } */ *uap; 1011 int *retval; 1012{ 1013 struct file *fp; 1014 struct mbuf *m = NULL; 1015 int error; 1016 1017 error = getsock(p->p_fd, uap->s, &fp); 1018 if (error) 1019 return (error); 1020 if (uap->valsize > MLEN) 1021 return (EINVAL); 1022 if (uap->val) { 1023 m = m_get(M_WAIT, MT_SOOPTS); 1024 if (m == NULL) 1025 return (ENOBUFS); 1026 error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize); 1027 if (error) { 1028 (void) m_free(m); 1029 return (error); 1030 } 1031 m->m_len = uap->valsize; 1032 } 1033 return (sosetopt((struct socket *)fp->f_data, uap->level, 1034 uap->name, m, p)); 1035} 1036 1037/* ARGSUSED */ 1038int 1039getsockopt(p, uap, retval) 1040 struct proc *p; 1041 register struct getsockopt_args /* { 1042 int s; 1043 int level; 1044 int name; 1045 caddr_t val; 1046 int *avalsize; 1047 } */ *uap; 1048 int *retval; 1049{ 1050 struct file *fp; 1051 struct mbuf *m = NULL, *m0; 1052 int op, i, valsize, error; 1053 1054 error = getsock(p->p_fd, uap->s, &fp); 1055 if (error) 1056 return (error); 1057 if (uap->val) { 1058 error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize, 1059 sizeof (valsize)); 1060 if (error) 1061 return (error); 1062 } else 1063 valsize = 0; 1064 if ((error = sogetopt((struct socket *)fp->f_data, uap->level, 1065 uap->name, &m, p)) == 0 && uap->val && valsize && m != NULL) { 1066 op = 0; 1067 while (m && !error && op < valsize) { 1068 i = min(m->m_len, (valsize - op)); 1069 error = copyout(mtod(m, caddr_t), uap->val, (u_int)i); 1070 op += i; 1071 uap->val += i; 1072 m0 = m; 1073 MFREE(m0,m); 1074 } 1075 valsize = op; 1076 if (error == 0) 1077 error = copyout((caddr_t)&valsize, 1078 (caddr_t)uap->avalsize, sizeof (valsize)); 1079 } 1080 if (m != NULL) 1081 (void) m_free(m); 1082 return (error); 1083} 1084 1085/* 1086 * Get socket name. 1087 */ 1088/* ARGSUSED */ 1089static int 1090getsockname1(p, uap, retval, compat) 1091 struct proc *p; 1092 register struct getsockname_args /* { 1093 int fdes; 1094 caddr_t asa; 1095 int *alen; 1096 } */ *uap; 1097 int *retval; 1098 int compat; 1099{ 1100 struct file *fp; 1101 register struct socket *so; 1102 struct sockaddr *sa; 1103 int len, error; 1104 1105 error = getsock(p->p_fd, uap->fdes, &fp); 1106 if (error) 1107 return (error); 1108 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); 1109 if (error) 1110 return (error); 1111 so = (struct socket *)fp->f_data; 1112 sa = 0; 1113 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa); 1114 if (error) 1115 goto bad; 1116 if (sa == 0) { 1117 len = 0; 1118 goto gotnothing; 1119 } 1120 1121 len = MIN(len, sa->sa_len); 1122#ifdef COMPAT_OLDSOCK 1123 if (compat) 1124 ((struct osockaddr *)sa)->sa_family = sa->sa_family; 1125#endif 1126 error = copyout(sa, (caddr_t)uap->asa, (u_int)len); 1127 if (error == 0) 1128gotnothing: 1129 error = copyout((caddr_t)&len, (caddr_t)uap->alen, 1130 sizeof (len)); 1131bad: 1132 if (sa) 1133 FREE(sa, M_SONAME); 1134 return (error); 1135} 1136 1137int 1138getsockname(p, uap, retval) 1139 struct proc *p; 1140 struct getsockname_args *uap; 1141 int *retval; 1142{ 1143 1144 return (getsockname1(p, uap, retval, 0)); 1145} 1146 1147#ifdef COMPAT_OLDSOCK 1148int 1149ogetsockname(p, uap, retval) 1150 struct proc *p; 1151 struct getsockname_args *uap; 1152 int *retval; 1153{ 1154 1155 return (getsockname1(p, uap, retval, 1)); 1156} 1157#endif /* COMPAT_OLDSOCK */ 1158 1159/* 1160 * Get name of peer for connected socket. 1161 */ 1162/* ARGSUSED */ 1163static int 1164getpeername1(p, uap, retval, compat) 1165 struct proc *p; 1166 register struct getpeername_args /* { 1167 int fdes; 1168 caddr_t asa; 1169 int *alen; 1170 } */ *uap; 1171 int *retval; 1172 int compat; 1173{ 1174 struct file *fp; 1175 register struct socket *so; 1176 struct sockaddr *sa; 1177 int len, error; 1178 1179 error = getsock(p->p_fd, uap->fdes, &fp); 1180 if (error) 1181 return (error); 1182 so = (struct socket *)fp->f_data; 1183 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) 1184 return (ENOTCONN); 1185 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); 1186 if (error) 1187 return (error); 1188 sa = 0; 1189 error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa); 1190 if (error) 1191 goto bad; 1192 if (sa == 0) { 1193 len = 0; 1194 goto gotnothing; 1195 } 1196 len = MIN(len, sa->sa_len); 1197#ifdef COMPAT_OLDSOCK 1198 if (compat) 1199 ((struct osockaddr *)sa)->sa_family = 1200 sa->sa_family; 1201#endif 1202 error = copyout(sa, (caddr_t)uap->asa, (u_int)len); 1203 if (error) 1204 goto bad; 1205gotnothing: 1206 error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); 1207bad: 1208 if (sa) FREE(sa, M_SONAME); 1209 return (error); 1210} 1211 1212int 1213getpeername(p, uap, retval) 1214 struct proc *p; 1215 struct getpeername_args *uap; 1216 int *retval; 1217{ 1218 1219 return (getpeername1(p, uap, retval, 0)); 1220} 1221 1222#ifdef COMPAT_OLDSOCK 1223int 1224ogetpeername(p, uap, retval) 1225 struct proc *p; 1226 struct ogetpeername_args *uap; 1227 int *retval; 1228{ 1229 1230 /* XXX uap should have type `getpeername_args *' to begin with. */ 1231 return (getpeername1(p, (struct getpeername_args *)uap, retval, 1)); 1232} 1233#endif /* COMPAT_OLDSOCK */ 1234 1235int 1236sockargs(mp, buf, buflen, type) 1237 struct mbuf **mp; 1238 caddr_t buf; 1239 int buflen, type; 1240{ 1241 register struct sockaddr *sa; 1242 register struct mbuf *m; 1243 int error; 1244 1245 if ((u_int)buflen > MLEN) { 1246#ifdef COMPAT_OLDSOCK 1247 if (type == MT_SONAME && (u_int)buflen <= 112) 1248 buflen = MLEN; /* unix domain compat. hack */ 1249 else 1250#endif 1251 return (EINVAL); 1252 } 1253 m = m_get(M_WAIT, type); 1254 if (m == NULL) 1255 return (ENOBUFS); 1256 m->m_len = buflen; 1257 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen); 1258 if (error) 1259 (void) m_free(m); 1260 else { 1261 *mp = m; 1262 if (type == MT_SONAME) { 1263 sa = mtod(m, struct sockaddr *); 1264 1265#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN 1266 if (sa->sa_family == 0 && sa->sa_len < AF_MAX) 1267 sa->sa_family = sa->sa_len; 1268#endif 1269 sa->sa_len = buflen; 1270 } 1271 } 1272 return (error); 1273} 1274 1275int 1276getsockaddr(namp, uaddr, len) 1277 struct sockaddr **namp; 1278 caddr_t uaddr; 1279 size_t len; 1280{ 1281 struct sockaddr *sa; 1282 int error; 1283 1284 if (len > SOCK_MAXADDRLEN) 1285 return ENAMETOOLONG; 1286 MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK); 1287 error = copyin(uaddr, sa, len); 1288 if (error) { 1289 FREE(sa, M_SONAME); 1290 } else { 1291#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN 1292 if (sa->sa_family == 0 && sa->sa_len < AF_MAX) 1293 sa->sa_family = sa->sa_len; 1294#endif 1295 sa->sa_len = len; 1296 *namp = sa; 1297 } 1298 return error; 1299} 1300 1301int 1302getsock(fdp, fdes, fpp) 1303 struct filedesc *fdp; 1304 int fdes; 1305 struct file **fpp; 1306{ 1307 register struct file *fp; 1308 1309 if ((unsigned)fdes >= fdp->fd_nfiles || 1310 (fp = fdp->fd_ofiles[fdes]) == NULL) 1311 return (EBADF); 1312 if (fp->f_type != DTYPE_SOCKET) 1313 return (ENOTSOCK); 1314 *fpp = fp; 1315 return (0); 1316} 1317