|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1982, 1986, 1989, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * (c) UNIX System Laboratories, Inc. ! 27: * All or some portions of this file are derived from material licensed ! 28: * to the University of California by American Telephone and Telegraph ! 29: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 30: * the permission of UNIX System Laboratories, Inc. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)sys_generic.c 8.9 (Berkeley) 2/14/95 ! 61: */ ! 62: ! 63: #include <sys/param.h> ! 64: #include <sys/systm.h> ! 65: #include <sys/filedesc.h> ! 66: #include <sys/ioctl.h> ! 67: #include <sys/file.h> ! 68: #include <sys/proc.h> ! 69: #include <sys/socketvar.h> ! 70: #include <sys/uio.h> ! 71: #include <sys/kernel.h> ! 72: #include <sys/stat.h> ! 73: #include <sys/malloc.h> ! 74: ! 75: #if KTRACE ! 76: #include <sys/ktrace.h> ! 77: #endif ! 78: ! 79: #include <sys/mount.h> ! 80: #include <sys/protosw.h> ! 81: #include <sys/ev.h> ! 82: #include <sys/user.h> ! 83: #include <sys/kdebug.h> ! 84: #include <kern/assert.h> ! 85: #include <kern/thread_act.h> ! 86: ! 87: #include <sys/mbuf.h> ! 88: #include <sys/socket.h> ! 89: #include <sys/socketvar.h> ! 90: #include <sys/errno.h> ! 91: ! 92: #include <net/if.h> ! 93: #include <net/route.h> ! 94: ! 95: #include <netinet/in.h> ! 96: #include <netinet/in_systm.h> ! 97: #include <netinet/ip.h> ! 98: #include <netinet/in_pcb.h> ! 99: #include <netinet/ip_var.h> ! 100: #include <netinet/tcp.h> ! 101: #include <netinet/tcp_fsm.h> ! 102: #include <netinet/tcp_seq.h> ! 103: #include <netinet/tcp_timer.h> ! 104: #include <netinet/tcp_var.h> ! 105: #include <netinet/tcpip.h> ! 106: #include <netinet/tcp_debug.h> ! 107: ! 108: /* ! 109: * Read system call. ! 110: */ ! 111: struct read_args { ! 112: int fd; ! 113: char *cbuf; ! 114: u_int nbyte; ! 115: }; ! 116: /* ARGSUSED */ ! 117: read(p, uap, retval) ! 118: struct proc *p; ! 119: register struct read_args *uap; ! 120: register_t *retval; ! 121: { ! 122: struct uio auio; ! 123: struct iovec aiov; ! 124: ! 125: aiov.iov_base = (caddr_t)uap->cbuf; ! 126: aiov.iov_len = uap->nbyte; ! 127: auio.uio_iov = &aiov; ! 128: auio.uio_iovcnt = 1; ! 129: auio.uio_rw = UIO_READ; ! 130: return (rwuio(p, uap->fd, &auio, UIO_READ, retval)); ! 131: } ! 132: ! 133: struct readv_args { ! 134: int fd; ! 135: struct iovec *iovp; ! 136: u_int iovcnt; ! 137: }; ! 138: readv(p, uap, retval) ! 139: struct proc *p; ! 140: register struct readv_args *uap; ! 141: int *retval; ! 142: { ! 143: struct uio auio; ! 144: register struct iovec *iov; ! 145: int error; ! 146: struct iovec aiov[UIO_SMALLIOV]; ! 147: ! 148: if (uap->iovcnt > UIO_SMALLIOV) { ! 149: if (uap->iovcnt > UIO_MAXIOV) ! 150: return (EINVAL); ! 151: if ((iov = (struct iovec *) ! 152: kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0) ! 153: return (ENOMEM); ! 154: } else ! 155: iov = aiov; ! 156: auio.uio_iov = iov; ! 157: auio.uio_iovcnt = uap->iovcnt; ! 158: auio.uio_rw = UIO_READ; ! 159: error = copyin((caddr_t)uap->iovp, (caddr_t)iov, ! 160: uap->iovcnt * sizeof (struct iovec)); ! 161: if (!error) ! 162: error = rwuio(p, uap->fd, &auio, UIO_READ, retval); ! 163: if (uap->iovcnt > UIO_SMALLIOV) ! 164: kfree(iov, sizeof(struct iovec)*uap->iovcnt); ! 165: return (error); ! 166: } ! 167: ! 168: /* ! 169: * Write system call ! 170: */ ! 171: struct write_args { ! 172: int fd; ! 173: char *cbuf; ! 174: u_int nbyte; ! 175: }; ! 176: write(p, uap, retval) ! 177: struct proc *p; ! 178: register struct write_args *uap; ! 179: int *retval; ! 180: { ! 181: struct uio auio; ! 182: struct iovec aiov; ! 183: ! 184: aiov.iov_base = uap->cbuf; ! 185: aiov.iov_len = uap->nbyte; ! 186: auio.uio_iov = &aiov; ! 187: auio.uio_iovcnt = 1; ! 188: auio.uio_rw = UIO_WRITE; ! 189: return (rwuio(p, uap->fd, &auio, UIO_WRITE, retval)); ! 190: } ! 191: ! 192: struct writev_args { ! 193: int fd; ! 194: struct iovec *iovp; ! 195: u_int iovcnt; ! 196: }; ! 197: writev(p, uap, retval) ! 198: struct proc *p; ! 199: register struct writev_args *uap; ! 200: int *retval; ! 201: { ! 202: struct uio auio; ! 203: register struct iovec *iov; ! 204: int error; ! 205: struct iovec aiov[UIO_SMALLIOV]; ! 206: ! 207: if (uap->iovcnt > UIO_SMALLIOV) { ! 208: if (uap->iovcnt > UIO_MAXIOV) ! 209: return (EINVAL); ! 210: if ((iov = (struct iovec *) ! 211: kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0) ! 212: return (ENOMEM); ! 213: } else ! 214: iov = aiov; ! 215: auio.uio_iov = iov; ! 216: auio.uio_iovcnt = uap->iovcnt; ! 217: auio.uio_rw = UIO_WRITE; ! 218: error = copyin((caddr_t)uap->iovp, (caddr_t)iov, ! 219: uap->iovcnt * sizeof (struct iovec)); ! 220: if (!error) ! 221: error = rwuio(p, uap->fd, &auio, UIO_WRITE, retval); ! 222: if (uap->iovcnt > UIO_SMALLIOV) ! 223: kfree(iov, sizeof(struct iovec)*uap->iovcnt); ! 224: return (error); ! 225: } ! 226: ! 227: rwuio(p, fdes, uio, rw, retval) ! 228: struct proc *p; ! 229: int fdes; ! 230: register struct uio *uio; ! 231: enum uio_rw rw; ! 232: int *retval; ! 233: { ! 234: register struct file *fp; ! 235: register struct iovec *iov; ! 236: int i, count, flag, error; ! 237: ! 238: if (error = fdgetf(p, fdes, &fp)) ! 239: return (error); ! 240: ! 241: if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { ! 242: return(EBADF); ! 243: } ! 244: uio->uio_resid = 0; ! 245: uio->uio_segflg = UIO_USERSPACE; ! 246: uio->uio_procp = p; ! 247: iov = uio->uio_iov; ! 248: for (i = 0; i < uio->uio_iovcnt; i++) { ! 249: if (iov->iov_len < 0) { ! 250: return(EINVAL); ! 251: } ! 252: uio->uio_resid += iov->iov_len; ! 253: if (uio->uio_resid < 0) { ! 254: return(EINVAL); ! 255: } ! 256: iov++; ! 257: } ! 258: count = uio->uio_resid; ! 259: if (rw == UIO_READ) { ! 260: if (error = (*fp->f_ops->fo_read)(fp, uio, fp->f_cred)) ! 261: if (uio->uio_resid != count && (error == ERESTART || ! 262: error == EINTR || error == EWOULDBLOCK)) ! 263: error = 0; ! 264: } else { ! 265: if (error = (*fp->f_ops->fo_write)(fp, uio, fp->f_cred)) { ! 266: if (uio->uio_resid != count && (error == ERESTART || ! 267: error == EINTR || error == EWOULDBLOCK)) ! 268: error = 0; ! 269: if (error == EPIPE) ! 270: psignal(p, SIGPIPE); ! 271: } ! 272: } ! 273: *retval = count - uio->uio_resid; ! 274: return(error); ! 275: } ! 276: ! 277: /* ! 278: * Ioctl system call ! 279: */ ! 280: struct ioctl_args { ! 281: int fd; ! 282: u_long com; ! 283: caddr_t data; ! 284: }; ! 285: /* ARGSUSED */ ! 286: ioctl(p, uap, retval) ! 287: struct proc *p; ! 288: register struct ioctl_args *uap; ! 289: register_t *retval; ! 290: { ! 291: register struct file *fp; ! 292: register u_long com; ! 293: register int error; ! 294: register u_int size; ! 295: caddr_t data, memp; ! 296: int tmp; ! 297: #define STK_PARAMS 128 ! 298: char stkbuf[STK_PARAMS]; ! 299: ! 300: if (error = fdgetf(p, uap->fd, &fp)) ! 301: return (error); ! 302: ! 303: if ((fp->f_flag & (FREAD | FWRITE)) == 0) ! 304: return (EBADF); ! 305: ! 306: /*### LD 6/11/97 Hack Alert: this is to get AppleTalk to work ! 307: * while implementing an ATioctl system call ! 308: */ ! 309: #if NETAT ! 310: { ! 311: extern int appletalk_inited; ! 312: ! 313: if (appletalk_inited && ((uap->com & 0x0000FFFF) == 0xff99)) { ! 314: #ifdef APPLETALK_DEBUG ! 315: kprintf("ioctl: special AppleTalk \n"); ! 316: #endif ! 317: error = (*fp->f_ops->fo_ioctl)(fp, uap->com, uap->data, p); ! 318: return(error); ! 319: } ! 320: } ! 321: ! 322: #endif /* NETAT */ ! 323: ! 324: ! 325: switch (com = uap->com) { ! 326: case FIONCLEX: ! 327: *fdflags(p, uap->fd) &= ~UF_EXCLOSE; ! 328: return (0); ! 329: case FIOCLEX: ! 330: *fdflags(p, uap->fd) |= UF_EXCLOSE; ! 331: return (0); ! 332: } ! 333: ! 334: /* ! 335: * Interpret high order word to find amount of data to be ! 336: * copied to/from the user's address space. ! 337: */ ! 338: size = IOCPARM_LEN(com); ! 339: if (size > IOCPARM_MAX) ! 340: return (ENOTTY); ! 341: memp = NULL; ! 342: if (size > sizeof (stkbuf)) { ! 343: if ((memp = (caddr_t)kalloc(size)) == 0) ! 344: return(ENOMEM); ! 345: data = memp; ! 346: } else ! 347: data = stkbuf; ! 348: if (com&IOC_IN) { ! 349: if (size) { ! 350: error = copyin(uap->data, data, (u_int)size); ! 351: if (error) { ! 352: if (memp) ! 353: kfree(memp, size); ! 354: return (error); ! 355: } ! 356: } else ! 357: *(caddr_t *)data = uap->data; ! 358: } else if ((com&IOC_OUT) && size) ! 359: /* ! 360: * Zero the buffer so the user always ! 361: * gets back something deterministic. ! 362: */ ! 363: bzero(data, size); ! 364: else if (com&IOC_VOID) ! 365: *(caddr_t *)data = uap->data; ! 366: ! 367: switch (com) { ! 368: ! 369: case FIONBIO: ! 370: if (tmp = *(int *)data) ! 371: fp->f_flag |= FNONBLOCK; ! 372: else ! 373: fp->f_flag &= ~FNONBLOCK; ! 374: error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); ! 375: break; ! 376: ! 377: case FIOASYNC: ! 378: if (tmp = *(int *)data) ! 379: fp->f_flag |= FASYNC; ! 380: else ! 381: fp->f_flag &= ~FASYNC; ! 382: error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); ! 383: break; ! 384: ! 385: case FIOSETOWN: ! 386: tmp = *(int *)data; ! 387: if (fp->f_type == DTYPE_SOCKET) { ! 388: ((struct socket *)fp->f_data)->so_pgid = tmp; ! 389: error = 0; ! 390: break; ! 391: } ! 392: if (tmp <= 0) { ! 393: tmp = -tmp; ! 394: } else { ! 395: struct proc *p1 = pfind(tmp); ! 396: if (p1 == 0) { ! 397: error = ESRCH; ! 398: break; ! 399: } ! 400: tmp = p1->p_pgrp->pg_id; ! 401: } ! 402: error = (*fp->f_ops->fo_ioctl) ! 403: (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); ! 404: break; ! 405: ! 406: case FIOGETOWN: ! 407: if (fp->f_type == DTYPE_SOCKET) { ! 408: error = 0; ! 409: *(int *)data = ((struct socket *)fp->f_data)->so_pgid; ! 410: break; ! 411: } ! 412: error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p); ! 413: *(int *)data = -*(int *)data; ! 414: break; ! 415: ! 416: default: ! 417: error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); ! 418: /* ! 419: * Copy any data to user, size was ! 420: * already set and checked above. ! 421: */ ! 422: if (error == 0 && (com&IOC_OUT) && size) ! 423: error = copyout(data, uap->data, (u_int)size); ! 424: break; ! 425: } ! 426: if (memp) ! 427: kfree(memp, size); ! 428: return (error); ! 429: } ! 430: ! 431: ! 432: int selwait, nselcoll; ! 433: ! 434: /* ! 435: * Select system call. ! 436: */ ! 437: struct select_args { ! 438: u_int nd; ! 439: fd_set *in; ! 440: fd_set *ou; ! 441: fd_set *ex; ! 442: struct timeval *tv; ! 443: }; ! 444: ! 445: int selcontinue(int error); ! 446: ! 447: select(p, uap, retval) ! 448: register struct proc *p; ! 449: register struct select_args *uap; ! 450: register_t *retval; ! 451: { ! 452: int s, ncoll, error = 0, timo; ! 453: u_int ni; ! 454: struct thread *th; ! 455: thread_act_t th_act; ! 456: struct uthread *uth; ! 457: struct _select *sel; ! 458: ! 459: th = current_thread(); ! 460: th_act = current_act(); ! 461: uth = get_bsdthread_info(th_act); ! 462: sel = &uth->uu_state.ss_select; ! 463: ! 464: bzero((caddr_t)&sel->ibits[0], sizeof(sel->ibits)); ! 465: bzero((caddr_t)&sel->obits[0], sizeof(sel->obits)); ! 466: ! 467: if (uap->nd > FD_SETSIZE) ! 468: return (EINVAL); ! 469: if (uap->nd > p->p_fd->fd_nfiles) { ! 470: /* forgiving; slightly wrong */ ! 471: uap->nd = p->p_fd->fd_nfiles; ! 472: } ! 473: ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); ! 474: ! 475: #define getbits(name, x) \ ! 476: if (uap->name && (error = copyin((caddr_t)uap->name, \ ! 477: (caddr_t)&sel->ibits[x], ni))) \ ! 478: goto contin; ! 479: getbits(in, 0); ! 480: getbits(ou, 1); ! 481: getbits(ex, 2); ! 482: #undef getbits ! 483: ! 484: if (uap->tv) { ! 485: error = copyin((caddr_t)uap->tv, (caddr_t)&sel->atv, ! 486: sizeof (sel->atv)); ! 487: if (error) ! 488: goto contin; ! 489: if (itimerfix(&sel->atv)) { ! 490: error = EINVAL; ! 491: goto contin; ! 492: } ! 493: s = splhigh(); ! 494: timeradd(&sel->atv, &time, &sel->atv); ! 495: timo = hzto(&sel->atv); ! 496: splx(s); ! 497: } else ! 498: timo = 0; ! 499: sel->poll = timo; ! 500: contin: ! 501: selcontinue(error); ! 502: } ! 503: ! 504: int ! 505: selcontinue(error) ! 506: { ! 507: int s, ncoll, timo; ! 508: u_int ni; ! 509: struct thread *th; ! 510: thread_act_t th_act; ! 511: struct uthread *uth; ! 512: struct proc *p; ! 513: struct select_args *uap; ! 514: int *retval; ! 515: struct _select *sel; ! 516: ! 517: th = (struct thread *)current_thread(); ! 518: th_act = current_act(); ! 519: uth = get_bsdthread_info(th_act); ! 520: p = (struct proc *)get_bsdtask_info(current_task()); ! 521: uap = (struct select_args *)get_bsduthreadarg(th_act); ! 522: retval = (int *)get_bsduthreadrval(th_act); ! 523: sel = &uth->uu_state.ss_select; ! 524: ! 525: retry: ! 526: if (error != 0) ! 527: goto done; ! 528: ncoll = nselcoll; ! 529: p->p_flag |= P_SELECT; ! 530: error = selscan(p, &sel->ibits[0], &sel->obits[0], uap->nd, retval); ! 531: if (error || *retval) ! 532: goto done; ! 533: s = splhigh(); ! 534: /* this should be timercmp(&time, &atv, >=) */ ! 535: if (uap->tv && (time.tv_sec > sel->atv.tv_sec || ! 536: time.tv_sec == sel->atv.tv_sec && time.tv_usec >= sel->atv.tv_usec)) { ! 537: splx(s); ! 538: goto done; ! 539: } ! 540: /* ! 541: * To effect a poll, the timeout argument should be ! 542: * non-nil, pointing to a zero-valued timeval structure. ! 543: */ ! 544: timo = sel->poll; ! 545: ! 546: if (uap->tv && (timo == 0)) { ! 547: splx(s); ! 548: goto done; ! 549: } ! 550: if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { ! 551: splx(s); ! 552: goto retry; ! 553: } ! 554: p->p_flag &= ~P_SELECT; ! 555: ! 556: #if 1 ! 557: error = tsleep0((caddr_t)&selwait, PSOCK | PCATCH, "select", timo, selcontinue); ! 558: /* NOTREACHED */ ! 559: #else ! 560: error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); ! 561: #endif ! 562: splx(s); ! 563: if (error == 0) ! 564: goto retry; ! 565: done: ! 566: p->p_flag &= ~P_SELECT; ! 567: /* select is not restarted after signals... */ ! 568: if (error == ERESTART) ! 569: error = EINTR; ! 570: if (error == EWOULDBLOCK) ! 571: error = 0; ! 572: ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); ! 573: #define putbits(name, x) \ ! 574: if (uap->name && (error2 = copyout((caddr_t)&sel->obits[x], \ ! 575: (caddr_t)uap->name, ni))) \ ! 576: error = error2; ! 577: if (error == 0) { ! 578: int error2; ! 579: ! 580: putbits(in, 0); ! 581: putbits(ou, 1); ! 582: putbits(ex, 2); ! 583: #undef putbits ! 584: } ! 585: ! 586: unix_syscall_return(error); ! 587: } ! 588: ! 589: selscan(p, ibits, obits, nfd, retval) ! 590: struct proc *p; ! 591: fd_set *ibits, *obits; ! 592: int nfd; ! 593: register_t *retval; ! 594: { ! 595: register struct filedesc *fdp = p->p_fd; ! 596: register int msk, i, j, fd; ! 597: register fd_mask bits; ! 598: struct file *fp; ! 599: int n = 0; ! 600: static int flag[3] = { FREAD, FWRITE, 0 }; ! 601: ! 602: /* Problems when reboot; due to MacOSX signal probs ! 603: * in Beaker1C ; verify that the p->p_fd is valid ! 604: */ ! 605: if (fdp == NULL) { ! 606: *retval=0; ! 607: return(EIO); ! 608: } ! 609: ! 610: for (msk = 0; msk < 3; msk++) { ! 611: for (i = 0; i < nfd; i += NFDBITS) { ! 612: bits = ibits[msk].fds_bits[i/NFDBITS]; ! 613: while ((j = ffs(bits)) && (fd = i + --j) < nfd) { ! 614: bits &= ~(1 << j); ! 615: fp = fdp->fd_ofiles[fd]; ! 616: if (fp == NULL || (fdp->fd_ofileflags[fd] & ! 617: UF_RESERVED)) ! 618: return (EBADF); ! 619: if (fp->f_ops && (*fp->f_ops->fo_select)(fp, flag[msk], p)) { ! 620: FD_SET(fd, &obits[msk]); ! 621: n++; ! 622: } ! 623: } ! 624: } ! 625: } ! 626: *retval = n; ! 627: return (0); ! 628: } ! 629: ! 630: /*ARGSUSED*/ ! 631: seltrue(dev, flag, p) ! 632: dev_t dev; ! 633: int flag; ! 634: struct proc *p; ! 635: { ! 636: ! 637: return (1); ! 638: } ! 639: ! 640: /* ! 641: * Record a select request. ! 642: */ ! 643: void ! 644: selrecord(selector, sip) ! 645: struct proc *selector; ! 646: struct selinfo *sip; ! 647: { ! 648: int oldpri = splhigh(); ! 649: thread_t my_thread = current_thread(); ! 650: thread_t selthread; ! 651: ! 652: selthread = sip->si_thread; ! 653: ! 654: if (selthread == my_thread) { ! 655: splx(oldpri); ! 656: return; ! 657: } ! 658: ! 659: if (selthread && is_thread_active(selthread) && ! 660: get_thread_waitevent(selthread) == (caddr_t)&selwait) { ! 661: sip->si_flags |= SI_COLL; ! 662: splx(oldpri); ! 663: } ! 664: else { ! 665: sip->si_thread = my_thread; ! 666: splx(oldpri); ! 667: if (selthread) { ! 668: /* thread_deallocate(selthread); */ ! 669: act_deallocate(getact_thread(selthread)); ! 670: } ! 671: /* do I need act reference ??? */ ! 672: /* thread_reference(sip->si_thread); */ ! 673: act_reference(getact_thread(sip->si_thread)); ! 674: } ! 675: ! 676: return; ! 677: } ! 678: ! 679: void ! 680: selwakeup(sip) ! 681: register struct selinfo *sip; ! 682: { ! 683: register thread_t the_thread = (thread_t)sip->si_thread; ! 684: int oldpri; ! 685: struct proc *p; ! 686: thread_act_t th_act; ! 687: ! 688: if (the_thread == 0) ! 689: return; ! 690: ! 691: if (sip->si_flags & SI_COLL) { ! 692: nselcoll++; ! 693: sip->si_flags &= ~SI_COLL; ! 694: wakeup((caddr_t)&selwait); ! 695: } ! 696: ! 697: oldpri = splhigh(); ! 698: ! 699: th_act = getact_thread(the_thread); ! 700: ! 701: if (is_thread_active(the_thread)) { ! 702: /* protect p_flag minimally at splsched() */ ! 703: if (get_thread_waitevent(the_thread) == &selwait) ! 704: clear_wait(the_thread, THREAD_AWAKENED, TRUE); ! 705: if (p=(struct proc *)(get_bsdtask_info(get_threadtask(th_act)))) ! 706: p->p_flag &= ~P_SELECT; ! 707: } ! 708: ! 709: th_act = getact_thread(the_thread); ! 710: ! 711: act_deallocate(th_act); ! 712: ! 713: sip->si_thread = 0; ! 714: ! 715: splx(oldpri); ! 716: ! 717: } ! 718: ! 719: void selthreadclear(sip) ! 720: register struct selinfo *sip; ! 721: { ! 722: thread_act_t th_act; ! 723: ! 724: if (sip->si_thread) { ! 725: th_act = getact_thread(sip->si_thread); ! 726: act_deallocate(th_act); ! 727: } ! 728: ! 729: } ! 730: /* ! 731: * called upon socket close. deque and free all events for ! 732: * the socket ! 733: */ ! 734: evsofree(struct socket *sp) ! 735: { ! 736: struct eventqelt *eqp, *next; ! 737: ! 738: if (sp == NULL) return; ! 739: ! 740: for (eqp = sp->so_evlist.tqh_first; eqp != NULL; eqp = next) { ! 741: next = eqp->ee_slist.tqe_next; ! 742: evprocdeque(eqp->ee_proc, eqp); // remove from proc q if there ! 743: TAILQ_REMOVE(&sp->so_evlist, eqp, ee_slist); // remove from socket q ! 744: FREE(eqp, M_TEMP); ! 745: } ! 746: } ! 747: ! 748: ! 749: #define DBG_EVENT 0x10 ! 750: ! 751: #define DBG_POST 0x10 ! 752: #define DBG_WATCH 0x11 ! 753: #define DBG_WAIT 0x12 ! 754: #define DBG_MOD 0x13 ! 755: #define DBG_EWAKEUP 0x14 ! 756: ! 757: #define DBG_MISC_POST MISCDBG_CODE(DBG_EVENT,DBG_POST) ! 758: #define DBG_MISC_WATCH MISCDBG_CODE(DBG_EVENT,DBG_WATCH) ! 759: #define DBG_MISC_WAIT MISCDBG_CODE(DBG_EVENT,DBG_WAIT) ! 760: #define DBG_MISC_MOD MISCDBG_CODE(DBG_EVENT,DBG_MOD) ! 761: #define DBG_MISC_EWAKEUP MISCDBG_CODE(DBG_EVENT,DBG_EWAKEUP) ! 762: ! 763: ! 764: ! 765: /* ! 766: * enque this event if it's not already queued. wakeup ! 767: the proc if we do queue this event to it. ! 768: */ ! 769: evprocenque(struct eventqelt *eqp) ! 770: { ! 771: struct proc *p; ! 772: ! 773: assert(eqp); ! 774: if (eqp->ee_flags & EV_QUEUED) { ! 775: return; ! 776: } ! 777: eqp->ee_flags |= EV_QUEUED; ! 778: eqp->ee_eventmask = 0; // disarm ! 779: p = eqp->ee_proc; ! 780: TAILQ_INSERT_TAIL(&p->p_evlist, eqp, ee_plist); ! 781: KERNEL_DEBUG(DBG_MISC_EWAKEUP,0,0,0,eqp,0); ! 782: wakeup(&p->p_evlist); ! 783: } ! 784: ! 785: /* ! 786: * given either a sockbuf or a socket run down the ! 787: * event list and queue ready events found ! 788: */ ! 789: postevent(struct socket *sp, struct sockbuf *sb, int event) ! 790: { ! 791: int mask; ! 792: struct eventqelt *evq; ! 793: register struct tcpcb *tp; ! 794: ! 795: if (sb) sp = sb->sb_so; ! 796: if (!sp || sp->so_evlist.tqh_first == NULL) return; ! 797: ! 798: KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_START, 0,0,0,0,0); ! 799: ! 800: for (evq = sp->so_evlist.tqh_first; ! 801: evq != NULL; evq = evq->ee_slist.tqe_next) { ! 802: ! 803: mask = 0; ! 804: ! 805: /* ready for reading: ! 806: - byte cnt >= receive low water mark ! 807: - read-half of conn closed ! 808: - conn pending for listening sock ! 809: - socket error pending ! 810: ! 811: ready for writing ! 812: - byte cnt avail >= send low water mark ! 813: - write half of conn closed ! 814: - socket error pending ! 815: - non-blocking conn completed successfully ! 816: ! 817: exception pending ! 818: - out of band data ! 819: - sock at out of band mark ! 820: ! 821: */ ! 822: switch (event & EV_DMASK) { ! 823: ! 824: case EV_RWBYTES: ! 825: case EV_OOB: ! 826: case EV_RWBYTES|EV_OOB: ! 827: if (event & EV_OOB) { ! 828: if ((evq->ee_eventmask & EV_EX)) { ! 829: if (sp->so_oobmark || ((sp->so_state & SS_RCVATMARK))) { ! 830: mask |= EV_EX|EV_OOB; ! 831: } ! 832: } ! 833: } ! 834: if (event & EV_RWBYTES) { ! 835: if ((evq->ee_eventmask & EV_RE) && soreadable(sp)) { ! 836: if ((sp->so_type == SOCK_STREAM) && (sp->so_error == ECONNREFUSED) || ! 837: (sp->so_error == ECONNRESET)) { ! 838: if ((sp->so_pcb == 0) || ! 839: !(tp = sototcpcb(sp)) || ! 840: (tp->t_state == TCPS_CLOSED)) { ! 841: mask |= EV_RE|EV_RESET; ! 842: break; ! 843: } ! 844: } ! 845: if (sp->so_state & SS_CANTRCVMORE) { ! 846: mask |= EV_RE|EV_FIN; ! 847: evq->ee_req.er_rcnt = sp->so_rcv.sb_cc; ! 848: break; ! 849: } ! 850: mask |= EV_RE; ! 851: evq->ee_req.er_rcnt = sp->so_rcv.sb_cc; ! 852: } ! 853: ! 854: if ((evq->ee_eventmask & EV_WR) && sowriteable(sp)) { ! 855: if ((sp->so_type == SOCK_STREAM) &&(sp->so_error == ECONNREFUSED) || ! 856: (sp->so_error == ECONNRESET)) { ! 857: if ((sp->so_pcb == 0) || ! 858: !(tp = sototcpcb(sp)) || ! 859: (tp->t_state == TCPS_CLOSED)) { ! 860: mask |= EV_WR|EV_RESET; ! 861: break; ! 862: } ! 863: } ! 864: mask |= EV_WR; ! 865: evq->ee_req.er_wcnt = sbspace(&sp->so_snd); ! 866: } ! 867: } ! 868: break; ! 869: ! 870: case EV_RCONN: ! 871: if ((evq->ee_eventmask & EV_RE)) { ! 872: evq->ee_req.er_rcnt = sp->so_qlen + 1; // incl this one ! 873: mask |= EV_RE|EV_RCONN; ! 874: } ! 875: break; ! 876: ! 877: case EV_WCONN: ! 878: if ((evq->ee_eventmask & EV_WR)) { ! 879: mask |= EV_WR|EV_WCONN; ! 880: } ! 881: break; ! 882: ! 883: case EV_RCLOSED: ! 884: if ((evq->ee_eventmask & EV_RE)) { ! 885: mask |= EV_RE|EV_RCLOSED; ! 886: } ! 887: break; ! 888: ! 889: case EV_WCLOSED: ! 890: if ((evq->ee_eventmask & EV_WR)) { ! 891: mask |= EV_WR|EV_WCLOSED; ! 892: } ! 893: break; ! 894: ! 895: case EV_FIN: ! 896: if (evq->ee_eventmask & EV_RE) { ! 897: mask |= EV_RE|EV_FIN; ! 898: } ! 899: break; ! 900: ! 901: case EV_RESET: ! 902: case EV_TIMEOUT: ! 903: if (evq->ee_eventmask & EV_RE) { ! 904: mask |= EV_RE | event; ! 905: } ! 906: if (evq->ee_eventmask & EV_WR) { ! 907: mask |= EV_WR | event; ! 908: } ! 909: break; ! 910: ! 911: default: ! 912: return; ! 913: } /* switch */ ! 914: ! 915: if (mask) { ! 916: evq->ee_req.er_eventbits |= mask; ! 917: evprocenque(evq); ! 918: } ! 919: } ! 920: KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_END, 0,0,0,0,0); ! 921: } ! 922: ! 923: /* ! 924: * remove and return the first event (eqp=NULL) or a specific ! 925: * event, or return NULL if no events found ! 926: */ ! 927: struct eventqelt * ! 928: evprocdeque(struct proc *p, struct eventqelt *eqp) ! 929: { ! 930: ! 931: ! 932: if (eqp && ((eqp->ee_flags & EV_QUEUED) == NULL)) ! 933: return(NULL); ! 934: if (p->p_evlist.tqh_first == NULL) ! 935: return(NULL); ! 936: if (eqp == NULL) { // remove first ! 937: eqp = p->p_evlist.tqh_first; ! 938: } ! 939: TAILQ_REMOVE(&p->p_evlist, eqp, ee_plist); ! 940: eqp->ee_flags &= ~EV_QUEUED; ! 941: return(eqp); ! 942: } ! 943: ! 944: struct evwatch_args { ! 945: struct eventreq *u_req; ! 946: int u_eventmask; ! 947: }; ! 948: ! 949: ! 950: /* ! 951: * watchevent system call. user passes us an event to watch ! 952: * for. we malloc an event object, initialize it, and queue ! 953: * it to the open socket. when the event occurs, postevent() ! 954: * will enque it back to our proc where we can retrieve it ! 955: * via waitevent(). ! 956: * ! 957: * should this prevent duplicate events on same socket? ! 958: */ ! 959: int ! 960: watchevent(p, uap, retval) ! 961: struct proc *p; ! 962: struct evwatch_args *uap; ! 963: register_t *retval; ! 964: { ! 965: struct eventqelt *eqp = (struct eventqelt *)0; ! 966: struct eventqelt *np; ! 967: struct eventreq *erp; ! 968: struct file *fp; ! 969: struct socket *sp; ! 970: int error; ! 971: ! 972: // get a qelt and fill with users req ! 973: MALLOC(eqp, struct eventqelt *, sizeof(struct eventqelt), M_TEMP, M_WAITOK); ! 974: if (!eqp) panic("can't MALLOC eqp"); ! 975: erp = &eqp->ee_req; ! 976: // get users request pkt ! 977: if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp, ! 978: sizeof(struct eventreq))) { ! 979: FREE(eqp, M_TEMP); ! 980: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 981: return(error); ! 982: } ! 983: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_START, 0, ! 984: erp->er_handle,uap->u_eventmask,eqp,0); ! 985: // validate, freeing qelt if errors ! 986: error = 0; ! 987: if (erp->er_type != EV_FD) { ! 988: error = EINVAL; ! 989: } else if (erp->er_handle < 0) { ! 990: error = EBADF; ! 991: } else if (erp->er_handle > p->p_fd->fd_nfiles) { ! 992: error = EBADF; ! 993: } else if ((fp = *fdfile(p, erp->er_handle)) == NULL) { ! 994: error = EBADF; ! 995: } else if (fp->f_type != DTYPE_SOCKET) { ! 996: error = EINVAL; ! 997: } ! 998: if (error) { ! 999: FREE(eqp,M_TEMP); ! 1000: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 1001: return(error); ! 1002: } ! 1003: ! 1004: erp->er_rcnt = erp->er_wcnt = erp->er_eventbits = 0; ! 1005: eqp->ee_proc = p; ! 1006: eqp->ee_eventmask = uap->u_eventmask & EV_MASK; ! 1007: eqp->ee_flags = 0; ! 1008: ! 1009: sp = (struct socket *)fp->f_data; ! 1010: assert(sp != NULL); ! 1011: ! 1012: // only allow one watch per file per proc ! 1013: for (np = sp->so_evlist.tqh_first; np != NULL; np = np->ee_slist.tqe_next) { ! 1014: if (np->ee_proc == p) { ! 1015: FREE(eqp,M_TEMP); ! 1016: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 1017: return(EINVAL); ! 1018: } ! 1019: } ! 1020: ! 1021: TAILQ_INSERT_TAIL(&sp->so_evlist, eqp, ee_slist); ! 1022: postevent(sp, 0, EV_RWBYTES); // catch existing events ! 1023: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 1024: return(0); ! 1025: } ! 1026: ! 1027: struct evwait_args { ! 1028: struct eventreq *u_req; ! 1029: struct timeval *tv; ! 1030: }; ! 1031: ! 1032: /* ! 1033: * waitevent system call. ! 1034: * grabs the next waiting event for this proc and returns ! 1035: * it. if no events, user can request to sleep with timeout ! 1036: * or poll mode (tv=NULL); ! 1037: */ ! 1038: int ! 1039: waitevent(p, uap, retval) ! 1040: struct proc *p; ! 1041: struct evwait_args *uap; ! 1042: register_t *retval; ! 1043: { ! 1044: int error = 0; ! 1045: struct eventqelt *eqp; ! 1046: int timo; ! 1047: struct timeval atv; ! 1048: int s; ! 1049: ! 1050: if (uap->tv) { ! 1051: error = copyin((caddr_t)uap->tv, (caddr_t)&atv, ! 1052: sizeof (atv)); ! 1053: if (error) ! 1054: return(error); ! 1055: if (itimerfix(&atv)) { ! 1056: error = EINVAL; ! 1057: return(error); ! 1058: } ! 1059: s = splhigh(); ! 1060: timeradd(&atv, &time, &atv); ! 1061: timo = hzto(&atv); ! 1062: splx(s); ! 1063: } else ! 1064: timo = 0; ! 1065: ! 1066: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_START, 0,0,0,0,0); ! 1067: ! 1068: retry: ! 1069: s = splhigh(); ! 1070: if ((eqp = evprocdeque(p,NULL)) != NULL) { ! 1071: splx(s); ! 1072: error = copyout((caddr_t)&eqp->ee_req, (caddr_t)uap->u_req, ! 1073: sizeof(struct eventreq)); ! 1074: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0, ! 1075: eqp->ee_req.er_handle,eqp->ee_req.er_eventbits,eqp,0); ! 1076: return(error); ! 1077: } else { ! 1078: if (uap->tv && (timo == 0)) { ! 1079: splx(s); ! 1080: *retval = 1; // poll failed ! 1081: return(error); ! 1082: } ! 1083: ! 1084: KERNEL_DEBUG(DBG_MISC_WAIT, 1,0,0,0,0); ! 1085: error = tsleep(&p->p_evlist, PSOCK | PCATCH, "waitevent", timo); ! 1086: KERNEL_DEBUG(DBG_MISC_WAIT, 0,0,2,p->p_evlist.tqh_first,0); ! 1087: splx(s); ! 1088: if (error == 0) ! 1089: goto retry; ! 1090: if (error == ERESTART) ! 1091: error = EINTR; ! 1092: if (error == EWOULDBLOCK) { ! 1093: *retval = 1; ! 1094: error = 0; ! 1095: } ! 1096: } ! 1097: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,0,0,0,0); ! 1098: return(error); ! 1099: } ! 1100: ! 1101: struct modwatch_args { ! 1102: struct eventreq *u_req; ! 1103: int u_eventmask; ! 1104: }; ! 1105: ! 1106: /* ! 1107: * modwatch system call. user passes in event to modify. ! 1108: * if we find it we reset the event bits and que/deque event ! 1109: * it needed. ! 1110: */ ! 1111: int ! 1112: modwatch(p, uap, retval) ! 1113: struct proc *p; ! 1114: struct modwatch_args *uap; ! 1115: register_t *retval; ! 1116: { ! 1117: struct eventreq er; ! 1118: struct eventreq *erp = &er; ! 1119: struct eventqelt *evq; ! 1120: int error; ! 1121: struct file *fp; ! 1122: struct socket *sp; ! 1123: int flag; ! 1124: ! 1125: ! 1126: // get users request pkt ! 1127: if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp, ! 1128: sizeof(struct eventreq))) return(error); ! 1129: ! 1130: if (erp->er_type != EV_FD) return(EINVAL); ! 1131: if (erp->er_handle < 0) return(EBADF); ! 1132: if (erp->er_handle > p->p_fd->fd_nfiles) return(EBADF); ! 1133: if ((fp = *fdfile(p, erp->er_handle)) == NULL) ! 1134: return(EBADF); ! 1135: if (fp->f_type != DTYPE_SOCKET) return(EINVAL); // for now must be sock ! 1136: sp = (struct socket *)fp->f_data; ! 1137: assert(sp != NULL); ! 1138: ! 1139: // locate event if possible ! 1140: for (evq = sp->so_evlist.tqh_first; ! 1141: evq != NULL; evq = evq->ee_slist.tqe_next) { ! 1142: if (evq->ee_proc == p) break; ! 1143: } ! 1144: if (evq == NULL) { ! 1145: return(EINVAL); ! 1146: } ! 1147: ! 1148: ! 1149: if (uap->u_eventmask == EV_RM) { ! 1150: evprocdeque(p, evq); ! 1151: TAILQ_REMOVE(&sp->so_evlist, evq, ee_slist); ! 1152: FREE(evq, M_TEMP); ! 1153: return(0); ! 1154: } ! 1155: ! 1156: switch (uap->u_eventmask & EV_MASK) { ! 1157: ! 1158: case 0: ! 1159: flag = 0; ! 1160: break; ! 1161: ! 1162: case EV_RE: ! 1163: case EV_WR: ! 1164: case EV_RE|EV_WR: ! 1165: flag = EV_RWBYTES; ! 1166: break; ! 1167: ! 1168: case EV_EX: ! 1169: flag = EV_OOB; ! 1170: break; ! 1171: ! 1172: case EV_EX|EV_RE: ! 1173: case EV_EX|EV_WR: ! 1174: case EV_EX|EV_RE|EV_WR: ! 1175: flag = EV_OOB|EV_RWBYTES; ! 1176: break; ! 1177: ! 1178: default: ! 1179: return(EINVAL); ! 1180: } ! 1181: ! 1182: evq->ee_eventmask = uap->u_eventmask & EV_MASK; ! 1183: evprocdeque(p, evq); ! 1184: evq->ee_req.er_eventbits = 0; ! 1185: postevent(sp, 0, flag); ! 1186: return(0); ! 1187: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.