|
|
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.