[BACK]Return to uipc_socket.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/uipc_socket.c, Revision 1.141.4.2

1.141.4.2! yamt        1: /*     $NetBSD: uipc_socket.c,v 1.141 2007/08/06 11:41:52 yamt Exp $   */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to The NetBSD Foundation
        !             8:  * by Jason R. Thorpe of Wasabi Systems, Inc.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *     This product includes software developed by the NetBSD
        !            21:  *     Foundation, Inc. and its contributors.
        !            22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            23:  *    contributors may be used to endorse or promote products derived
        !            24:  *    from this software without specific prior written permission.
        !            25:  *
        !            26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            36:  * POSSIBILITY OF SUCH DAMAGE.
        !            37:  */
        !            38:
        !            39: /*
        !            40:  * Copyright (c) 1982, 1986, 1988, 1990, 1993
        !            41:  *     The Regents of the University of California.  All rights reserved.
        !            42:  *
        !            43:  * Redistribution and use in source and binary forms, with or without
        !            44:  * modification, are permitted provided that the following conditions
        !            45:  * are met:
        !            46:  * 1. Redistributions of source code must retain the above copyright
        !            47:  *    notice, this list of conditions and the following disclaimer.
        !            48:  * 2. Redistributions in binary form must reproduce the above copyright
        !            49:  *    notice, this list of conditions and the following disclaimer in the
        !            50:  *    documentation and/or other materials provided with the distribution.
        !            51:  * 3. Neither the name of the University nor the names of its contributors
        !            52:  *    may be used to endorse or promote products derived from this software
        !            53:  *    without specific prior written permission.
        !            54:  *
        !            55:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            56:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            57:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            58:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            59:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            60:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            61:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            62:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            63:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            64:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            65:  * SUCH DAMAGE.
        !            66:  *
        !            67:  *     @(#)uipc_socket.c       8.6 (Berkeley) 5/2/95
        !            68:  */
        !            69:
        !            70: #include <sys/cdefs.h>
        !            71: __KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.141 2007/08/06 11:41:52 yamt Exp $");
        !            72:
        !            73: #include "opt_sock_counters.h"
        !            74: #include "opt_sosend_loan.h"
        !            75: #include "opt_mbuftrace.h"
        !            76: #include "opt_somaxkva.h"
        !            77:
        !            78: #include <sys/param.h>
        !            79: #include <sys/systm.h>
        !            80: #include <sys/proc.h>
        !            81: #include <sys/file.h>
        !            82: #include <sys/malloc.h>
        !            83: #include <sys/mbuf.h>
        !            84: #include <sys/domain.h>
        !            85: #include <sys/kernel.h>
        !            86: #include <sys/protosw.h>
        !            87: #include <sys/socket.h>
        !            88: #include <sys/socketvar.h>
        !            89: #include <sys/signalvar.h>
        !            90: #include <sys/resourcevar.h>
        !            91: #include <sys/pool.h>
        !            92: #include <sys/event.h>
        !            93: #include <sys/poll.h>
        !            94: #include <sys/kauth.h>
        !            95: #include <sys/mutex.h>
        !            96: #include <sys/condvar.h>
        !            97:
        !            98: #include <uvm/uvm.h>
        !            99:
        !           100: POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL,
        !           101:     IPL_SOFTNET);
        !           102:
        !           103: MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options");
        !           104: MALLOC_DEFINE(M_SONAME, "soname", "socket name");
        !           105:
        !           106: extern int     somaxconn;                      /* patchable (XXX sysctl) */
        !           107: int            somaxconn = SOMAXCONN;
        !           108:
        !           109: #ifdef SOSEND_COUNTERS
        !           110: #include <sys/device.h>
        !           111:
        !           112: static struct evcnt sosend_loan_big = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
        !           113:     NULL, "sosend", "loan big");
        !           114: static struct evcnt sosend_copy_big = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
        !           115:     NULL, "sosend", "copy big");
        !           116: static struct evcnt sosend_copy_small = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
        !           117:     NULL, "sosend", "copy small");
        !           118: static struct evcnt sosend_kvalimit = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
        !           119:     NULL, "sosend", "kva limit");
        !           120:
        !           121: #define        SOSEND_COUNTER_INCR(ev)         (ev)->ev_count++
        !           122:
        !           123: EVCNT_ATTACH_STATIC(sosend_loan_big);
        !           124: EVCNT_ATTACH_STATIC(sosend_copy_big);
        !           125: EVCNT_ATTACH_STATIC(sosend_copy_small);
        !           126: EVCNT_ATTACH_STATIC(sosend_kvalimit);
        !           127: #else
        !           128:
        !           129: #define        SOSEND_COUNTER_INCR(ev)         /* nothing */
        !           130:
        !           131: #endif /* SOSEND_COUNTERS */
        !           132:
        !           133: static struct callback_entry sokva_reclaimerentry;
        !           134:
        !           135: #ifdef SOSEND_NO_LOAN
        !           136: int sock_loan_thresh = -1;
        !           137: #else
        !           138: int sock_loan_thresh = 4096;
        !           139: #endif
        !           140:
        !           141: static kmutex_t so_pendfree_lock;
        !           142: static struct mbuf *so_pendfree;
        !           143:
        !           144: #ifndef SOMAXKVA
        !           145: #define        SOMAXKVA (16 * 1024 * 1024)
        !           146: #endif
        !           147: int somaxkva = SOMAXKVA;
        !           148: static int socurkva;
        !           149: static kcondvar_t socurkva_cv;
        !           150:
        !           151: #define        SOCK_LOAN_CHUNK         65536
        !           152:
        !           153: static size_t sodopendfree(void);
        !           154: static size_t sodopendfreel(void);
        !           155:
        !           156: static vsize_t
        !           157: sokvareserve(struct socket *so, vsize_t len)
        !           158: {
        !           159:        int error;
        !           160:
        !           161:        mutex_enter(&so_pendfree_lock);
        !           162:        while (socurkva + len > somaxkva) {
        !           163:                size_t freed;
        !           164:
        !           165:                /*
        !           166:                 * try to do pendfree.
        !           167:                 */
        !           168:
        !           169:                freed = sodopendfreel();
        !           170:
        !           171:                /*
        !           172:                 * if some kva was freed, try again.
        !           173:                 */
        !           174:
        !           175:                if (freed)
        !           176:                        continue;
        !           177:
        !           178:                SOSEND_COUNTER_INCR(&sosend_kvalimit);
        !           179:                error = cv_wait_sig(&socurkva_cv, &so_pendfree_lock);
        !           180:                if (error) {
        !           181:                        len = 0;
        !           182:                        break;
        !           183:                }
        !           184:        }
        !           185:        socurkva += len;
        !           186:        mutex_exit(&so_pendfree_lock);
        !           187:        return len;
        !           188: }
        !           189:
        !           190: static void
        !           191: sokvaunreserve(vsize_t len)
        !           192: {
        !           193:
        !           194:        mutex_enter(&so_pendfree_lock);
        !           195:        socurkva -= len;
        !           196:        cv_broadcast(&socurkva_cv);
        !           197:        mutex_exit(&so_pendfree_lock);
        !           198: }
        !           199:
        !           200: /*
        !           201:  * sokvaalloc: allocate kva for loan.
        !           202:  */
        !           203:
        !           204: vaddr_t
        !           205: sokvaalloc(vsize_t len, struct socket *so)
        !           206: {
        !           207:        vaddr_t lva;
        !           208:
        !           209:        /*
        !           210:         * reserve kva.
        !           211:         */
        !           212:
        !           213:        if (sokvareserve(so, len) == 0)
        !           214:                return 0;
        !           215:
        !           216:        /*
        !           217:         * allocate kva.
        !           218:         */
        !           219:
        !           220:        lva = uvm_km_alloc(kernel_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
        !           221:        if (lva == 0) {
        !           222:                sokvaunreserve(len);
        !           223:                return (0);
        !           224:        }
        !           225:
        !           226:        return lva;
        !           227: }
        !           228:
        !           229: /*
        !           230:  * sokvafree: free kva for loan.
        !           231:  */
        !           232:
        !           233: void
        !           234: sokvafree(vaddr_t sva, vsize_t len)
        !           235: {
        !           236:
        !           237:        /*
        !           238:         * free kva.
        !           239:         */
        !           240:
        !           241:        uvm_km_free(kernel_map, sva, len, UVM_KMF_VAONLY);
        !           242:
        !           243:        /*
        !           244:         * unreserve kva.
        !           245:         */
        !           246:
        !           247:        sokvaunreserve(len);
        !           248: }
        !           249:
        !           250: static void
        !           251: sodoloanfree(struct vm_page **pgs, void *buf, size_t size)
        !           252: {
        !           253:        vaddr_t va, sva, eva;
        !           254:        vsize_t len;
        !           255:        paddr_t pa;
        !           256:        int i, npgs;
        !           257:
        !           258:        eva = round_page((vaddr_t) buf + size);
        !           259:        sva = trunc_page((vaddr_t) buf);
        !           260:        len = eva - sva;
        !           261:        npgs = len >> PAGE_SHIFT;
        !           262:
        !           263:        if (__predict_false(pgs == NULL)) {
        !           264:                pgs = alloca(npgs * sizeof(*pgs));
        !           265:
        !           266:                for (i = 0, va = sva; va < eva; i++, va += PAGE_SIZE) {
        !           267:                        if (pmap_extract(pmap_kernel(), va, &pa) == false)
        !           268:                                panic("sodoloanfree: va 0x%lx not mapped", va);
        !           269:                        pgs[i] = PHYS_TO_VM_PAGE(pa);
        !           270:                }
        !           271:        }
        !           272:
        !           273:        pmap_kremove(sva, len);
        !           274:        pmap_update(pmap_kernel());
        !           275:        uvm_unloan(pgs, npgs, UVM_LOAN_TOPAGE);
        !           276:        sokvafree(sva, len);
        !           277: }
        !           278:
        !           279: static size_t
        !           280: sodopendfree()
        !           281: {
        !           282:        size_t rv;
        !           283:
        !           284:        mutex_enter(&so_pendfree_lock);
        !           285:        rv = sodopendfreel();
        !           286:        mutex_exit(&so_pendfree_lock);
        !           287:
        !           288:        return rv;
        !           289: }
        !           290:
        !           291: /*
        !           292:  * sodopendfreel: free mbufs on "pendfree" list.
        !           293:  * unlock and relock so_pendfree_lock when freeing mbufs.
        !           294:  *
        !           295:  * => called with so_pendfree_lock held.
        !           296:  */
        !           297:
        !           298: static size_t
        !           299: sodopendfreel()
        !           300: {
        !           301:        struct mbuf *m, *next;
        !           302:        size_t rv = 0;
        !           303:        int s;
        !           304:
        !           305:        KASSERT(mutex_owned(&so_pendfree_lock));
        !           306:
        !           307:        while (so_pendfree != NULL) {
        !           308:                m = so_pendfree;
        !           309:                so_pendfree = NULL;
        !           310:                mutex_exit(&so_pendfree_lock);
        !           311:
        !           312:                for (; m != NULL; m = next) {
        !           313:                        next = m->m_next;
        !           314:
        !           315:                        rv += m->m_ext.ext_size;
        !           316:                        sodoloanfree((m->m_flags & M_EXT_PAGES) ?
        !           317:                            m->m_ext.ext_pgs : NULL, m->m_ext.ext_buf,
        !           318:                            m->m_ext.ext_size);
        !           319:                        s = splvm();
        !           320:                        pool_cache_put(&mbpool_cache, m);
        !           321:                        splx(s);
        !           322:                }
        !           323:
        !           324:                mutex_enter(&so_pendfree_lock);
        !           325:        }
        !           326:
        !           327:        return (rv);
        !           328: }
        !           329:
        !           330: void
        !           331: soloanfree(struct mbuf *m, void *buf, size_t size, void *arg)
        !           332: {
        !           333:
        !           334:        if (m == NULL) {
        !           335:
        !           336:                /*
        !           337:                 * called from MEXTREMOVE.
        !           338:                 */
        !           339:
        !           340:                sodoloanfree(NULL, buf, size);
        !           341:                return;
        !           342:        }
        !           343:
        !           344:        /*
        !           345:         * postpone freeing mbuf.
        !           346:         *
        !           347:         * we can't do it in interrupt context
        !           348:         * because we need to put kva back to kernel_map.
        !           349:         */
        !           350:
        !           351:        mutex_enter(&so_pendfree_lock);
        !           352:        m->m_next = so_pendfree;
        !           353:        so_pendfree = m;
        !           354:        cv_broadcast(&socurkva_cv);
        !           355:        mutex_exit(&so_pendfree_lock);
        !           356: }
        !           357:
        !           358: static long
        !           359: sosend_loan(struct socket *so, struct uio *uio, struct mbuf *m, long space)
        !           360: {
        !           361:        struct iovec *iov = uio->uio_iov;
        !           362:        vaddr_t sva, eva;
        !           363:        vsize_t len;
        !           364:        vaddr_t lva, va;
        !           365:        int npgs, i, error;
        !           366:
        !           367:        if (VMSPACE_IS_KERNEL_P(uio->uio_vmspace))
        !           368:                return (0);
        !           369:
        !           370:        if (iov->iov_len < (size_t) space)
        !           371:                space = iov->iov_len;
        !           372:        if (space > SOCK_LOAN_CHUNK)
        !           373:                space = SOCK_LOAN_CHUNK;
        !           374:
        !           375:        eva = round_page((vaddr_t) iov->iov_base + space);
        !           376:        sva = trunc_page((vaddr_t) iov->iov_base);
        !           377:        len = eva - sva;
        !           378:        npgs = len >> PAGE_SHIFT;
        !           379:
        !           380:        /* XXX KDASSERT */
        !           381:        KASSERT(npgs <= M_EXT_MAXPAGES);
        !           382:
        !           383:        lva = sokvaalloc(len, so);
        !           384:        if (lva == 0)
        !           385:                return 0;
        !           386:
        !           387:        error = uvm_loan(&uio->uio_vmspace->vm_map, sva, len,
        !           388:            m->m_ext.ext_pgs, UVM_LOAN_TOPAGE);
        !           389:        if (error) {
        !           390:                sokvafree(lva, len);
        !           391:                return (0);
        !           392:        }
        !           393:
        !           394:        for (i = 0, va = lva; i < npgs; i++, va += PAGE_SIZE)
        !           395:                pmap_kenter_pa(va, VM_PAGE_TO_PHYS(m->m_ext.ext_pgs[i]),
        !           396:                    VM_PROT_READ);
        !           397:        pmap_update(pmap_kernel());
        !           398:
        !           399:        lva += (vaddr_t) iov->iov_base & PAGE_MASK;
        !           400:
        !           401:        MEXTADD(m, (void *) lva, space, M_MBUF, soloanfree, so);
        !           402:        m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;
        !           403:
        !           404:        uio->uio_resid -= space;
        !           405:        /* uio_offset not updated, not set/used for write(2) */
        !           406:        uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + space;
        !           407:        uio->uio_iov->iov_len -= space;
        !           408:        if (uio->uio_iov->iov_len == 0) {
        !           409:                uio->uio_iov++;
        !           410:                uio->uio_iovcnt--;
        !           411:        }
        !           412:
        !           413:        return (space);
        !           414: }
        !           415:
        !           416: static int
        !           417: sokva_reclaim_callback(struct callback_entry *ce, void *obj, void *arg)
        !           418: {
        !           419:
        !           420:        KASSERT(ce == &sokva_reclaimerentry);
        !           421:        KASSERT(obj == NULL);
        !           422:
        !           423:        sodopendfree();
        !           424:        if (!vm_map_starved_p(kernel_map)) {
        !           425:                return CALLBACK_CHAIN_ABORT;
        !           426:        }
        !           427:        return CALLBACK_CHAIN_CONTINUE;
        !           428: }
        !           429:
        !           430: void
        !           431: soinit(void)
        !           432: {
        !           433:
        !           434:        mutex_init(&so_pendfree_lock, MUTEX_DRIVER, IPL_VM);
        !           435:        cv_init(&socurkva_cv, "sokva");
        !           436:
        !           437:        /* Set the initial adjusted socket buffer size. */
        !           438:        if (sb_max_set(sb_max))
        !           439:                panic("bad initial sb_max value: %lu", sb_max);
        !           440:
        !           441:        callback_register(&vm_map_to_kernel(kernel_map)->vmk_reclaim_callback,
        !           442:            &sokva_reclaimerentry, NULL, sokva_reclaim_callback);
        !           443: }
        !           444:
        !           445: /*
        !           446:  * Socket operation routines.
        !           447:  * These routines are called by the routines in
        !           448:  * sys_socket.c or from a system process, and
        !           449:  * implement the semantics of socket operations by
        !           450:  * switching out to the protocol specific routines.
        !           451:  */
        !           452: /*ARGSUSED*/
        !           453: int
        !           454: socreate(int dom, struct socket **aso, int type, int proto, struct lwp *l)
        !           455: {
        !           456:        const struct protosw    *prp;
        !           457:        struct socket   *so;
        !           458:        uid_t           uid;
        !           459:        int             error, s;
        !           460:
        !           461:        error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET,
        !           462:            KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type),
        !           463:            KAUTH_ARG(proto));
        !           464:        if (error != 0)
        !           465:                return error;
        !           466:
        !           467:        if (proto)
        !           468:                prp = pffindproto(dom, proto, type);
        !           469:        else
        !           470:                prp = pffindtype(dom, type);
        !           471:        if (prp == NULL) {
        !           472:                /* no support for domain */
        !           473:                if (pffinddomain(dom) == 0)
        !           474:                        return EAFNOSUPPORT;
        !           475:                /* no support for socket type */
        !           476:                if (proto == 0 && type != 0)
        !           477:                        return EPROTOTYPE;
        !           478:                return EPROTONOSUPPORT;
        !           479:        }
        !           480:        if (prp->pr_usrreq == NULL)
        !           481:                return EPROTONOSUPPORT;
        !           482:        if (prp->pr_type != type)
        !           483:                return EPROTOTYPE;
        !           484:        s = splsoftnet();
        !           485:        so = pool_get(&socket_pool, PR_WAITOK);
        !           486:        memset(so, 0, sizeof(*so));
        !           487:        TAILQ_INIT(&so->so_q0);
        !           488:        TAILQ_INIT(&so->so_q);
        !           489:        so->so_type = type;
        !           490:        so->so_proto = prp;
        !           491:        so->so_send = sosend;
        !           492:        so->so_receive = soreceive;
        !           493: #ifdef MBUFTRACE
        !           494:        so->so_rcv.sb_mowner = &prp->pr_domain->dom_mowner;
        !           495:        so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner;
        !           496:        so->so_mowner = &prp->pr_domain->dom_mowner;
        !           497: #endif
        !           498:        uid = kauth_cred_geteuid(l->l_cred);
        !           499:        so->so_uidinfo = uid_find(uid);
        !           500:        error = (*prp->pr_usrreq)(so, PRU_ATTACH, NULL,
        !           501:            (struct mbuf *)(long)proto, NULL, l);
        !           502:        if (error != 0) {
        !           503:                so->so_state |= SS_NOFDREF;
        !           504:                sofree(so);
        !           505:                splx(s);
        !           506:                return error;
        !           507:        }
        !           508:        splx(s);
        !           509:        *aso = so;
        !           510:        return 0;
        !           511: }
        !           512:
        !           513: int
        !           514: sobind(struct socket *so, struct mbuf *nam, struct lwp *l)
        !           515: {
        !           516:        int     s, error;
        !           517:
        !           518:        s = splsoftnet();
        !           519:        error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, l);
        !           520:        splx(s);
        !           521:        return error;
        !           522: }
        !           523:
        !           524: int
        !           525: solisten(struct socket *so, int backlog)
        !           526: {
        !           527:        int     s, error;
        !           528:
        !           529:        s = splsoftnet();
        !           530:        error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, NULL,
        !           531:            NULL, NULL, NULL);
        !           532:        if (error != 0) {
        !           533:                splx(s);
        !           534:                return error;
        !           535:        }
        !           536:        if (TAILQ_EMPTY(&so->so_q))
        !           537:                so->so_options |= SO_ACCEPTCONN;
        !           538:        if (backlog < 0)
        !           539:                backlog = 0;
        !           540:        so->so_qlimit = min(backlog, somaxconn);
        !           541:        splx(s);
        !           542:        return 0;
        !           543: }
        !           544:
        !           545: void
        !           546: sofree(struct socket *so)
        !           547: {
        !           548:
        !           549:        if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
        !           550:                return;
        !           551:        if (so->so_head) {
        !           552:                /*
        !           553:                 * We must not decommission a socket that's on the accept(2)
        !           554:                 * queue.  If we do, then accept(2) may hang after select(2)
        !           555:                 * indicated that the listening socket was ready.
        !           556:                 */
        !           557:                if (!soqremque(so, 0))
        !           558:                        return;
        !           559:        }
        !           560:        if (so->so_rcv.sb_hiwat)
        !           561:                (void)chgsbsize(so->so_uidinfo, &so->so_rcv.sb_hiwat, 0,
        !           562:                    RLIM_INFINITY);
        !           563:        if (so->so_snd.sb_hiwat)
        !           564:                (void)chgsbsize(so->so_uidinfo, &so->so_snd.sb_hiwat, 0,
        !           565:                    RLIM_INFINITY);
        !           566:        sbrelease(&so->so_snd, so);
        !           567:        sorflush(so);
        !           568:        pool_put(&socket_pool, so);
        !           569: }
        !           570:
        !           571: /*
        !           572:  * Close a socket on last file table reference removal.
        !           573:  * Initiate disconnect if connected.
        !           574:  * Free socket when disconnect complete.
        !           575:  */
        !           576: int
        !           577: soclose(struct socket *so)
        !           578: {
        !           579:        struct socket   *so2;
        !           580:        int             s, error;
        !           581:
        !           582:        error = 0;
        !           583:        s = splsoftnet();               /* conservative */
        !           584:        if (so->so_options & SO_ACCEPTCONN) {
        !           585:                while ((so2 = TAILQ_FIRST(&so->so_q0)) != 0) {
        !           586:                        (void) soqremque(so2, 0);
        !           587:                        (void) soabort(so2);
        !           588:                }
        !           589:                while ((so2 = TAILQ_FIRST(&so->so_q)) != 0) {
        !           590:                        (void) soqremque(so2, 1);
        !           591:                        (void) soabort(so2);
        !           592:                }
        !           593:        }
        !           594:        if (so->so_pcb == 0)
        !           595:                goto discard;
        !           596:        if (so->so_state & SS_ISCONNECTED) {
        !           597:                if ((so->so_state & SS_ISDISCONNECTING) == 0) {
        !           598:                        error = sodisconnect(so);
        !           599:                        if (error)
        !           600:                                goto drop;
        !           601:                }
        !           602:                if (so->so_options & SO_LINGER) {
        !           603:                        if ((so->so_state & SS_ISDISCONNECTING) &&
        !           604:                            (so->so_state & SS_NBIO))
        !           605:                                goto drop;
        !           606:                        while (so->so_state & SS_ISCONNECTED) {
        !           607:                                error = tsleep((void *)&so->so_timeo,
        !           608:                                               PSOCK | PCATCH, netcls,
        !           609:                                               so->so_linger * hz);
        !           610:                                if (error)
        !           611:                                        break;
        !           612:                        }
        !           613:                }
        !           614:        }
        !           615:  drop:
        !           616:        if (so->so_pcb) {
        !           617:                int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
        !           618:                    NULL, NULL, NULL, NULL);
        !           619:                if (error == 0)
        !           620:                        error = error2;
        !           621:        }
        !           622:  discard:
        !           623:        if (so->so_state & SS_NOFDREF)
        !           624:                panic("soclose: NOFDREF");
        !           625:        so->so_state |= SS_NOFDREF;
        !           626:        sofree(so);
        !           627:        splx(s);
        !           628:        return (error);
        !           629: }
        !           630:
        !           631: /*
        !           632:  * Must be called at splsoftnet...
        !           633:  */
        !           634: int
        !           635: soabort(struct socket *so)
        !           636: {
        !           637:        int error;
        !           638:
        !           639:        KASSERT(so->so_head == NULL);
        !           640:        error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, NULL,
        !           641:            NULL, NULL, NULL);
        !           642:        if (error) {
        !           643:                sofree(so);
        !           644:        }
        !           645:        return error;
        !           646: }
        !           647:
        !           648: int
        !           649: soaccept(struct socket *so, struct mbuf *nam)
        !           650: {
        !           651:        int     s, error;
        !           652:
        !           653:        error = 0;
        !           654:        s = splsoftnet();
        !           655:        if ((so->so_state & SS_NOFDREF) == 0)
        !           656:                panic("soaccept: !NOFDREF");
        !           657:        so->so_state &= ~SS_NOFDREF;
        !           658:        if ((so->so_state & SS_ISDISCONNECTED) == 0 ||
        !           659:            (so->so_proto->pr_flags & PR_ABRTACPTDIS) == 0)
        !           660:                error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
        !           661:                    NULL, nam, NULL, NULL);
        !           662:        else
        !           663:                error = ECONNABORTED;
        !           664:
        !           665:        splx(s);
        !           666:        return (error);
        !           667: }
        !           668:
        !           669: int
        !           670: soconnect(struct socket *so, struct mbuf *nam, struct lwp *l)
        !           671: {
        !           672:        int             s, error;
        !           673:
        !           674:        if (so->so_options & SO_ACCEPTCONN)
        !           675:                return (EOPNOTSUPP);
        !           676:        s = splsoftnet();
        !           677:        /*
        !           678:         * If protocol is connection-based, can only connect once.
        !           679:         * Otherwise, if connected, try to disconnect first.
        !           680:         * This allows user to disconnect by connecting to, e.g.,
        !           681:         * a null address.
        !           682:         */
        !           683:        if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
        !           684:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
        !           685:            (error = sodisconnect(so))))
        !           686:                error = EISCONN;
        !           687:        else
        !           688:                error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
        !           689:                    NULL, nam, NULL, l);
        !           690:        splx(s);
        !           691:        return (error);
        !           692: }
        !           693:
        !           694: int
        !           695: soconnect2(struct socket *so1, struct socket *so2)
        !           696: {
        !           697:        int     s, error;
        !           698:
        !           699:        s = splsoftnet();
        !           700:        error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
        !           701:            NULL, (struct mbuf *)so2, NULL, NULL);
        !           702:        splx(s);
        !           703:        return (error);
        !           704: }
        !           705:
        !           706: int
        !           707: sodisconnect(struct socket *so)
        !           708: {
        !           709:        int     s, error;
        !           710:
        !           711:        s = splsoftnet();
        !           712:        if ((so->so_state & SS_ISCONNECTED) == 0) {
        !           713:                error = ENOTCONN;
        !           714:                goto bad;
        !           715:        }
        !           716:        if (so->so_state & SS_ISDISCONNECTING) {
        !           717:                error = EALREADY;
        !           718:                goto bad;
        !           719:        }
        !           720:        error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
        !           721:            NULL, NULL, NULL, NULL);
        !           722:  bad:
        !           723:        splx(s);
        !           724:        sodopendfree();
        !           725:        return (error);
        !           726: }
        !           727:
        !           728: #define        SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
        !           729: /*
        !           730:  * Send on a socket.
        !           731:  * If send must go all at once and message is larger than
        !           732:  * send buffering, then hard error.
        !           733:  * Lock against other senders.
        !           734:  * If must go all at once and not enough room now, then
        !           735:  * inform user that this would block and do nothing.
        !           736:  * Otherwise, if nonblocking, send as much as possible.
        !           737:  * The data to be sent is described by "uio" if nonzero,
        !           738:  * otherwise by the mbuf chain "top" (which must be null
        !           739:  * if uio is not).  Data provided in mbuf chain must be small
        !           740:  * enough to send all at once.
        !           741:  *
        !           742:  * Returns nonzero on error, timeout or signal; callers
        !           743:  * must check for short counts if EINTR/ERESTART are returned.
        !           744:  * Data and control buffers are freed on return.
        !           745:  */
        !           746: int
        !           747: sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top,
        !           748:        struct mbuf *control, int flags, struct lwp *l)
        !           749: {
        !           750:        struct mbuf     **mp, *m;
        !           751:        struct proc     *p;
        !           752:        long            space, len, resid, clen, mlen;
        !           753:        int             error, s, dontroute, atomic;
        !           754:
        !           755:        p = l->l_proc;
        !           756:        sodopendfree();
        !           757:
        !           758:        clen = 0;
        !           759:        atomic = sosendallatonce(so) || top;
        !           760:        if (uio)
        !           761:                resid = uio->uio_resid;
        !           762:        else
        !           763:                resid = top->m_pkthdr.len;
        !           764:        /*
        !           765:         * In theory resid should be unsigned.
        !           766:         * However, space must be signed, as it might be less than 0
        !           767:         * if we over-committed, and we must use a signed comparison
        !           768:         * of space and resid.  On the other hand, a negative resid
        !           769:         * causes us to loop sending 0-length segments to the protocol.
        !           770:         */
        !           771:        if (resid < 0) {
        !           772:                error = EINVAL;
        !           773:                goto out;
        !           774:        }
        !           775:        dontroute =
        !           776:            (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
        !           777:            (so->so_proto->pr_flags & PR_ATOMIC);
        !           778:        if (p)
        !           779:                p->p_stats->p_ru.ru_msgsnd++;
        !           780:        if (control)
        !           781:                clen = control->m_len;
        !           782: #define        snderr(errno)   { error = errno; splx(s); goto release; }
        !           783:
        !           784:  restart:
        !           785:        if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
        !           786:                goto out;
        !           787:        do {
        !           788:                s = splsoftnet();
        !           789:                if (so->so_state & SS_CANTSENDMORE)
        !           790:                        snderr(EPIPE);
        !           791:                if (so->so_error) {
        !           792:                        error = so->so_error;
        !           793:                        so->so_error = 0;
        !           794:                        splx(s);
        !           795:                        goto release;
        !           796:                }
        !           797:                if ((so->so_state & SS_ISCONNECTED) == 0) {
        !           798:                        if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
        !           799:                                if ((so->so_state & SS_ISCONFIRMING) == 0 &&
        !           800:                                    !(resid == 0 && clen != 0))
        !           801:                                        snderr(ENOTCONN);
        !           802:                        } else if (addr == 0)
        !           803:                                snderr(EDESTADDRREQ);
        !           804:                }
        !           805:                space = sbspace(&so->so_snd);
        !           806:                if (flags & MSG_OOB)
        !           807:                        space += 1024;
        !           808:                if ((atomic && resid > so->so_snd.sb_hiwat) ||
        !           809:                    clen > so->so_snd.sb_hiwat)
        !           810:                        snderr(EMSGSIZE);
        !           811:                if (space < resid + clen &&
        !           812:                    (atomic || space < so->so_snd.sb_lowat || space < clen)) {
        !           813:                        if (so->so_state & SS_NBIO)
        !           814:                                snderr(EWOULDBLOCK);
        !           815:                        sbunlock(&so->so_snd);
        !           816:                        error = sbwait(&so->so_snd);
        !           817:                        splx(s);
        !           818:                        if (error)
        !           819:                                goto out;
        !           820:                        goto restart;
        !           821:                }
        !           822:                splx(s);
        !           823:                mp = &top;
        !           824:                space -= clen;
        !           825:                do {
        !           826:                        if (uio == NULL) {
        !           827:                                /*
        !           828:                                 * Data is prepackaged in "top".
        !           829:                                 */
        !           830:                                resid = 0;
        !           831:                                if (flags & MSG_EOR)
        !           832:                                        top->m_flags |= M_EOR;
        !           833:                        } else do {
        !           834:                                if (top == 0) {
        !           835:                                        m = m_gethdr(M_WAIT, MT_DATA);
        !           836:                                        mlen = MHLEN;
        !           837:                                        m->m_pkthdr.len = 0;
        !           838:                                        m->m_pkthdr.rcvif = NULL;
        !           839:                                } else {
        !           840:                                        m = m_get(M_WAIT, MT_DATA);
        !           841:                                        mlen = MLEN;
        !           842:                                }
        !           843:                                MCLAIM(m, so->so_snd.sb_mowner);
        !           844:                                if (sock_loan_thresh >= 0 &&
        !           845:                                    uio->uio_iov->iov_len >= sock_loan_thresh &&
        !           846:                                    space >= sock_loan_thresh &&
        !           847:                                    (len = sosend_loan(so, uio, m,
        !           848:                                                       space)) != 0) {
        !           849:                                        SOSEND_COUNTER_INCR(&sosend_loan_big);
        !           850:                                        space -= len;
        !           851:                                        goto have_data;
        !           852:                                }
        !           853:                                if (resid >= MINCLSIZE && space >= MCLBYTES) {
        !           854:                                        SOSEND_COUNTER_INCR(&sosend_copy_big);
        !           855:                                        m_clget(m, M_WAIT);
        !           856:                                        if ((m->m_flags & M_EXT) == 0)
        !           857:                                                goto nopages;
        !           858:                                        mlen = MCLBYTES;
        !           859:                                        if (atomic && top == 0) {
        !           860:                                                len = lmin(MCLBYTES - max_hdr,
        !           861:                                                    resid);
        !           862:                                                m->m_data += max_hdr;
        !           863:                                        } else
        !           864:                                                len = lmin(MCLBYTES, resid);
        !           865:                                        space -= len;
        !           866:                                } else {
        !           867:  nopages:
        !           868:                                        SOSEND_COUNTER_INCR(&sosend_copy_small);
        !           869:                                        len = lmin(lmin(mlen, resid), space);
        !           870:                                        space -= len;
        !           871:                                        /*
        !           872:                                         * For datagram protocols, leave room
        !           873:                                         * for protocol headers in first mbuf.
        !           874:                                         */
        !           875:                                        if (atomic && top == 0 && len < mlen)
        !           876:                                                MH_ALIGN(m, len);
        !           877:                                }
        !           878:                                error = uiomove(mtod(m, void *), (int)len,
        !           879:                                    uio);
        !           880:  have_data:
        !           881:                                resid = uio->uio_resid;
        !           882:                                m->m_len = len;
        !           883:                                *mp = m;
        !           884:                                top->m_pkthdr.len += len;
        !           885:                                if (error)
        !           886:                                        goto release;
        !           887:                                mp = &m->m_next;
        !           888:                                if (resid <= 0) {
        !           889:                                        if (flags & MSG_EOR)
        !           890:                                                top->m_flags |= M_EOR;
        !           891:                                        break;
        !           892:                                }
        !           893:                        } while (space > 0 && atomic);
        !           894:
        !           895:                        s = splsoftnet();
        !           896:
        !           897:                        if (so->so_state & SS_CANTSENDMORE)
        !           898:                                snderr(EPIPE);
        !           899:
        !           900:                        if (dontroute)
        !           901:                                so->so_options |= SO_DONTROUTE;
        !           902:                        if (resid > 0)
        !           903:                                so->so_state |= SS_MORETOCOME;
        !           904:                        error = (*so->so_proto->pr_usrreq)(so,
        !           905:                            (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
        !           906:                            top, addr, control, curlwp);        /* XXX */
        !           907:                        if (dontroute)
        !           908:                                so->so_options &= ~SO_DONTROUTE;
        !           909:                        if (resid > 0)
        !           910:                                so->so_state &= ~SS_MORETOCOME;
        !           911:                        splx(s);
        !           912:
        !           913:                        clen = 0;
        !           914:                        control = 0;
        !           915:                        top = 0;
        !           916:                        mp = &top;
        !           917:                        if (error)
        !           918:                                goto release;
        !           919:                } while (resid && space > 0);
        !           920:        } while (resid);
        !           921:
        !           922:  release:
        !           923:        sbunlock(&so->so_snd);
        !           924:  out:
        !           925:        if (top)
        !           926:                m_freem(top);
        !           927:        if (control)
        !           928:                m_freem(control);
        !           929:        return (error);
        !           930: }
        !           931:
        !           932: /*
        !           933:  * Implement receive operations on a socket.
        !           934:  * We depend on the way that records are added to the sockbuf
        !           935:  * by sbappend*.  In particular, each record (mbufs linked through m_next)
        !           936:  * must begin with an address if the protocol so specifies,
        !           937:  * followed by an optional mbuf or mbufs containing ancillary data,
        !           938:  * and then zero or more mbufs of data.
        !           939:  * In order to avoid blocking network interrupts for the entire time here,
        !           940:  * we splx() while doing the actual copy to user space.
        !           941:  * Although the sockbuf is locked, new data may still be appended,
        !           942:  * and thus we must maintain consistency of the sockbuf during that time.
        !           943:  *
        !           944:  * The caller may receive the data as a single mbuf chain by supplying
        !           945:  * an mbuf **mp0 for use in returning the chain.  The uio is then used
        !           946:  * only for the count in uio_resid.
        !           947:  */
        !           948: int
        !           949: soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio,
        !           950:        struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
        !           951: {
        !           952:        struct lwp *l = curlwp;
        !           953:        struct mbuf     *m, **mp;
        !           954:        int             flags, len, error, s, offset, moff, type, orig_resid;
        !           955:        const struct protosw    *pr;
        !           956:        struct mbuf     *nextrecord;
        !           957:        int             mbuf_removed = 0;
        !           958:
        !           959:        pr = so->so_proto;
        !           960:        mp = mp0;
        !           961:        type = 0;
        !           962:        orig_resid = uio->uio_resid;
        !           963:
        !           964:        if (paddr)
        !           965:                *paddr = 0;
        !           966:        if (controlp)
        !           967:                *controlp = 0;
        !           968:        if (flagsp)
        !           969:                flags = *flagsp &~ MSG_EOR;
        !           970:        else
        !           971:                flags = 0;
        !           972:
        !           973:        if ((flags & MSG_DONTWAIT) == 0)
        !           974:                sodopendfree();
        !           975:
        !           976:        if (flags & MSG_OOB) {
        !           977:                m = m_get(M_WAIT, MT_DATA);
        !           978:                error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
        !           979:                    (struct mbuf *)(long)(flags & MSG_PEEK), NULL, l);
        !           980:                if (error)
        !           981:                        goto bad;
        !           982:                do {
        !           983:                        error = uiomove(mtod(m, void *),
        !           984:                            (int) min(uio->uio_resid, m->m_len), uio);
        !           985:                        m = m_free(m);
        !           986:                } while (uio->uio_resid && error == 0 && m);
        !           987:  bad:
        !           988:                if (m)
        !           989:                        m_freem(m);
        !           990:                return (error);
        !           991:        }
        !           992:        if (mp)
        !           993:                *mp = NULL;
        !           994:        if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
        !           995:                (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, l);
        !           996:
        !           997:  restart:
        !           998:        if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
        !           999:                return (error);
        !          1000:        s = splsoftnet();
        !          1001:
        !          1002:        m = so->so_rcv.sb_mb;
        !          1003:        /*
        !          1004:         * If we have less data than requested, block awaiting more
        !          1005:         * (subject to any timeout) if:
        !          1006:         *   1. the current count is less than the low water mark,
        !          1007:         *   2. MSG_WAITALL is set, and it is possible to do the entire
        !          1008:         *      receive operation at once if we block (resid <= hiwat), or
        !          1009:         *   3. MSG_DONTWAIT is not set.
        !          1010:         * If MSG_WAITALL is set but resid is larger than the receive buffer,
        !          1011:         * we have to do the receive in sections, and thus risk returning
        !          1012:         * a short count if a timeout or signal occurs after we start.
        !          1013:         */
        !          1014:        if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
        !          1015:            so->so_rcv.sb_cc < uio->uio_resid) &&
        !          1016:            (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
        !          1017:            ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
        !          1018:            m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
        !          1019: #ifdef DIAGNOSTIC
        !          1020:                if (m == 0 && so->so_rcv.sb_cc)
        !          1021:                        panic("receive 1");
        !          1022: #endif
        !          1023:                if (so->so_error) {
        !          1024:                        if (m)
        !          1025:                                goto dontblock;
        !          1026:                        error = so->so_error;
        !          1027:                        if ((flags & MSG_PEEK) == 0)
        !          1028:                                so->so_error = 0;
        !          1029:                        goto release;
        !          1030:                }
        !          1031:                if (so->so_state & SS_CANTRCVMORE) {
        !          1032:                        if (m)
        !          1033:                                goto dontblock;
        !          1034:                        else
        !          1035:                                goto release;
        !          1036:                }
        !          1037:                for (; m; m = m->m_next)
        !          1038:                        if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
        !          1039:                                m = so->so_rcv.sb_mb;
        !          1040:                                goto dontblock;
        !          1041:                        }
        !          1042:                if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
        !          1043:                    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
        !          1044:                        error = ENOTCONN;
        !          1045:                        goto release;
        !          1046:                }
        !          1047:                if (uio->uio_resid == 0)
        !          1048:                        goto release;
        !          1049:                if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
        !          1050:                        error = EWOULDBLOCK;
        !          1051:                        goto release;
        !          1052:                }
        !          1053:                SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1");
        !          1054:                SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1");
        !          1055:                sbunlock(&so->so_rcv);
        !          1056:                error = sbwait(&so->so_rcv);
        !          1057:                splx(s);
        !          1058:                if (error)
        !          1059:                        return (error);
        !          1060:                goto restart;
        !          1061:        }
        !          1062:  dontblock:
        !          1063:        /*
        !          1064:         * On entry here, m points to the first record of the socket buffer.
        !          1065:         * While we process the initial mbufs containing address and control
        !          1066:         * info, we save a copy of m->m_nextpkt into nextrecord.
        !          1067:         */
        !          1068:        if (l)
        !          1069:                l->l_proc->p_stats->p_ru.ru_msgrcv++;
        !          1070:        KASSERT(m == so->so_rcv.sb_mb);
        !          1071:        SBLASTRECORDCHK(&so->so_rcv, "soreceive 1");
        !          1072:        SBLASTMBUFCHK(&so->so_rcv, "soreceive 1");
        !          1073:        nextrecord = m->m_nextpkt;
        !          1074:        if (pr->pr_flags & PR_ADDR) {
        !          1075: #ifdef DIAGNOSTIC
        !          1076:                if (m->m_type != MT_SONAME)
        !          1077:                        panic("receive 1a");
        !          1078: #endif
        !          1079:                orig_resid = 0;
        !          1080:                if (flags & MSG_PEEK) {
        !          1081:                        if (paddr)
        !          1082:                                *paddr = m_copy(m, 0, m->m_len);
        !          1083:                        m = m->m_next;
        !          1084:                } else {
        !          1085:                        sbfree(&so->so_rcv, m);
        !          1086:                        mbuf_removed = 1;
        !          1087:                        if (paddr) {
        !          1088:                                *paddr = m;
        !          1089:                                so->so_rcv.sb_mb = m->m_next;
        !          1090:                                m->m_next = 0;
        !          1091:                                m = so->so_rcv.sb_mb;
        !          1092:                        } else {
        !          1093:                                MFREE(m, so->so_rcv.sb_mb);
        !          1094:                                m = so->so_rcv.sb_mb;
        !          1095:                        }
        !          1096:                }
        !          1097:        }
        !          1098:        while (m && m->m_type == MT_CONTROL && error == 0) {
        !          1099:                if (flags & MSG_PEEK) {
        !          1100:                        if (controlp)
        !          1101:                                *controlp = m_copy(m, 0, m->m_len);
        !          1102:                        m = m->m_next;
        !          1103:                } else {
        !          1104:                        sbfree(&so->so_rcv, m);
        !          1105:                        mbuf_removed = 1;
        !          1106:                        if (controlp) {
        !          1107:                                struct domain *dom = pr->pr_domain;
        !          1108:                                if (dom->dom_externalize && l &&
        !          1109:                                    mtod(m, struct cmsghdr *)->cmsg_type ==
        !          1110:                                    SCM_RIGHTS)
        !          1111:                                        error = (*dom->dom_externalize)(m, l);
        !          1112:                                *controlp = m;
        !          1113:                                so->so_rcv.sb_mb = m->m_next;
        !          1114:                                m->m_next = 0;
        !          1115:                                m = so->so_rcv.sb_mb;
        !          1116:                        } else {
        !          1117:                                /*
        !          1118:                                 * Dispose of any SCM_RIGHTS message that went
        !          1119:                                 * through the read path rather than recv.
        !          1120:                                 */
        !          1121:                                if (pr->pr_domain->dom_dispose &&
        !          1122:                                    mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)
        !          1123:                                        (*pr->pr_domain->dom_dispose)(m);
        !          1124:                                MFREE(m, so->so_rcv.sb_mb);
        !          1125:                                m = so->so_rcv.sb_mb;
        !          1126:                        }
        !          1127:                }
        !          1128:                if (controlp) {
        !          1129:                        orig_resid = 0;
        !          1130:                        controlp = &(*controlp)->m_next;
        !          1131:                }
        !          1132:        }
        !          1133:
        !          1134:        /*
        !          1135:         * If m is non-NULL, we have some data to read.  From now on,
        !          1136:         * make sure to keep sb_lastrecord consistent when working on
        !          1137:         * the last packet on the chain (nextrecord == NULL) and we
        !          1138:         * change m->m_nextpkt.
        !          1139:         */
        !          1140:        if (m) {
        !          1141:                if ((flags & MSG_PEEK) == 0) {
        !          1142:                        m->m_nextpkt = nextrecord;
        !          1143:                        /*
        !          1144:                         * If nextrecord == NULL (this is a single chain),
        !          1145:                         * then sb_lastrecord may not be valid here if m
        !          1146:                         * was changed earlier.
        !          1147:                         */
        !          1148:                        if (nextrecord == NULL) {
        !          1149:                                KASSERT(so->so_rcv.sb_mb == m);
        !          1150:                                so->so_rcv.sb_lastrecord = m;
        !          1151:                        }
        !          1152:                }
        !          1153:                type = m->m_type;
        !          1154:                if (type == MT_OOBDATA)
        !          1155:                        flags |= MSG_OOB;
        !          1156:        } else {
        !          1157:                if ((flags & MSG_PEEK) == 0) {
        !          1158:                        KASSERT(so->so_rcv.sb_mb == m);
        !          1159:                        so->so_rcv.sb_mb = nextrecord;
        !          1160:                        SB_EMPTY_FIXUP(&so->so_rcv);
        !          1161:                }
        !          1162:        }
        !          1163:        SBLASTRECORDCHK(&so->so_rcv, "soreceive 2");
        !          1164:        SBLASTMBUFCHK(&so->so_rcv, "soreceive 2");
        !          1165:
        !          1166:        moff = 0;
        !          1167:        offset = 0;
        !          1168:        while (m && uio->uio_resid > 0 && error == 0) {
        !          1169:                if (m->m_type == MT_OOBDATA) {
        !          1170:                        if (type != MT_OOBDATA)
        !          1171:                                break;
        !          1172:                } else if (type == MT_OOBDATA)
        !          1173:                        break;
        !          1174: #ifdef DIAGNOSTIC
        !          1175:                else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
        !          1176:                        panic("receive 3");
        !          1177: #endif
        !          1178:                so->so_state &= ~SS_RCVATMARK;
        !          1179:                len = uio->uio_resid;
        !          1180:                if (so->so_oobmark && len > so->so_oobmark - offset)
        !          1181:                        len = so->so_oobmark - offset;
        !          1182:                if (len > m->m_len - moff)
        !          1183:                        len = m->m_len - moff;
        !          1184:                /*
        !          1185:                 * If mp is set, just pass back the mbufs.
        !          1186:                 * Otherwise copy them out via the uio, then free.
        !          1187:                 * Sockbuf must be consistent here (points to current mbuf,
        !          1188:                 * it points to next record) when we drop priority;
        !          1189:                 * we must note any additions to the sockbuf when we
        !          1190:                 * block interrupts again.
        !          1191:                 */
        !          1192:                if (mp == 0) {
        !          1193:                        SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
        !          1194:                        SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
        !          1195:                        splx(s);
        !          1196:                        error = uiomove(mtod(m, char *) + moff, (int)len, uio);
        !          1197:                        s = splsoftnet();
        !          1198:                        if (error) {
        !          1199:                                /*
        !          1200:                                 * If any part of the record has been removed
        !          1201:                                 * (such as the MT_SONAME mbuf, which will
        !          1202:                                 * happen when PR_ADDR, and thus also
        !          1203:                                 * PR_ATOMIC, is set), then drop the entire
        !          1204:                                 * record to maintain the atomicity of the
        !          1205:                                 * receive operation.
        !          1206:                                 *
        !          1207:                                 * This avoids a later panic("receive 1a")
        !          1208:                                 * when compiled with DIAGNOSTIC.
        !          1209:                                 */
        !          1210:                                if (m && mbuf_removed
        !          1211:                                    && (pr->pr_flags & PR_ATOMIC))
        !          1212:                                        (void) sbdroprecord(&so->so_rcv);
        !          1213:
        !          1214:                                goto release;
        !          1215:                        }
        !          1216:                } else
        !          1217:                        uio->uio_resid -= len;
        !          1218:                if (len == m->m_len - moff) {
        !          1219:                        if (m->m_flags & M_EOR)
        !          1220:                                flags |= MSG_EOR;
        !          1221:                        if (flags & MSG_PEEK) {
        !          1222:                                m = m->m_next;
        !          1223:                                moff = 0;
        !          1224:                        } else {
        !          1225:                                nextrecord = m->m_nextpkt;
        !          1226:                                sbfree(&so->so_rcv, m);
        !          1227:                                if (mp) {
        !          1228:                                        *mp = m;
        !          1229:                                        mp = &m->m_next;
        !          1230:                                        so->so_rcv.sb_mb = m = m->m_next;
        !          1231:                                        *mp = NULL;
        !          1232:                                } else {
        !          1233:                                        MFREE(m, so->so_rcv.sb_mb);
        !          1234:                                        m = so->so_rcv.sb_mb;
        !          1235:                                }
        !          1236:                                /*
        !          1237:                                 * If m != NULL, we also know that
        !          1238:                                 * so->so_rcv.sb_mb != NULL.
        !          1239:                                 */
        !          1240:                                KASSERT(so->so_rcv.sb_mb == m);
        !          1241:                                if (m) {
        !          1242:                                        m->m_nextpkt = nextrecord;
        !          1243:                                        if (nextrecord == NULL)
        !          1244:                                                so->so_rcv.sb_lastrecord = m;
        !          1245:                                } else {
        !          1246:                                        so->so_rcv.sb_mb = nextrecord;
        !          1247:                                        SB_EMPTY_FIXUP(&so->so_rcv);
        !          1248:                                }
        !          1249:                                SBLASTRECORDCHK(&so->so_rcv, "soreceive 3");
        !          1250:                                SBLASTMBUFCHK(&so->so_rcv, "soreceive 3");
        !          1251:                        }
        !          1252:                } else {
        !          1253:                        if (flags & MSG_PEEK)
        !          1254:                                moff += len;
        !          1255:                        else {
        !          1256:                                if (mp)
        !          1257:                                        *mp = m_copym(m, 0, len, M_WAIT);
        !          1258:                                m->m_data += len;
        !          1259:                                m->m_len -= len;
        !          1260:                                so->so_rcv.sb_cc -= len;
        !          1261:                        }
        !          1262:                }
        !          1263:                if (so->so_oobmark) {
        !          1264:                        if ((flags & MSG_PEEK) == 0) {
        !          1265:                                so->so_oobmark -= len;
        !          1266:                                if (so->so_oobmark == 0) {
        !          1267:                                        so->so_state |= SS_RCVATMARK;
        !          1268:                                        break;
        !          1269:                                }
        !          1270:                        } else {
        !          1271:                                offset += len;
        !          1272:                                if (offset == so->so_oobmark)
        !          1273:                                        break;
        !          1274:                        }
        !          1275:                }
        !          1276:                if (flags & MSG_EOR)
        !          1277:                        break;
        !          1278:                /*
        !          1279:                 * If the MSG_WAITALL flag is set (for non-atomic socket),
        !          1280:                 * we must not quit until "uio->uio_resid == 0" or an error
        !          1281:                 * termination.  If a signal/timeout occurs, return
        !          1282:                 * with a short count but without error.
        !          1283:                 * Keep sockbuf locked against other readers.
        !          1284:                 */
        !          1285:                while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
        !          1286:                    !sosendallatonce(so) && !nextrecord) {
        !          1287:                        if (so->so_error || so->so_state & SS_CANTRCVMORE)
        !          1288:                                break;
        !          1289:                        /*
        !          1290:                         * If we are peeking and the socket receive buffer is
        !          1291:                         * full, stop since we can't get more data to peek at.
        !          1292:                         */
        !          1293:                        if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0)
        !          1294:                                break;
        !          1295:                        /*
        !          1296:                         * If we've drained the socket buffer, tell the
        !          1297:                         * protocol in case it needs to do something to
        !          1298:                         * get it filled again.
        !          1299:                         */
        !          1300:                        if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb)
        !          1301:                                (*pr->pr_usrreq)(so, PRU_RCVD,
        !          1302:                                    NULL, (struct mbuf *)(long)flags, NULL, l);
        !          1303:                        SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2");
        !          1304:                        SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2");
        !          1305:                        error = sbwait(&so->so_rcv);
        !          1306:                        if (error) {
        !          1307:                                sbunlock(&so->so_rcv);
        !          1308:                                splx(s);
        !          1309:                                return (0);
        !          1310:                        }
        !          1311:                        if ((m = so->so_rcv.sb_mb) != NULL)
        !          1312:                                nextrecord = m->m_nextpkt;
        !          1313:                }
        !          1314:        }
        !          1315:
        !          1316:        if (m && pr->pr_flags & PR_ATOMIC) {
        !          1317:                flags |= MSG_TRUNC;
        !          1318:                if ((flags & MSG_PEEK) == 0)
        !          1319:                        (void) sbdroprecord(&so->so_rcv);
        !          1320:        }
        !          1321:        if ((flags & MSG_PEEK) == 0) {
        !          1322:                if (m == 0) {
        !          1323:                        /*
        !          1324:                         * First part is an inline SB_EMPTY_FIXUP().  Second
        !          1325:                         * part makes sure sb_lastrecord is up-to-date if
        !          1326:                         * there is still data in the socket buffer.
        !          1327:                         */
        !          1328:                        so->so_rcv.sb_mb = nextrecord;
        !          1329:                        if (so->so_rcv.sb_mb == NULL) {
        !          1330:                                so->so_rcv.sb_mbtail = NULL;
        !          1331:                                so->so_rcv.sb_lastrecord = NULL;
        !          1332:                        } else if (nextrecord->m_nextpkt == NULL)
        !          1333:                                so->so_rcv.sb_lastrecord = nextrecord;
        !          1334:                }
        !          1335:                SBLASTRECORDCHK(&so->so_rcv, "soreceive 4");
        !          1336:                SBLASTMBUFCHK(&so->so_rcv, "soreceive 4");
        !          1337:                if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
        !          1338:                        (*pr->pr_usrreq)(so, PRU_RCVD, NULL,
        !          1339:                            (struct mbuf *)(long)flags, NULL, l);
        !          1340:        }
        !          1341:        if (orig_resid == uio->uio_resid && orig_resid &&
        !          1342:            (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
        !          1343:                sbunlock(&so->so_rcv);
        !          1344:                splx(s);
        !          1345:                goto restart;
        !          1346:        }
        !          1347:
        !          1348:        if (flagsp)
        !          1349:                *flagsp |= flags;
        !          1350:  release:
        !          1351:        sbunlock(&so->so_rcv);
        !          1352:        splx(s);
        !          1353:        return (error);
        !          1354: }
        !          1355:
        !          1356: int
        !          1357: soshutdown(struct socket *so, int how)
        !          1358: {
        !          1359:        const struct protosw    *pr;
        !          1360:
        !          1361:        pr = so->so_proto;
        !          1362:        if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR))
        !          1363:                return (EINVAL);
        !          1364:
        !          1365:        if (how == SHUT_RD || how == SHUT_RDWR)
        !          1366:                sorflush(so);
        !          1367:        if (how == SHUT_WR || how == SHUT_RDWR)
        !          1368:                return (*pr->pr_usrreq)(so, PRU_SHUTDOWN, NULL,
        !          1369:                    NULL, NULL, NULL);
        !          1370:        return (0);
        !          1371: }
        !          1372:
        !          1373: void
        !          1374: sorflush(struct socket *so)
        !          1375: {
        !          1376:        struct sockbuf  *sb, asb;
        !          1377:        const struct protosw    *pr;
        !          1378:        int             s;
        !          1379:
        !          1380:        sb = &so->so_rcv;
        !          1381:        pr = so->so_proto;
        !          1382:        sb->sb_flags |= SB_NOINTR;
        !          1383:        (void) sblock(sb, M_WAITOK);
        !          1384:        s = splnet();
        !          1385:        socantrcvmore(so);
        !          1386:        sbunlock(sb);
        !          1387:        asb = *sb;
        !          1388:        /*
        !          1389:         * Clear most of the sockbuf structure, but leave some of the
        !          1390:         * fields valid.
        !          1391:         */
        !          1392:        memset(&sb->sb_startzero, 0,
        !          1393:            sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
        !          1394:        splx(s);
        !          1395:        if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
        !          1396:                (*pr->pr_domain->dom_dispose)(asb.sb_mb);
        !          1397:        sbrelease(&asb, so);
        !          1398: }
        !          1399:
        !          1400: int
        !          1401: sosetopt(struct socket *so, int level, int optname, struct mbuf *m0)
        !          1402: {
        !          1403:        int             error;
        !          1404:        struct mbuf     *m;
        !          1405:        struct linger   *l;
        !          1406:        struct sockbuf  *sb;
        !          1407:
        !          1408:        error = 0;
        !          1409:        m = m0;
        !          1410:        if (level != SOL_SOCKET) {
        !          1411:                if (so->so_proto && so->so_proto->pr_ctloutput)
        !          1412:                        return ((*so->so_proto->pr_ctloutput)
        !          1413:                                  (PRCO_SETOPT, so, level, optname, &m0));
        !          1414:                error = ENOPROTOOPT;
        !          1415:        } else {
        !          1416:                switch (optname) {
        !          1417:
        !          1418:                case SO_LINGER:
        !          1419:                        if (m == NULL || m->m_len != sizeof(struct linger)) {
        !          1420:                                error = EINVAL;
        !          1421:                                goto bad;
        !          1422:                        }
        !          1423:                        l = mtod(m, struct linger *);
        !          1424:                        if (l->l_linger < 0 || l->l_linger > USHRT_MAX ||
        !          1425:                            l->l_linger > (INT_MAX / hz)) {
        !          1426:                                error = EDOM;
        !          1427:                                goto bad;
        !          1428:                        }
        !          1429:                        so->so_linger = l->l_linger;
        !          1430:                        if (l->l_onoff)
        !          1431:                                so->so_options |= SO_LINGER;
        !          1432:                        else
        !          1433:                                so->so_options &= ~SO_LINGER;
        !          1434:                        break;
        !          1435:
        !          1436:                case SO_DEBUG:
        !          1437:                case SO_KEEPALIVE:
        !          1438:                case SO_DONTROUTE:
        !          1439:                case SO_USELOOPBACK:
        !          1440:                case SO_BROADCAST:
        !          1441:                case SO_REUSEADDR:
        !          1442:                case SO_REUSEPORT:
        !          1443:                case SO_OOBINLINE:
        !          1444:                case SO_TIMESTAMP:
        !          1445:                        if (m == NULL || m->m_len < sizeof(int)) {
        !          1446:                                error = EINVAL;
        !          1447:                                goto bad;
        !          1448:                        }
        !          1449:                        if (*mtod(m, int *))
        !          1450:                                so->so_options |= optname;
        !          1451:                        else
        !          1452:                                so->so_options &= ~optname;
        !          1453:                        break;
        !          1454:
        !          1455:                case SO_SNDBUF:
        !          1456:                case SO_RCVBUF:
        !          1457:                case SO_SNDLOWAT:
        !          1458:                case SO_RCVLOWAT:
        !          1459:                    {
        !          1460:                        int optval;
        !          1461:
        !          1462:                        if (m == NULL || m->m_len < sizeof(int)) {
        !          1463:                                error = EINVAL;
        !          1464:                                goto bad;
        !          1465:                        }
        !          1466:
        !          1467:                        /*
        !          1468:                         * Values < 1 make no sense for any of these
        !          1469:                         * options, so disallow them.
        !          1470:                         */
        !          1471:                        optval = *mtod(m, int *);
        !          1472:                        if (optval < 1) {
        !          1473:                                error = EINVAL;
        !          1474:                                goto bad;
        !          1475:                        }
        !          1476:
        !          1477:                        switch (optname) {
        !          1478:
        !          1479:                        case SO_SNDBUF:
        !          1480:                        case SO_RCVBUF:
        !          1481:                                sb = (optname == SO_SNDBUF) ?
        !          1482:                                    &so->so_snd : &so->so_rcv;
        !          1483:                                if (sbreserve(sb, (u_long)optval, so) == 0) {
        !          1484:                                        error = ENOBUFS;
        !          1485:                                        goto bad;
        !          1486:                                }
        !          1487:                                sb->sb_flags &= ~SB_AUTOSIZE;
        !          1488:                                break;
        !          1489:
        !          1490:                        /*
        !          1491:                         * Make sure the low-water is never greater than
        !          1492:                         * the high-water.
        !          1493:                         */
        !          1494:                        case SO_SNDLOWAT:
        !          1495:                                so->so_snd.sb_lowat =
        !          1496:                                    (optval > so->so_snd.sb_hiwat) ?
        !          1497:                                    so->so_snd.sb_hiwat : optval;
        !          1498:                                break;
        !          1499:                        case SO_RCVLOWAT:
        !          1500:                                so->so_rcv.sb_lowat =
        !          1501:                                    (optval > so->so_rcv.sb_hiwat) ?
        !          1502:                                    so->so_rcv.sb_hiwat : optval;
        !          1503:                                break;
        !          1504:                        }
        !          1505:                        break;
        !          1506:                    }
        !          1507:
        !          1508:                case SO_SNDTIMEO:
        !          1509:                case SO_RCVTIMEO:
        !          1510:                    {
        !          1511:                        struct timeval *tv;
        !          1512:                        int val;
        !          1513:
        !          1514:                        if (m == NULL || m->m_len < sizeof(*tv)) {
        !          1515:                                error = EINVAL;
        !          1516:                                goto bad;
        !          1517:                        }
        !          1518:                        tv = mtod(m, struct timeval *);
        !          1519:                        if (tv->tv_sec > (INT_MAX - tv->tv_usec / tick) / hz) {
        !          1520:                                error = EDOM;
        !          1521:                                goto bad;
        !          1522:                        }
        !          1523:                        val = tv->tv_sec * hz + tv->tv_usec / tick;
        !          1524:                        if (val == 0 && tv->tv_usec != 0)
        !          1525:                                val = 1;
        !          1526:
        !          1527:                        switch (optname) {
        !          1528:
        !          1529:                        case SO_SNDTIMEO:
        !          1530:                                so->so_snd.sb_timeo = val;
        !          1531:                                break;
        !          1532:                        case SO_RCVTIMEO:
        !          1533:                                so->so_rcv.sb_timeo = val;
        !          1534:                                break;
        !          1535:                        }
        !          1536:                        break;
        !          1537:                    }
        !          1538:
        !          1539:                default:
        !          1540:                        error = ENOPROTOOPT;
        !          1541:                        break;
        !          1542:                }
        !          1543:                if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
        !          1544:                        (void) ((*so->so_proto->pr_ctloutput)
        !          1545:                                  (PRCO_SETOPT, so, level, optname, &m0));
        !          1546:                        m = NULL;       /* freed by protocol */
        !          1547:                }
        !          1548:        }
        !          1549:  bad:
        !          1550:        if (m)
        !          1551:                (void) m_free(m);
        !          1552:        return (error);
        !          1553: }
        !          1554:
        !          1555: int
        !          1556: sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
        !          1557: {
        !          1558:        struct mbuf     *m;
        !          1559:
        !          1560:        if (level != SOL_SOCKET) {
        !          1561:                if (so->so_proto && so->so_proto->pr_ctloutput) {
        !          1562:                        return ((*so->so_proto->pr_ctloutput)
        !          1563:                                  (PRCO_GETOPT, so, level, optname, mp));
        !          1564:                } else
        !          1565:                        return (ENOPROTOOPT);
        !          1566:        } else {
        !          1567:                m = m_get(M_WAIT, MT_SOOPTS);
        !          1568:                m->m_len = sizeof(int);
        !          1569:
        !          1570:                switch (optname) {
        !          1571:
        !          1572:                case SO_LINGER:
        !          1573:                        m->m_len = sizeof(struct linger);
        !          1574:                        mtod(m, struct linger *)->l_onoff =
        !          1575:                            (so->so_options & SO_LINGER) ? 1 : 0;
        !          1576:                        mtod(m, struct linger *)->l_linger = so->so_linger;
        !          1577:                        break;
        !          1578:
        !          1579:                case SO_USELOOPBACK:
        !          1580:                case SO_DONTROUTE:
        !          1581:                case SO_DEBUG:
        !          1582:                case SO_KEEPALIVE:
        !          1583:                case SO_REUSEADDR:
        !          1584:                case SO_REUSEPORT:
        !          1585:                case SO_BROADCAST:
        !          1586:                case SO_OOBINLINE:
        !          1587:                case SO_TIMESTAMP:
        !          1588:                        *mtod(m, int *) = (so->so_options & optname) ? 1 : 0;
        !          1589:                        break;
        !          1590:
        !          1591:                case SO_TYPE:
        !          1592:                        *mtod(m, int *) = so->so_type;
        !          1593:                        break;
        !          1594:
        !          1595:                case SO_ERROR:
        !          1596:                        *mtod(m, int *) = so->so_error;
        !          1597:                        so->so_error = 0;
        !          1598:                        break;
        !          1599:
        !          1600:                case SO_SNDBUF:
        !          1601:                        *mtod(m, int *) = so->so_snd.sb_hiwat;
        !          1602:                        break;
        !          1603:
        !          1604:                case SO_RCVBUF:
        !          1605:                        *mtod(m, int *) = so->so_rcv.sb_hiwat;
        !          1606:                        break;
        !          1607:
        !          1608:                case SO_SNDLOWAT:
        !          1609:                        *mtod(m, int *) = so->so_snd.sb_lowat;
        !          1610:                        break;
        !          1611:
        !          1612:                case SO_RCVLOWAT:
        !          1613:                        *mtod(m, int *) = so->so_rcv.sb_lowat;
        !          1614:                        break;
        !          1615:
        !          1616:                case SO_SNDTIMEO:
        !          1617:                case SO_RCVTIMEO:
        !          1618:                    {
        !          1619:                        int val = (optname == SO_SNDTIMEO ?
        !          1620:                             so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
        !          1621:
        !          1622:                        m->m_len = sizeof(struct timeval);
        !          1623:                        mtod(m, struct timeval *)->tv_sec = val / hz;
        !          1624:                        mtod(m, struct timeval *)->tv_usec =
        !          1625:                            (val % hz) * tick;
        !          1626:                        break;
        !          1627:                    }
        !          1628:
        !          1629:                case SO_OVERFLOWED:
        !          1630:                        *mtod(m, int *) = so->so_rcv.sb_overflowed;
        !          1631:                        break;
        !          1632:
        !          1633:                default:
        !          1634:                        (void)m_free(m);
        !          1635:                        return (ENOPROTOOPT);
        !          1636:                }
        !          1637:                *mp = m;
        !          1638:                return (0);
        !          1639:        }
        !          1640: }
        !          1641:
        !          1642: void
        !          1643: sohasoutofband(struct socket *so)
        !          1644: {
        !          1645:        fownsignal(so->so_pgid, SIGURG, POLL_PRI, POLLPRI|POLLRDBAND, so);
        !          1646:        selwakeup(&so->so_rcv.sb_sel);
        !          1647: }
        !          1648:
        !          1649: static void
        !          1650: filt_sordetach(struct knote *kn)
        !          1651: {
        !          1652:        struct socket   *so;
        !          1653:
        !          1654:        so = (struct socket *)kn->kn_fp->f_data;
        !          1655:        SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext);
        !          1656:        if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist))
        !          1657:                so->so_rcv.sb_flags &= ~SB_KNOTE;
        !          1658: }
        !          1659:
        !          1660: /*ARGSUSED*/
        !          1661: static int
        !          1662: filt_soread(struct knote *kn, long hint)
        !          1663: {
        !          1664:        struct socket   *so;
        !          1665:
        !          1666:        so = (struct socket *)kn->kn_fp->f_data;
        !          1667:        kn->kn_data = so->so_rcv.sb_cc;
        !          1668:        if (so->so_state & SS_CANTRCVMORE) {
        !          1669:                kn->kn_flags |= EV_EOF;
        !          1670:                kn->kn_fflags = so->so_error;
        !          1671:                return (1);
        !          1672:        }
        !          1673:        if (so->so_error)       /* temporary udp error */
        !          1674:                return (1);
        !          1675:        if (kn->kn_sfflags & NOTE_LOWAT)
        !          1676:                return (kn->kn_data >= kn->kn_sdata);
        !          1677:        return (kn->kn_data >= so->so_rcv.sb_lowat);
        !          1678: }
        !          1679:
        !          1680: static void
        !          1681: filt_sowdetach(struct knote *kn)
        !          1682: {
        !          1683:        struct socket   *so;
        !          1684:
        !          1685:        so = (struct socket *)kn->kn_fp->f_data;
        !          1686:        SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext);
        !          1687:        if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist))
        !          1688:                so->so_snd.sb_flags &= ~SB_KNOTE;
        !          1689: }
        !          1690:
        !          1691: /*ARGSUSED*/
        !          1692: static int
        !          1693: filt_sowrite(struct knote *kn, long hint)
        !          1694: {
        !          1695:        struct socket   *so;
        !          1696:
        !          1697:        so = (struct socket *)kn->kn_fp->f_data;
        !          1698:        kn->kn_data = sbspace(&so->so_snd);
        !          1699:        if (so->so_state & SS_CANTSENDMORE) {
        !          1700:                kn->kn_flags |= EV_EOF;
        !          1701:                kn->kn_fflags = so->so_error;
        !          1702:                return (1);
        !          1703:        }
        !          1704:        if (so->so_error)       /* temporary udp error */
        !          1705:                return (1);
        !          1706:        if (((so->so_state & SS_ISCONNECTED) == 0) &&
        !          1707:            (so->so_proto->pr_flags & PR_CONNREQUIRED))
        !          1708:                return (0);
        !          1709:        if (kn->kn_sfflags & NOTE_LOWAT)
        !          1710:                return (kn->kn_data >= kn->kn_sdata);
        !          1711:        return (kn->kn_data >= so->so_snd.sb_lowat);
        !          1712: }
        !          1713:
        !          1714: /*ARGSUSED*/
        !          1715: static int
        !          1716: filt_solisten(struct knote *kn, long hint)
        !          1717: {
        !          1718:        struct socket   *so;
        !          1719:
        !          1720:        so = (struct socket *)kn->kn_fp->f_data;
        !          1721:
        !          1722:        /*
        !          1723:         * Set kn_data to number of incoming connections, not
        !          1724:         * counting partial (incomplete) connections.
        !          1725:         */
        !          1726:        kn->kn_data = so->so_qlen;
        !          1727:        return (kn->kn_data > 0);
        !          1728: }
        !          1729:
        !          1730: static const struct filterops solisten_filtops =
        !          1731:        { 1, NULL, filt_sordetach, filt_solisten };
        !          1732: static const struct filterops soread_filtops =
        !          1733:        { 1, NULL, filt_sordetach, filt_soread };
        !          1734: static const struct filterops sowrite_filtops =
        !          1735:        { 1, NULL, filt_sowdetach, filt_sowrite };
        !          1736:
        !          1737: int
        !          1738: soo_kqfilter(struct file *fp, struct knote *kn)
        !          1739: {
        !          1740:        struct socket   *so;
        !          1741:        struct sockbuf  *sb;
        !          1742:
        !          1743:        so = (struct socket *)kn->kn_fp->f_data;
        !          1744:        switch (kn->kn_filter) {
        !          1745:        case EVFILT_READ:
        !          1746:                if (so->so_options & SO_ACCEPTCONN)
        !          1747:                        kn->kn_fop = &solisten_filtops;
        !          1748:                else
        !          1749:                        kn->kn_fop = &soread_filtops;
        !          1750:                sb = &so->so_rcv;
        !          1751:                break;
        !          1752:        case EVFILT_WRITE:
        !          1753:                kn->kn_fop = &sowrite_filtops;
        !          1754:                sb = &so->so_snd;
        !          1755:                break;
        !          1756:        default:
        !          1757:                return (1);
        !          1758:        }
        !          1759:        SLIST_INSERT_HEAD(&sb->sb_sel.sel_klist, kn, kn_selnext);
        !          1760:        sb->sb_flags |= SB_KNOTE;
        !          1761:        return (0);
        !          1762: }
        !          1763:
        !          1764: #include <sys/sysctl.h>
        !          1765:
        !          1766: static int sysctl_kern_somaxkva(SYSCTLFN_PROTO);
        !          1767:
        !          1768: /*
        !          1769:  * sysctl helper routine for kern.somaxkva.  ensures that the given
        !          1770:  * value is not too small.
        !          1771:  * (XXX should we maybe make sure it's not too large as well?)
        !          1772:  */
        !          1773: static int
        !          1774: sysctl_kern_somaxkva(SYSCTLFN_ARGS)
        !          1775: {
        !          1776:        int error, new_somaxkva;
        !          1777:        struct sysctlnode node;
        !          1778:
        !          1779:        new_somaxkva = somaxkva;
        !          1780:        node = *rnode;
        !          1781:        node.sysctl_data = &new_somaxkva;
        !          1782:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
        !          1783:        if (error || newp == NULL)
        !          1784:                return (error);
        !          1785:
        !          1786:        if (new_somaxkva < (16 * 1024 * 1024)) /* sanity */
        !          1787:                return (EINVAL);
        !          1788:
        !          1789:        mutex_enter(&so_pendfree_lock);
        !          1790:        somaxkva = new_somaxkva;
        !          1791:        cv_broadcast(&socurkva_cv);
        !          1792:        mutex_exit(&so_pendfree_lock);
        !          1793:
        !          1794:        return (error);
        !          1795: }
        !          1796:
        !          1797: SYSCTL_SETUP(sysctl_kern_somaxkva_setup, "sysctl kern.somaxkva setup")
        !          1798: {
        !          1799:
        !          1800:        sysctl_createv(clog, 0, NULL, NULL,
        !          1801:                       CTLFLAG_PERMANENT,
        !          1802:                       CTLTYPE_NODE, "kern", NULL,
        !          1803:                       NULL, 0, NULL, 0,
        !          1804:                       CTL_KERN, CTL_EOL);
        !          1805:
        !          1806:        sysctl_createv(clog, 0, NULL, NULL,
        !          1807:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !          1808:                       CTLTYPE_INT, "somaxkva",
        !          1809:                       SYSCTL_DESCR("Maximum amount of kernel memory to be "
        !          1810:                                    "used for socket buffers"),
        !          1811:                       sysctl_kern_somaxkva, 0, NULL, 0,
        !          1812:                       CTL_KERN, KERN_SOMAXKVA, CTL_EOL);
        !          1813: }

CVSweb <webmaster@jp.NetBSD.org>