[BACK]Return to uipc_socket.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/uipc_socket.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: uipc_socket.c,v 1.66 2007/02/26 23:53:33 kurt Exp $   */
        !             2: /*     $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1988, 1990, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the University nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  *     @(#)uipc_socket.c       8.3 (Berkeley) 4/15/94
        !            33:  */
        !            34:
        !            35: #include <sys/param.h>
        !            36: #include <sys/systm.h>
        !            37: #include <sys/proc.h>
        !            38: #include <sys/file.h>
        !            39: #include <sys/malloc.h>
        !            40: #include <sys/mbuf.h>
        !            41: #include <sys/domain.h>
        !            42: #include <sys/kernel.h>
        !            43: #include <sys/event.h>
        !            44: #include <sys/protosw.h>
        !            45: #include <sys/socket.h>
        !            46: #include <sys/socketvar.h>
        !            47: #include <sys/signalvar.h>
        !            48: #include <sys/resourcevar.h>
        !            49: #include <sys/pool.h>
        !            50:
        !            51: void   filt_sordetach(struct knote *kn);
        !            52: int    filt_soread(struct knote *kn, long hint);
        !            53: void   filt_sowdetach(struct knote *kn);
        !            54: int    filt_sowrite(struct knote *kn, long hint);
        !            55: int    filt_solisten(struct knote *kn, long hint);
        !            56:
        !            57: struct filterops solisten_filtops =
        !            58:        { 1, NULL, filt_sordetach, filt_solisten };
        !            59: struct filterops soread_filtops =
        !            60:        { 1, NULL, filt_sordetach, filt_soread };
        !            61: struct filterops sowrite_filtops =
        !            62:        { 1, NULL, filt_sowdetach, filt_sowrite };
        !            63:
        !            64:
        !            65: #ifndef SOMINCONN
        !            66: #define SOMINCONN 80
        !            67: #endif /* SOMINCONN */
        !            68:
        !            69: int    somaxconn = SOMAXCONN;
        !            70: int    sominconn = SOMINCONN;
        !            71:
        !            72: struct pool socket_pool;
        !            73:
        !            74: void
        !            75: soinit(void)
        !            76: {
        !            77:
        !            78:        pool_init(&socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL);
        !            79: }
        !            80:
        !            81: /*
        !            82:  * Socket operation routines.
        !            83:  * These routines are called by the routines in
        !            84:  * sys_socket.c or from a system process, and
        !            85:  * implement the semantics of socket operations by
        !            86:  * switching out to the protocol specific routines.
        !            87:  */
        !            88: /*ARGSUSED*/
        !            89: int
        !            90: socreate(int dom, struct socket **aso, int type, int proto)
        !            91: {
        !            92:        struct proc *p = curproc;               /* XXX */
        !            93:        struct protosw *prp;
        !            94:        struct socket *so;
        !            95:        int error, s;
        !            96:
        !            97:        if (proto)
        !            98:                prp = pffindproto(dom, proto, type);
        !            99:        else
        !           100:                prp = pffindtype(dom, type);
        !           101:        if (prp == NULL || prp->pr_usrreq == 0)
        !           102:                return (EPROTONOSUPPORT);
        !           103:        if (prp->pr_type != type)
        !           104:                return (EPROTOTYPE);
        !           105:        s = splsoftnet();
        !           106:        so = pool_get(&socket_pool, PR_WAITOK);
        !           107:        bzero(so, sizeof(*so));
        !           108:        TAILQ_INIT(&so->so_q0);
        !           109:        TAILQ_INIT(&so->so_q);
        !           110:        so->so_type = type;
        !           111:        if (p->p_ucred->cr_uid == 0)
        !           112:                so->so_state = SS_PRIV;
        !           113:        so->so_ruid = p->p_cred->p_ruid;
        !           114:        so->so_euid = p->p_ucred->cr_uid;
        !           115:        so->so_rgid = p->p_cred->p_rgid;
        !           116:        so->so_egid = p->p_ucred->cr_gid;
        !           117:        so->so_cpid = p->p_pid;
        !           118:        so->so_proto = prp;
        !           119:        error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL,
        !           120:            (struct mbuf *)(long)proto, NULL);
        !           121:        if (error) {
        !           122:                so->so_state |= SS_NOFDREF;
        !           123:                sofree(so);
        !           124:                splx(s);
        !           125:                return (error);
        !           126:        }
        !           127: #ifdef COMPAT_SUNOS
        !           128:        {
        !           129:                extern struct emul emul_sunos;
        !           130:                if (p->p_emul == &emul_sunos && type == SOCK_DGRAM)
        !           131:                        so->so_options |= SO_BROADCAST;
        !           132:        }
        !           133: #endif
        !           134:        splx(s);
        !           135:        *aso = so;
        !           136:        return (0);
        !           137: }
        !           138:
        !           139: int
        !           140: sobind(struct socket *so, struct mbuf *nam)
        !           141: {
        !           142:        int s = splsoftnet();
        !           143:        int error;
        !           144:
        !           145:        error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL);
        !           146:        splx(s);
        !           147:        return (error);
        !           148: }
        !           149:
        !           150: int
        !           151: solisten(struct socket *so, int backlog)
        !           152: {
        !           153:        int s = splsoftnet(), error;
        !           154:
        !           155:        error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL, NULL, NULL);
        !           156:        if (error) {
        !           157:                splx(s);
        !           158:                return (error);
        !           159:        }
        !           160:        if (TAILQ_FIRST(&so->so_q) == NULL)
        !           161:                so->so_options |= SO_ACCEPTCONN;
        !           162:        if (backlog < 0 || backlog > somaxconn)
        !           163:                backlog = somaxconn;
        !           164:        if (backlog < sominconn)
        !           165:                backlog = sominconn;
        !           166:        so->so_qlimit = backlog;
        !           167:        splx(s);
        !           168:        return (0);
        !           169: }
        !           170:
        !           171: /*
        !           172:  *  Must be called at splsoftnet()
        !           173:  */
        !           174:
        !           175: void
        !           176: sofree(struct socket *so)
        !           177: {
        !           178:        splassert(IPL_SOFTNET);
        !           179:
        !           180:        if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
        !           181:                return;
        !           182:        if (so->so_head) {
        !           183:                /*
        !           184:                 * We must not decommission a socket that's on the accept(2)
        !           185:                 * queue.  If we do, then accept(2) may hang after select(2)
        !           186:                 * indicated that the listening socket was ready.
        !           187:                 */
        !           188:                if (!soqremque(so, 0))
        !           189:                        return;
        !           190:        }
        !           191:        sbrelease(&so->so_snd);
        !           192:        sorflush(so);
        !           193:        pool_put(&socket_pool, so);
        !           194: }
        !           195:
        !           196: /*
        !           197:  * Close a socket on last file table reference removal.
        !           198:  * Initiate disconnect if connected.
        !           199:  * Free socket when disconnect complete.
        !           200:  */
        !           201: int
        !           202: soclose(struct socket *so)
        !           203: {
        !           204:        struct socket *so2;
        !           205:        int s = splsoftnet();           /* conservative */
        !           206:        int error = 0;
        !           207:
        !           208:        if (so->so_options & SO_ACCEPTCONN) {
        !           209:                while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) {
        !           210:                        (void) soqremque(so2, 0);
        !           211:                        (void) soabort(so2);
        !           212:                }
        !           213:                while ((so2 = TAILQ_FIRST(&so->so_q)) != NULL) {
        !           214:                        (void) soqremque(so2, 1);
        !           215:                        (void) soabort(so2);
        !           216:                }
        !           217:        }
        !           218:        if (so->so_pcb == 0)
        !           219:                goto discard;
        !           220:        if (so->so_state & SS_ISCONNECTED) {
        !           221:                if ((so->so_state & SS_ISDISCONNECTING) == 0) {
        !           222:                        error = sodisconnect(so);
        !           223:                        if (error)
        !           224:                                goto drop;
        !           225:                }
        !           226:                if (so->so_options & SO_LINGER) {
        !           227:                        if ((so->so_state & SS_ISDISCONNECTING) &&
        !           228:                            (so->so_state & SS_NBIO))
        !           229:                                goto drop;
        !           230:                        while (so->so_state & SS_ISCONNECTED) {
        !           231:                                error = tsleep(&so->so_timeo,
        !           232:                                    PSOCK | PCATCH, netcls,
        !           233:                                    so->so_linger * hz);
        !           234:                                if (error)
        !           235:                                        break;
        !           236:                        }
        !           237:                }
        !           238:        }
        !           239: drop:
        !           240:        if (so->so_pcb) {
        !           241:                int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, NULL,
        !           242:                                                        NULL, NULL);
        !           243:                if (error == 0)
        !           244:                        error = error2;
        !           245:        }
        !           246: discard:
        !           247:        if (so->so_state & SS_NOFDREF)
        !           248:                panic("soclose: NOFDREF");
        !           249:        so->so_state |= SS_NOFDREF;
        !           250:        sofree(so);
        !           251:        splx(s);
        !           252:        return (error);
        !           253: }
        !           254:
        !           255: /*
        !           256:  * Must be called at splsoftnet.
        !           257:  */
        !           258: int
        !           259: soabort(struct socket *so)
        !           260: {
        !           261:        splassert(IPL_SOFTNET);
        !           262:
        !           263:        return (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL, NULL, NULL);
        !           264: }
        !           265:
        !           266: int
        !           267: soaccept(struct socket *so, struct mbuf *nam)
        !           268: {
        !           269:        int s = splsoftnet();
        !           270:        int error = 0;
        !           271:
        !           272:        if ((so->so_state & SS_NOFDREF) == 0)
        !           273:                panic("soaccept: !NOFDREF");
        !           274:        so->so_state &= ~SS_NOFDREF;
        !           275:        if ((so->so_state & SS_ISDISCONNECTED) == 0 ||
        !           276:            (so->so_proto->pr_flags & PR_ABRTACPTDIS) == 0)
        !           277:                error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, NULL,
        !           278:                    nam, NULL);
        !           279:        else
        !           280:                error = ECONNABORTED;
        !           281:        splx(s);
        !           282:        return (error);
        !           283: }
        !           284:
        !           285: int
        !           286: soconnect(struct socket *so, struct mbuf *nam)
        !           287: {
        !           288:        int s;
        !           289:        int error;
        !           290:
        !           291:        if (so->so_options & SO_ACCEPTCONN)
        !           292:                return (EOPNOTSUPP);
        !           293:        s = splsoftnet();
        !           294:        /*
        !           295:         * If protocol is connection-based, can only connect once.
        !           296:         * Otherwise, if connected, try to disconnect first.
        !           297:         * This allows user to disconnect by connecting to, e.g.,
        !           298:         * a null address.
        !           299:         */
        !           300:        if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
        !           301:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
        !           302:            (error = sodisconnect(so))))
        !           303:                error = EISCONN;
        !           304:        else
        !           305:                error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
        !           306:                                                   NULL, nam, NULL);
        !           307:        splx(s);
        !           308:        return (error);
        !           309: }
        !           310:
        !           311: int
        !           312: soconnect2(struct socket *so1, struct socket *so2)
        !           313: {
        !           314:        int s = splsoftnet();
        !           315:        int error;
        !           316:
        !           317:        error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, NULL,
        !           318:                                            (struct mbuf *)so2, NULL);
        !           319:        splx(s);
        !           320:        return (error);
        !           321: }
        !           322:
        !           323: int
        !           324: sodisconnect(struct socket *so)
        !           325: {
        !           326:        int s = splsoftnet();
        !           327:        int error;
        !           328:
        !           329:        if ((so->so_state & SS_ISCONNECTED) == 0) {
        !           330:                error = ENOTCONN;
        !           331:                goto bad;
        !           332:        }
        !           333:        if (so->so_state & SS_ISDISCONNECTING) {
        !           334:                error = EALREADY;
        !           335:                goto bad;
        !           336:        }
        !           337:        error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, NULL, NULL,
        !           338:                                           NULL);
        !           339: bad:
        !           340:        splx(s);
        !           341:        return (error);
        !           342: }
        !           343:
        !           344: #define        SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
        !           345: /*
        !           346:  * Send on a socket.
        !           347:  * If send must go all at once and message is larger than
        !           348:  * send buffering, then hard error.
        !           349:  * Lock against other senders.
        !           350:  * If must go all at once and not enough room now, then
        !           351:  * inform user that this would block and do nothing.
        !           352:  * Otherwise, if nonblocking, send as much as possible.
        !           353:  * The data to be sent is described by "uio" if nonzero,
        !           354:  * otherwise by the mbuf chain "top" (which must be null
        !           355:  * if uio is not).  Data provided in mbuf chain must be small
        !           356:  * enough to send all at once.
        !           357:  *
        !           358:  * Returns nonzero on error, timeout or signal; callers
        !           359:  * must check for short counts if EINTR/ERESTART are returned.
        !           360:  * Data and control buffers are freed on return.
        !           361:  */
        !           362: int
        !           363: sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top,
        !           364:     struct mbuf *control, int flags)
        !           365: {
        !           366:        struct mbuf **mp;
        !           367:        struct mbuf *m;
        !           368:        long space, len, mlen, clen = 0;
        !           369:        quad_t resid;
        !           370:        int error, s, dontroute;
        !           371:        int atomic = sosendallatonce(so) || top;
        !           372:
        !           373:        if (uio)
        !           374:                resid = uio->uio_resid;
        !           375:        else
        !           376:                resid = top->m_pkthdr.len;
        !           377:        /*
        !           378:         * In theory resid should be unsigned (since uio->uio_resid is).
        !           379:         * However, space must be signed, as it might be less than 0
        !           380:         * if we over-committed, and we must use a signed comparison
        !           381:         * of space and resid.  On the other hand, a negative resid
        !           382:         * causes us to loop sending 0-length segments to the protocol.
        !           383:         * MSG_EOR on a SOCK_STREAM socket is also invalid.
        !           384:         */
        !           385:        if (resid < 0 ||
        !           386:            (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
        !           387:                error = EINVAL;
        !           388:                goto out;
        !           389:        }
        !           390:        dontroute =
        !           391:            (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
        !           392:            (so->so_proto->pr_flags & PR_ATOMIC);
        !           393:        if (uio && uio->uio_procp)
        !           394:                uio->uio_procp->p_stats->p_ru.ru_msgsnd++;
        !           395:        if (control)
        !           396:                clen = control->m_len;
        !           397: #define        snderr(errno)   { error = errno; splx(s); goto release; }
        !           398:
        !           399: restart:
        !           400:        if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
        !           401:                goto out;
        !           402:        so->so_state |= SS_ISSENDING;
        !           403:        do {
        !           404:                s = splsoftnet();
        !           405:                if (so->so_state & SS_CANTSENDMORE)
        !           406:                        snderr(EPIPE);
        !           407:                if (so->so_error) {
        !           408:                        error = so->so_error;
        !           409:                        so->so_error = 0;
        !           410:                        splx(s);
        !           411:                        goto release;
        !           412:                }
        !           413:                if ((so->so_state & SS_ISCONNECTED) == 0) {
        !           414:                        if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
        !           415:                                if ((so->so_state & SS_ISCONFIRMING) == 0 &&
        !           416:                                    !(resid == 0 && clen != 0))
        !           417:                                        snderr(ENOTCONN);
        !           418:                        } else if (addr == 0)
        !           419:                                snderr(EDESTADDRREQ);
        !           420:                }
        !           421:                space = sbspace(&so->so_snd);
        !           422:                if (flags & MSG_OOB)
        !           423:                        space += 1024;
        !           424:                if ((atomic && resid > so->so_snd.sb_hiwat) ||
        !           425:                    clen > so->so_snd.sb_hiwat)
        !           426:                        snderr(EMSGSIZE);
        !           427:                if (space < resid + clen && uio &&
        !           428:                    (atomic || space < so->so_snd.sb_lowat || space < clen)) {
        !           429:                        if (so->so_state & SS_NBIO)
        !           430:                                snderr(EWOULDBLOCK);
        !           431:                        sbunlock(&so->so_snd);
        !           432:                        error = sbwait(&so->so_snd);
        !           433:                        so->so_state &= ~SS_ISSENDING;
        !           434:                        splx(s);
        !           435:                        if (error)
        !           436:                                goto out;
        !           437:                        goto restart;
        !           438:                }
        !           439:                splx(s);
        !           440:                mp = &top;
        !           441:                space -= clen;
        !           442:                do {
        !           443:                        if (uio == NULL) {
        !           444:                                /*
        !           445:                                 * Data is prepackaged in "top".
        !           446:                                 */
        !           447:                                resid = 0;
        !           448:                                if (flags & MSG_EOR)
        !           449:                                        top->m_flags |= M_EOR;
        !           450:                        } else do {
        !           451:                                if (top == 0) {
        !           452:                                        MGETHDR(m, M_WAIT, MT_DATA);
        !           453:                                        mlen = MHLEN;
        !           454:                                        m->m_pkthdr.len = 0;
        !           455:                                        m->m_pkthdr.rcvif = (struct ifnet *)0;
        !           456:                                } else {
        !           457:                                        MGET(m, M_WAIT, MT_DATA);
        !           458:                                        mlen = MLEN;
        !           459:                                }
        !           460:                                if (resid >= MINCLSIZE && space >= MCLBYTES) {
        !           461:                                        MCLGET(m, M_WAIT);
        !           462:                                        if ((m->m_flags & M_EXT) == 0)
        !           463:                                                goto nopages;
        !           464:                                        mlen = MCLBYTES;
        !           465:                                        if (atomic && top == 0) {
        !           466:                                                len = lmin(MCLBYTES - max_hdr, resid);
        !           467:                                                m->m_data += max_hdr;
        !           468:                                        } else
        !           469:                                                len = lmin(MCLBYTES, resid);
        !           470:                                        space -= len;
        !           471:                                } else {
        !           472: nopages:
        !           473:                                        len = lmin(lmin(mlen, resid), space);
        !           474:                                        space -= len;
        !           475:                                        /*
        !           476:                                         * For datagram protocols, leave room
        !           477:                                         * for protocol headers in first mbuf.
        !           478:                                         */
        !           479:                                        if (atomic && top == 0 && len < mlen)
        !           480:                                                MH_ALIGN(m, len);
        !           481:                                }
        !           482:                                error = uiomove(mtod(m, caddr_t), (int)len,
        !           483:                                    uio);
        !           484:                                resid = uio->uio_resid;
        !           485:                                m->m_len = len;
        !           486:                                *mp = m;
        !           487:                                top->m_pkthdr.len += len;
        !           488:                                if (error)
        !           489:                                        goto release;
        !           490:                                mp = &m->m_next;
        !           491:                                if (resid <= 0) {
        !           492:                                        if (flags & MSG_EOR)
        !           493:                                                top->m_flags |= M_EOR;
        !           494:                                        break;
        !           495:                                }
        !           496:                        } while (space > 0 && atomic);
        !           497:                        if (dontroute)
        !           498:                                so->so_options |= SO_DONTROUTE;
        !           499:                        s = splsoftnet();               /* XXX */
        !           500:                        if (resid <= 0)
        !           501:                                so->so_state &= ~SS_ISSENDING;
        !           502:                        error = (*so->so_proto->pr_usrreq)(so,
        !           503:                            (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
        !           504:                            top, addr, control);
        !           505:                        splx(s);
        !           506:                        if (dontroute)
        !           507:                                so->so_options &= ~SO_DONTROUTE;
        !           508:                        clen = 0;
        !           509:                        control = 0;
        !           510:                        top = 0;
        !           511:                        mp = &top;
        !           512:                        if (error)
        !           513:                                goto release;
        !           514:                } while (resid && space > 0);
        !           515:        } while (resid);
        !           516:
        !           517: release:
        !           518:        so->so_state &= ~SS_ISSENDING;
        !           519:        sbunlock(&so->so_snd);
        !           520: out:
        !           521:        if (top)
        !           522:                m_freem(top);
        !           523:        if (control)
        !           524:                m_freem(control);
        !           525:        return (error);
        !           526: }
        !           527:
        !           528: /*
        !           529:  * Implement receive operations on a socket.
        !           530:  * We depend on the way that records are added to the sockbuf
        !           531:  * by sbappend*.  In particular, each record (mbufs linked through m_next)
        !           532:  * must begin with an address if the protocol so specifies,
        !           533:  * followed by an optional mbuf or mbufs containing ancillary data,
        !           534:  * and then zero or more mbufs of data.
        !           535:  * In order to avoid blocking network interrupts for the entire time here,
        !           536:  * we splx() while doing the actual copy to user space.
        !           537:  * Although the sockbuf is locked, new data may still be appended,
        !           538:  * and thus we must maintain consistency of the sockbuf during that time.
        !           539:  *
        !           540:  * The caller may receive the data as a single mbuf chain by supplying
        !           541:  * an mbuf **mp0 for use in returning the chain.  The uio is then used
        !           542:  * only for the count in uio_resid.
        !           543:  */
        !           544: int
        !           545: soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio,
        !           546:     struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
        !           547: {
        !           548:        struct mbuf *m, **mp;
        !           549:        int flags, len, error, s, offset;
        !           550:        struct protosw *pr = so->so_proto;
        !           551:        struct mbuf *nextrecord;
        !           552:        int moff, type = 0;
        !           553:        size_t orig_resid = uio->uio_resid;
        !           554:        int uio_error = 0;
        !           555:        int resid;
        !           556:
        !           557:        mp = mp0;
        !           558:        if (paddr)
        !           559:                *paddr = 0;
        !           560:        if (controlp)
        !           561:                *controlp = 0;
        !           562:        if (flagsp)
        !           563:                flags = *flagsp &~ MSG_EOR;
        !           564:        else
        !           565:                flags = 0;
        !           566:        if (so->so_state & SS_NBIO)
        !           567:                flags |= MSG_DONTWAIT;
        !           568:        if (flags & MSG_OOB) {
        !           569:                m = m_get(M_WAIT, MT_DATA);
        !           570:                error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
        !           571:                    (struct mbuf *)(long)(flags & MSG_PEEK), NULL);
        !           572:                if (error)
        !           573:                        goto bad;
        !           574:                do {
        !           575:                        error = uiomove(mtod(m, caddr_t),
        !           576:                            (int) min(uio->uio_resid, m->m_len), uio);
        !           577:                        m = m_free(m);
        !           578:                } while (uio->uio_resid && error == 0 && m);
        !           579: bad:
        !           580:                if (m)
        !           581:                        m_freem(m);
        !           582:                return (error);
        !           583:        }
        !           584:        if (mp)
        !           585:                *mp = NULL;
        !           586:        if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
        !           587:                (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL);
        !           588:
        !           589: restart:
        !           590:        if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
        !           591:                return (error);
        !           592:        s = splsoftnet();
        !           593:
        !           594:        m = so->so_rcv.sb_mb;
        !           595:        /*
        !           596:         * If we have less data than requested, block awaiting more
        !           597:         * (subject to any timeout) if:
        !           598:         *   1. the current count is less than the low water mark,
        !           599:         *   2. MSG_WAITALL is set, and it is possible to do the entire
        !           600:         *      receive operation at once if we block (resid <= hiwat), or
        !           601:         *   3. MSG_DONTWAIT is not set.
        !           602:         * If MSG_WAITALL is set but resid is larger than the receive buffer,
        !           603:         * we have to do the receive in sections, and thus risk returning
        !           604:         * a short count if a timeout or signal occurs after we start.
        !           605:         */
        !           606:        if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
        !           607:            so->so_rcv.sb_cc < uio->uio_resid) &&
        !           608:            (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
        !           609:            ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
        !           610:            m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
        !           611: #ifdef DIAGNOSTIC
        !           612:                if (m == NULL && so->so_rcv.sb_cc)
        !           613:                        panic("receive 1");
        !           614: #endif
        !           615:                if (so->so_error) {
        !           616:                        if (m)
        !           617:                                goto dontblock;
        !           618:                        error = so->so_error;
        !           619:                        if ((flags & MSG_PEEK) == 0)
        !           620:                                so->so_error = 0;
        !           621:                        goto release;
        !           622:                }
        !           623:                if (so->so_state & SS_CANTRCVMORE) {
        !           624:                        if (m)
        !           625:                                goto dontblock;
        !           626:                        else
        !           627:                                goto release;
        !           628:                }
        !           629:                for (; m; m = m->m_next)
        !           630:                        if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
        !           631:                                m = so->so_rcv.sb_mb;
        !           632:                                goto dontblock;
        !           633:                        }
        !           634:                if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
        !           635:                    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
        !           636:                        error = ENOTCONN;
        !           637:                        goto release;
        !           638:                }
        !           639:                if (uio->uio_resid == 0 && controlp == NULL)
        !           640:                        goto release;
        !           641:                if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
        !           642:                        error = EWOULDBLOCK;
        !           643:                        goto release;
        !           644:                }
        !           645:                SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1");
        !           646:                SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
        !           647:                sbunlock(&so->so_rcv);
        !           648:                error = sbwait(&so->so_rcv);
        !           649:                splx(s);
        !           650:                if (error)
        !           651:                        return (error);
        !           652:                goto restart;
        !           653:        }
        !           654: dontblock:
        !           655:        /*
        !           656:         * On entry here, m points to the first record of the socket buffer.
        !           657:         * While we process the initial mbufs containing address and control
        !           658:         * info, we save a copy of m->m_nextpkt into nextrecord.
        !           659:         */
        !           660:        if (uio->uio_procp)
        !           661:                uio->uio_procp->p_stats->p_ru.ru_msgrcv++;
        !           662:        KASSERT(m == so->so_rcv.sb_mb);
        !           663:        SBLASTRECORDCHK(&so->so_rcv, "soreceive 1");
        !           664:        SBLASTMBUFCHK(&so->so_rcv, "soreceive 1");
        !           665:        nextrecord = m->m_nextpkt;
        !           666:        if (pr->pr_flags & PR_ADDR) {
        !           667: #ifdef DIAGNOSTIC
        !           668:                if (m->m_type != MT_SONAME)
        !           669:                        panic("receive 1a");
        !           670: #endif
        !           671:                orig_resid = 0;
        !           672:                if (flags & MSG_PEEK) {
        !           673:                        if (paddr)
        !           674:                                *paddr = m_copy(m, 0, m->m_len);
        !           675:                        m = m->m_next;
        !           676:                } else {
        !           677:                        sbfree(&so->so_rcv, m);
        !           678:                        if (paddr) {
        !           679:                                *paddr = m;
        !           680:                                so->so_rcv.sb_mb = m->m_next;
        !           681:                                m->m_next = 0;
        !           682:                                m = so->so_rcv.sb_mb;
        !           683:                        } else {
        !           684:                                MFREE(m, so->so_rcv.sb_mb);
        !           685:                                m = so->so_rcv.sb_mb;
        !           686:                        }
        !           687:                }
        !           688:        }
        !           689:        while (m && m->m_type == MT_CONTROL && error == 0) {
        !           690:                if (flags & MSG_PEEK) {
        !           691:                        if (controlp)
        !           692:                                *controlp = m_copy(m, 0, m->m_len);
        !           693:                        m = m->m_next;
        !           694:                } else {
        !           695:                        sbfree(&so->so_rcv, m);
        !           696:                        if (controlp) {
        !           697:                                if (pr->pr_domain->dom_externalize &&
        !           698:                                    mtod(m, struct cmsghdr *)->cmsg_type ==
        !           699:                                    SCM_RIGHTS)
        !           700:                                   error = (*pr->pr_domain->dom_externalize)(m);
        !           701:                                *controlp = m;
        !           702:                                so->so_rcv.sb_mb = m->m_next;
        !           703:                                m->m_next = 0;
        !           704:                                m = so->so_rcv.sb_mb;
        !           705:                        } else {
        !           706:                                /*
        !           707:                                 * Dispose of any SCM_RIGHTS message that went
        !           708:                                 * through the read path rather than recv.
        !           709:                                 */
        !           710:                                if (pr->pr_domain->dom_dispose &&
        !           711:                                    mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)
        !           712:                                        pr->pr_domain->dom_dispose(m);
        !           713:                                MFREE(m, so->so_rcv.sb_mb);
        !           714:                                m = so->so_rcv.sb_mb;
        !           715:                        }
        !           716:                }
        !           717:                if (controlp) {
        !           718:                        orig_resid = 0;
        !           719:                        controlp = &(*controlp)->m_next;
        !           720:                }
        !           721:        }
        !           722:
        !           723:        /*
        !           724:         * If m is non-NULL, we have some data to read.  From now on,
        !           725:         * make sure to keep sb_lastrecord consistent when working on
        !           726:         * the last packet on the chain (nextrecord == NULL) and we
        !           727:         * change m->m_nextpkt.
        !           728:         */
        !           729:        if (m) {
        !           730:                if ((flags & MSG_PEEK) == 0) {
        !           731:                        m->m_nextpkt = nextrecord;
        !           732:                        /*
        !           733:                         * If nextrecord == NULL (this is a single chain),
        !           734:                         * then sb_lastrecord may not be valid here if m
        !           735:                         * was changed earlier.
        !           736:                         */
        !           737:                        if (nextrecord == NULL) {
        !           738:                                KASSERT(so->so_rcv.sb_mb == m);
        !           739:                                so->so_rcv.sb_lastrecord = m;
        !           740:                        }
        !           741:                }
        !           742:                type = m->m_type;
        !           743:                if (type == MT_OOBDATA)
        !           744:                        flags |= MSG_OOB;
        !           745:                if (m->m_flags & M_BCAST)
        !           746:                        flags |= MSG_BCAST;
        !           747:                if (m->m_flags & M_MCAST)
        !           748:                        flags |= MSG_MCAST;
        !           749:        } else {
        !           750:                if ((flags & MSG_PEEK) == 0) {
        !           751:                        KASSERT(so->so_rcv.sb_mb == m);
        !           752:                        so->so_rcv.sb_mb = nextrecord;
        !           753:                        SB_EMPTY_FIXUP(&so->so_rcv);
        !           754:                }
        !           755:        }
        !           756:        SBLASTRECORDCHK(&so->so_rcv, "soreceive 2");
        !           757:        SBLASTMBUFCHK(&so->so_rcv, "soreceive 2");
        !           758:
        !           759:        moff = 0;
        !           760:        offset = 0;
        !           761:        while (m && uio->uio_resid > 0 && error == 0) {
        !           762:                if (m->m_type == MT_OOBDATA) {
        !           763:                        if (type != MT_OOBDATA)
        !           764:                                break;
        !           765:                } else if (type == MT_OOBDATA)
        !           766:                        break;
        !           767: #ifdef DIAGNOSTIC
        !           768:                else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
        !           769:                        panic("receive 3");
        !           770: #endif
        !           771:                so->so_state &= ~SS_RCVATMARK;
        !           772:                len = uio->uio_resid;
        !           773:                if (so->so_oobmark && len > so->so_oobmark - offset)
        !           774:                        len = so->so_oobmark - offset;
        !           775:                if (len > m->m_len - moff)
        !           776:                        len = m->m_len - moff;
        !           777:                /*
        !           778:                 * If mp is set, just pass back the mbufs.
        !           779:                 * Otherwise copy them out via the uio, then free.
        !           780:                 * Sockbuf must be consistent here (points to current mbuf,
        !           781:                 * it points to next record) when we drop priority;
        !           782:                 * we must note any additions to the sockbuf when we
        !           783:                 * block interrupts again.
        !           784:                 */
        !           785:                if (mp == NULL && uio_error == 0) {
        !           786:                        SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
        !           787:                        SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
        !           788:                        resid = uio->uio_resid;
        !           789:                        splx(s);
        !           790:                        uio_error =
        !           791:                                uiomove(mtod(m, caddr_t) + moff, (int)len,
        !           792:                                        uio);
        !           793:                        s = splsoftnet();
        !           794:                        if (uio_error)
        !           795:                                uio->uio_resid = resid - len;
        !           796:                } else
        !           797:                        uio->uio_resid -= len;
        !           798:                if (len == m->m_len - moff) {
        !           799:                        if (m->m_flags & M_EOR)
        !           800:                                flags |= MSG_EOR;
        !           801:                        if (flags & MSG_PEEK) {
        !           802:                                m = m->m_next;
        !           803:                                moff = 0;
        !           804:                        } else {
        !           805:                                nextrecord = m->m_nextpkt;
        !           806:                                sbfree(&so->so_rcv, m);
        !           807:                                if (mp) {
        !           808:                                        *mp = m;
        !           809:                                        mp = &m->m_next;
        !           810:                                        so->so_rcv.sb_mb = m = m->m_next;
        !           811:                                        *mp = NULL;
        !           812:                                } else {
        !           813:                                        MFREE(m, so->so_rcv.sb_mb);
        !           814:                                        m = so->so_rcv.sb_mb;
        !           815:                                }
        !           816:                                /*
        !           817:                                 * If m != NULL, we also know that
        !           818:                                 * so->so_rcv.sb_mb != NULL.
        !           819:                                 */
        !           820:                                KASSERT(so->so_rcv.sb_mb == m);
        !           821:                                if (m) {
        !           822:                                        m->m_nextpkt = nextrecord;
        !           823:                                        if (nextrecord == NULL)
        !           824:                                                so->so_rcv.sb_lastrecord = m;
        !           825:                                } else {
        !           826:                                        so->so_rcv.sb_mb = nextrecord;
        !           827:                                        SB_EMPTY_FIXUP(&so->so_rcv);
        !           828:                                }
        !           829:                                SBLASTRECORDCHK(&so->so_rcv, "soreceive 3");
        !           830:                                SBLASTMBUFCHK(&so->so_rcv, "soreceive 3");
        !           831:                        }
        !           832:                } else {
        !           833:                        if (flags & MSG_PEEK)
        !           834:                                moff += len;
        !           835:                        else {
        !           836:                                if (mp)
        !           837:                                        *mp = m_copym(m, 0, len, M_WAIT);
        !           838:                                m->m_data += len;
        !           839:                                m->m_len -= len;
        !           840:                                so->so_rcv.sb_cc -= len;
        !           841:                                so->so_rcv.sb_datacc -= len;
        !           842:                        }
        !           843:                }
        !           844:                if (so->so_oobmark) {
        !           845:                        if ((flags & MSG_PEEK) == 0) {
        !           846:                                so->so_oobmark -= len;
        !           847:                                if (so->so_oobmark == 0) {
        !           848:                                        so->so_state |= SS_RCVATMARK;
        !           849:                                        break;
        !           850:                                }
        !           851:                        } else {
        !           852:                                offset += len;
        !           853:                                if (offset == so->so_oobmark)
        !           854:                                        break;
        !           855:                        }
        !           856:                }
        !           857:                if (flags & MSG_EOR)
        !           858:                        break;
        !           859:                /*
        !           860:                 * If the MSG_WAITALL flag is set (for non-atomic socket),
        !           861:                 * we must not quit until "uio->uio_resid == 0" or an error
        !           862:                 * termination.  If a signal/timeout occurs, return
        !           863:                 * with a short count but without error.
        !           864:                 * Keep sockbuf locked against other readers.
        !           865:                 */
        !           866:                while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 &&
        !           867:                    !sosendallatonce(so) && !nextrecord) {
        !           868:                        if (so->so_error || so->so_state & SS_CANTRCVMORE)
        !           869:                                break;
        !           870:                        SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2");
        !           871:                        SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2");
        !           872:                        error = sbwait(&so->so_rcv);
        !           873:                        if (error) {
        !           874:                                sbunlock(&so->so_rcv);
        !           875:                                splx(s);
        !           876:                                return (0);
        !           877:                        }
        !           878:                        if ((m = so->so_rcv.sb_mb) != NULL)
        !           879:                                nextrecord = m->m_nextpkt;
        !           880:                }
        !           881:        }
        !           882:
        !           883:        if (m && pr->pr_flags & PR_ATOMIC) {
        !           884:                flags |= MSG_TRUNC;
        !           885:                if ((flags & MSG_PEEK) == 0)
        !           886:                        (void) sbdroprecord(&so->so_rcv);
        !           887:        }
        !           888:        if ((flags & MSG_PEEK) == 0) {
        !           889:                if (m == NULL) {
        !           890:                        /*
        !           891:                         * First part is an inline SB_EMPTY_FIXUP().  Second
        !           892:                         * part makes sure sb_lastrecord is up-to-date if
        !           893:                         * there is still data in the socket buffer.
        !           894:                         */
        !           895:                        so->so_rcv.sb_mb = nextrecord;
        !           896:                        if (so->so_rcv.sb_mb == NULL) {
        !           897:                                so->so_rcv.sb_mbtail = NULL;
        !           898:                                so->so_rcv.sb_lastrecord = NULL;
        !           899:                        } else if (nextrecord->m_nextpkt == NULL)
        !           900:                                so->so_rcv.sb_lastrecord = nextrecord;
        !           901:                }
        !           902:                SBLASTRECORDCHK(&so->so_rcv, "soreceive 4");
        !           903:                SBLASTMBUFCHK(&so->so_rcv, "soreceive 4");
        !           904:                if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
        !           905:                        (*pr->pr_usrreq)(so, PRU_RCVD, NULL,
        !           906:                                         (struct mbuf *)(long)flags, NULL);
        !           907:        }
        !           908:        if (orig_resid == uio->uio_resid && orig_resid &&
        !           909:            (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
        !           910:                sbunlock(&so->so_rcv);
        !           911:                splx(s);
        !           912:                goto restart;
        !           913:        }
        !           914:
        !           915:        if (uio_error)
        !           916:                error = uio_error;
        !           917:
        !           918:        if (flagsp)
        !           919:                *flagsp |= flags;
        !           920: release:
        !           921:        sbunlock(&so->so_rcv);
        !           922:        splx(s);
        !           923:        return (error);
        !           924: }
        !           925:
        !           926: int
        !           927: soshutdown(struct socket *so, int how)
        !           928: {
        !           929:        struct protosw *pr = so->so_proto;
        !           930:
        !           931:        switch (how) {
        !           932:        case SHUT_RD:
        !           933:        case SHUT_RDWR:
        !           934:                sorflush(so);
        !           935:                if (how == SHUT_RD)
        !           936:                        return (0);
        !           937:                /* FALLTHROUGH */
        !           938:        case SHUT_WR:
        !           939:                return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL, NULL, NULL);
        !           940:        default:
        !           941:                return (EINVAL);
        !           942:        }
        !           943: }
        !           944:
        !           945: void
        !           946: sorflush(struct socket *so)
        !           947: {
        !           948:        struct sockbuf *sb = &so->so_rcv;
        !           949:        struct protosw *pr = so->so_proto;
        !           950:        int s;
        !           951:        struct sockbuf asb;
        !           952:
        !           953:        sb->sb_flags |= SB_NOINTR;
        !           954:        (void) sblock(sb, M_WAITOK);
        !           955:        s = splnet();
        !           956:        socantrcvmore(so);
        !           957:        sbunlock(sb);
        !           958:        asb = *sb;
        !           959:        bzero(sb, sizeof (*sb));
        !           960:        /* XXX - the bzero stumps all over so_rcv */
        !           961:        if (asb.sb_flags & SB_KNOTE) {
        !           962:                sb->sb_sel.si_note = asb.sb_sel.si_note;
        !           963:                sb->sb_flags = SB_KNOTE;
        !           964:        }
        !           965:        splx(s);
        !           966:        if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
        !           967:                (*pr->pr_domain->dom_dispose)(asb.sb_mb);
        !           968:        sbrelease(&asb);
        !           969: }
        !           970:
        !           971: int
        !           972: sosetopt(struct socket *so, int level, int optname, struct mbuf *m0)
        !           973: {
        !           974:        int error = 0;
        !           975:        struct mbuf *m = m0;
        !           976:
        !           977:        if (level != SOL_SOCKET) {
        !           978:                if (so->so_proto && so->so_proto->pr_ctloutput)
        !           979:                        return ((*so->so_proto->pr_ctloutput)
        !           980:                                  (PRCO_SETOPT, so, level, optname, &m0));
        !           981:                error = ENOPROTOOPT;
        !           982:        } else {
        !           983:                switch (optname) {
        !           984:
        !           985:                case SO_LINGER:
        !           986:                        if (m == NULL || m->m_len != sizeof (struct linger) ||
        !           987:                            mtod(m, struct linger *)->l_linger < 0 ||
        !           988:                            mtod(m, struct linger *)->l_linger > SHRT_MAX) {
        !           989:                                error = EINVAL;
        !           990:                                goto bad;
        !           991:                        }
        !           992:                        so->so_linger = mtod(m, struct linger *)->l_linger;
        !           993:                        /* FALLTHROUGH */
        !           994:
        !           995:                case SO_DEBUG:
        !           996:                case SO_KEEPALIVE:
        !           997:                case SO_DONTROUTE:
        !           998:                case SO_USELOOPBACK:
        !           999:                case SO_BROADCAST:
        !          1000:                case SO_REUSEADDR:
        !          1001:                case SO_REUSEPORT:
        !          1002:                case SO_OOBINLINE:
        !          1003:                case SO_JUMBO:
        !          1004:                        if (m == NULL || m->m_len < sizeof (int)) {
        !          1005:                                error = EINVAL;
        !          1006:                                goto bad;
        !          1007:                        }
        !          1008:                        if (*mtod(m, int *))
        !          1009:                                so->so_options |= optname;
        !          1010:                        else
        !          1011:                                so->so_options &= ~optname;
        !          1012:                        break;
        !          1013:
        !          1014:                case SO_SNDBUF:
        !          1015:                case SO_RCVBUF:
        !          1016:                case SO_SNDLOWAT:
        !          1017:                case SO_RCVLOWAT:
        !          1018:                    {
        !          1019:                        u_long cnt;
        !          1020:
        !          1021:                        if (m == NULL || m->m_len < sizeof (int)) {
        !          1022:                                error = EINVAL;
        !          1023:                                goto bad;
        !          1024:                        }
        !          1025:                        cnt = *mtod(m, int *);
        !          1026:                        if ((long)cnt <= 0)
        !          1027:                                cnt = 1;
        !          1028:                        switch (optname) {
        !          1029:
        !          1030:                        case SO_SNDBUF:
        !          1031:                                if (sbcheckreserve(cnt, so->so_snd.sb_hiwat) ||
        !          1032:                                    sbreserve(&so->so_snd, cnt) == 0) {
        !          1033:                                        error = ENOBUFS;
        !          1034:                                        goto bad;
        !          1035:                                }
        !          1036:                                break;
        !          1037:
        !          1038:                        case SO_RCVBUF:
        !          1039:                                if (sbcheckreserve(cnt, so->so_rcv.sb_hiwat) ||
        !          1040:                                    sbreserve(&so->so_rcv, cnt) == 0) {
        !          1041:                                        error = ENOBUFS;
        !          1042:                                        goto bad;
        !          1043:                                }
        !          1044:                                break;
        !          1045:
        !          1046:                        case SO_SNDLOWAT:
        !          1047:                                so->so_snd.sb_lowat = (cnt > so->so_snd.sb_hiwat) ?
        !          1048:                                    so->so_snd.sb_hiwat : cnt;
        !          1049:                                break;
        !          1050:                        case SO_RCVLOWAT:
        !          1051:                                so->so_rcv.sb_lowat = (cnt > so->so_rcv.sb_hiwat) ?
        !          1052:                                    so->so_rcv.sb_hiwat : cnt;
        !          1053:                                break;
        !          1054:                        }
        !          1055:                        break;
        !          1056:                    }
        !          1057:
        !          1058:                case SO_SNDTIMEO:
        !          1059:                case SO_RCVTIMEO:
        !          1060:                    {
        !          1061:                        struct timeval *tv;
        !          1062:                        short val;
        !          1063:
        !          1064:                        if (m == NULL || m->m_len < sizeof (*tv)) {
        !          1065:                                error = EINVAL;
        !          1066:                                goto bad;
        !          1067:                        }
        !          1068:                        tv = mtod(m, struct timeval *);
        !          1069:                        if (tv->tv_sec > (SHRT_MAX - tv->tv_usec / tick) / hz) {
        !          1070:                                error = EDOM;
        !          1071:                                goto bad;
        !          1072:                        }
        !          1073:                        val = tv->tv_sec * hz + tv->tv_usec / tick;
        !          1074:                        if (val == 0 && tv->tv_usec != 0)
        !          1075:                                val = 1;
        !          1076:
        !          1077:                        switch (optname) {
        !          1078:
        !          1079:                        case SO_SNDTIMEO:
        !          1080:                                so->so_snd.sb_timeo = val;
        !          1081:                                break;
        !          1082:                        case SO_RCVTIMEO:
        !          1083:                                so->so_rcv.sb_timeo = val;
        !          1084:                                break;
        !          1085:                        }
        !          1086:                        break;
        !          1087:                    }
        !          1088:
        !          1089:                default:
        !          1090:                        error = ENOPROTOOPT;
        !          1091:                        break;
        !          1092:                }
        !          1093:                if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
        !          1094:                        (void) ((*so->so_proto->pr_ctloutput)
        !          1095:                                  (PRCO_SETOPT, so, level, optname, &m0));
        !          1096:                        m = NULL;       /* freed by protocol */
        !          1097:                }
        !          1098:        }
        !          1099: bad:
        !          1100:        if (m)
        !          1101:                (void) m_free(m);
        !          1102:        return (error);
        !          1103: }
        !          1104:
        !          1105: int
        !          1106: sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
        !          1107: {
        !          1108:        struct mbuf *m;
        !          1109:
        !          1110:        if (level != SOL_SOCKET) {
        !          1111:                if (so->so_proto && so->so_proto->pr_ctloutput) {
        !          1112:                        return ((*so->so_proto->pr_ctloutput)
        !          1113:                                  (PRCO_GETOPT, so, level, optname, mp));
        !          1114:                } else
        !          1115:                        return (ENOPROTOOPT);
        !          1116:        } else {
        !          1117:                m = m_get(M_WAIT, MT_SOOPTS);
        !          1118:                m->m_len = sizeof (int);
        !          1119:
        !          1120:                switch (optname) {
        !          1121:
        !          1122:                case SO_LINGER:
        !          1123:                        m->m_len = sizeof (struct linger);
        !          1124:                        mtod(m, struct linger *)->l_onoff =
        !          1125:                                so->so_options & SO_LINGER;
        !          1126:                        mtod(m, struct linger *)->l_linger = so->so_linger;
        !          1127:                        break;
        !          1128:
        !          1129:                case SO_USELOOPBACK:
        !          1130:                case SO_DONTROUTE:
        !          1131:                case SO_DEBUG:
        !          1132:                case SO_KEEPALIVE:
        !          1133:                case SO_REUSEADDR:
        !          1134:                case SO_REUSEPORT:
        !          1135:                case SO_BROADCAST:
        !          1136:                case SO_OOBINLINE:
        !          1137:                case SO_JUMBO:
        !          1138:                        *mtod(m, int *) = so->so_options & optname;
        !          1139:                        break;
        !          1140:
        !          1141:                case SO_TYPE:
        !          1142:                        *mtod(m, int *) = so->so_type;
        !          1143:                        break;
        !          1144:
        !          1145:                case SO_ERROR:
        !          1146:                        *mtod(m, int *) = so->so_error;
        !          1147:                        so->so_error = 0;
        !          1148:                        break;
        !          1149:
        !          1150:                case SO_SNDBUF:
        !          1151:                        *mtod(m, int *) = so->so_snd.sb_hiwat;
        !          1152:                        break;
        !          1153:
        !          1154:                case SO_RCVBUF:
        !          1155:                        *mtod(m, int *) = so->so_rcv.sb_hiwat;
        !          1156:                        break;
        !          1157:
        !          1158:                case SO_SNDLOWAT:
        !          1159:                        *mtod(m, int *) = so->so_snd.sb_lowat;
        !          1160:                        break;
        !          1161:
        !          1162:                case SO_RCVLOWAT:
        !          1163:                        *mtod(m, int *) = so->so_rcv.sb_lowat;
        !          1164:                        break;
        !          1165:
        !          1166:                case SO_SNDTIMEO:
        !          1167:                case SO_RCVTIMEO:
        !          1168:                    {
        !          1169:                        int val = (optname == SO_SNDTIMEO ?
        !          1170:                            so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
        !          1171:
        !          1172:                        m->m_len = sizeof(struct timeval);
        !          1173:                        mtod(m, struct timeval *)->tv_sec = val / hz;
        !          1174:                        mtod(m, struct timeval *)->tv_usec =
        !          1175:                            (val % hz) * tick;
        !          1176:                        break;
        !          1177:                    }
        !          1178:
        !          1179:                default:
        !          1180:                        (void)m_free(m);
        !          1181:                        return (ENOPROTOOPT);
        !          1182:                }
        !          1183:                *mp = m;
        !          1184:                return (0);
        !          1185:        }
        !          1186: }
        !          1187:
        !          1188: void
        !          1189: sohasoutofband(struct socket *so)
        !          1190: {
        !          1191:        csignal(so->so_pgid, SIGURG, so->so_siguid, so->so_sigeuid);
        !          1192:        selwakeup(&so->so_rcv.sb_sel);
        !          1193: }
        !          1194:
        !          1195: int
        !          1196: soo_kqfilter(struct file *fp, struct knote *kn)
        !          1197: {
        !          1198:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1199:        struct sockbuf *sb;
        !          1200:        int s;
        !          1201:
        !          1202:        switch (kn->kn_filter) {
        !          1203:        case EVFILT_READ:
        !          1204:                if (so->so_options & SO_ACCEPTCONN)
        !          1205:                        kn->kn_fop = &solisten_filtops;
        !          1206:                else
        !          1207:                        kn->kn_fop = &soread_filtops;
        !          1208:                sb = &so->so_rcv;
        !          1209:                break;
        !          1210:        case EVFILT_WRITE:
        !          1211:                kn->kn_fop = &sowrite_filtops;
        !          1212:                sb = &so->so_snd;
        !          1213:                break;
        !          1214:        default:
        !          1215:                return (1);
        !          1216:        }
        !          1217:
        !          1218:        s = splnet();
        !          1219:        SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext);
        !          1220:        sb->sb_flags |= SB_KNOTE;
        !          1221:        splx(s);
        !          1222:        return (0);
        !          1223: }
        !          1224:
        !          1225: void
        !          1226: filt_sordetach(struct knote *kn)
        !          1227: {
        !          1228:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1229:        int s = splnet();
        !          1230:
        !          1231:        SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
        !          1232:        if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
        !          1233:                so->so_rcv.sb_flags &= ~SB_KNOTE;
        !          1234:        splx(s);
        !          1235: }
        !          1236:
        !          1237: /*ARGSUSED*/
        !          1238: int
        !          1239: filt_soread(struct knote *kn, long hint)
        !          1240: {
        !          1241:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1242:
        !          1243:        kn->kn_data = so->so_rcv.sb_cc;
        !          1244:        if (so->so_state & SS_CANTRCVMORE) {
        !          1245:                kn->kn_flags |= EV_EOF;
        !          1246:                kn->kn_fflags = so->so_error;
        !          1247:                return (1);
        !          1248:        }
        !          1249:        if (so->so_error)       /* temporary udp error */
        !          1250:                return (1);
        !          1251:        if (kn->kn_sfflags & NOTE_LOWAT)
        !          1252:                return (kn->kn_data >= kn->kn_sdata);
        !          1253:        return (kn->kn_data >= so->so_rcv.sb_lowat);
        !          1254: }
        !          1255:
        !          1256: void
        !          1257: filt_sowdetach(struct knote *kn)
        !          1258: {
        !          1259:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1260:        int s = splnet();
        !          1261:
        !          1262:        SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
        !          1263:        if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
        !          1264:                so->so_snd.sb_flags &= ~SB_KNOTE;
        !          1265:        splx(s);
        !          1266: }
        !          1267:
        !          1268: /*ARGSUSED*/
        !          1269: int
        !          1270: filt_sowrite(struct knote *kn, long hint)
        !          1271: {
        !          1272:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1273:
        !          1274:        kn->kn_data = sbspace(&so->so_snd);
        !          1275:        if (so->so_state & SS_CANTSENDMORE) {
        !          1276:                kn->kn_flags |= EV_EOF;
        !          1277:                kn->kn_fflags = so->so_error;
        !          1278:                return (1);
        !          1279:        }
        !          1280:        if (so->so_error)       /* temporary udp error */
        !          1281:                return (1);
        !          1282:        if (((so->so_state & SS_ISCONNECTED) == 0) &&
        !          1283:            (so->so_proto->pr_flags & PR_CONNREQUIRED))
        !          1284:                return (0);
        !          1285:        if (kn->kn_sfflags & NOTE_LOWAT)
        !          1286:                return (kn->kn_data >= kn->kn_sdata);
        !          1287:        return (kn->kn_data >= so->so_snd.sb_lowat);
        !          1288: }
        !          1289:
        !          1290: /*ARGSUSED*/
        !          1291: int
        !          1292: filt_solisten(struct knote *kn, long hint)
        !          1293: {
        !          1294:        struct socket *so = (struct socket *)kn->kn_fp->f_data;
        !          1295:
        !          1296:        kn->kn_data = so->so_qlen;
        !          1297:        return (so->so_qlen != 0);
        !          1298: }

CVSweb