Annotation of XNU/bsd/net/ndrv.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
        !            23: /*
        !            24:  *     @(#)ndrv.c      1.1 (MacOSX) 6/10/43
        !            25:  * Justin Walker, 970604
        !            26:  *   AF_NDRV support
        !            27:  * 980130 - Cleanup, reorg, performance improvemements
        !            28:  */
        !            29: 
        !            30: /*
        !            31:  * PF_NDRV allows raw access to a specified network device, directly
        !            32:  *  with a socket.  Expected use involves a socket option to request
        !            33:  *  protocol packets.  This lets ndrv_output() call dlil_output(), and
        !            34:  *  lets DLIL find the proper recipient for incoming packets.
        !            35:  *  The purpose here is for user-mode protocol implementation.
        !            36:  * Note that "pure raw access" will still be accomplished with BPF.
        !            37:  *
        !            38:  * In addition to the former use, when combined with socket NKEs,
        !            39:  * PF_NDRV permits a fairly flexible mechanism for implementing
        !            40:  * strange protocol support.  One of the main ones will be the
        !            41:  * BlueBox/Classic Shared IP Address support.
        !            42:  *
        !            43:  * TODO: Add user access to protocol registration
        !            44:  */
        !            45: 
        !            46: #include <sys/param.h>
        !            47: #include <sys/systm.h>
        !            48: #include <sys/kernel.h>
        !            49: #include <sys/malloc.h>
        !            50: #include <sys/mbuf.h>
        !            51: #include <sys/protosw.h>
        !            52: #include <sys/domain.h>
        !            53: #include <sys/socket.h>
        !            54: #include <sys/socketvar.h>
        !            55: #include <sys/ioctl.h>
        !            56: #include <sys/errno.h>
        !            57: #include <sys/syslog.h>
        !            58: #include <sys/proc.h>
        !            59: 
        !            60: #include <kern/queue.h>
        !            61: 
        !            62: #include <net/if.h>
        !            63: #include <net/netisr.h>
        !            64: #include <net/route.h>
        !            65: #include <net/if_llc.h>
        !            66: #include <net/if_dl.h>
        !            67: #include <net/if_types.h>
        !            68: #include "if_blue.h"           /* TEMP!  Until BB gets in synch */
        !            69: #include "ndrv.h"
        !            70: 
        !            71: #if INET
        !            72: #include <netinet/in.h>
        !            73: #include <netinet/in_var.h>
        !            74: #endif
        !            75: #include <netinet/if_ether.h>
        !            76: 
        !            77: #if NS
        !            78: #include <netns/ns.h>
        !            79: #include <netns/ns_if.h>
        !            80: #endif
        !            81: 
        !            82: #if ISO
        !            83: #include <netiso/argo_debug.h>
        !            84: #include <netiso/iso.h>
        !            85: #include <netiso/iso_var.h>
        !            86: #include <netiso/iso_snpac.h>
        !            87: #endif
        !            88: 
        !            89: #if LLC
        !            90: #include <netccitt/dll.h>
        !            91: #include <netccitt/llc_var.h>
        !            92: #endif
        !            93: 
        !            94: #include <machine/spl.h>
        !            95: 
        !            96: int local_ndrv_attach(struct socket *, int);
        !            97: int local_ndrv_detach(struct ndrv_cb *);
        !            98: int local_ndrv_bind(struct socket *, struct sockaddr_ndrv *);
        !            99: int local_ndrv_disconnect(struct ndrv_cb *);
        !           100: 
        !           101: extern int splitter_ctl(struct socket *, int, caddr_t, struct ifnet *);
        !           102: 
        !           103: void local_ndrv_dinit(void);
        !           104: 
        !           105: unsigned long  ndrv_sendspace = NDRVSNDQ;
        !           106: unsigned long  ndrv_recvspace = NDRVRCVQ;
        !           107: struct ndrv_cb ndrvl;          /* Head of controlblock list */
        !           108: 
        !           109: #define BLUEQMAXLEN    50
        !           110: int blueqmaxlen = BLUEQMAXLEN; /* Default */
        !           111: 
        !           112: /* Domain init function for AF_NDRV - noop */
        !           113: void
        !           114: local_ndrv_dinit(void)
        !           115: {
        !           116: }
        !           117: 
        !           118: /*
        !           119:  * Protocol init function for NDRV protocol
        !           120:  * Init the control block list.
        !           121:  */
        !           122: void
        !           123: ndrv_init()
        !           124: {      ndrvl.nd_next = ndrvl.nd_prev = &ndrvl;
        !           125:        blueq.ifq_maxlen = blueqmaxlen;
        !           126: }
        !           127: 
        !           128: /*
        !           129:  * Protocol output - Called to output a raw network packet directly
        !           130:  *  to the driver.  If we're splitting, maybe loop it back.
        !           131:  */
        !           132: int
        !           133: ndrv_output(register struct mbuf *m,
        !           134:            register struct socket *so)
        !           135: {      register struct ndrv_cb *np = sotondrvcb(so);
        !           136:        register struct ifnet *ifp = np->nd_if;
        !           137:        int s, error;
        !           138:        extern struct ifnet_blue *blue_if;
        !           139:        extern void kprintf(const char *, ...);
        !           140:        extern int Filter_check(struct mbuf **);
        !           141: #define senderr(e) { error = (e); goto bad;}
        !           142: 
        !           143: #if NDRV_DEBUG
        !           144:        kprintf("NDRV output: %x, %x, %x\n", m, so, np);
        !           145: #endif
        !           146: 
        !           147:        /*
        !           148:         * No header is a format error
        !           149:         */
        !           150:        if ((m->m_flags&M_PKTHDR) == 0)
        !           151:                return(ENOBUFS); /* EINVAL??? */
        !           152: 
        !           153:        /* If we're splitting,  */
        !           154:        if (ifp->if_flags&IFF_SPLITTER) /* Splitter is turned on */
        !           155:        {       register struct mbuf *m0;
        !           156:                struct mbuf *m1;
        !           157:                register int rv;
        !           158:                extern struct mbuf *m_dup(struct mbuf *, int);
        !           159: #if 0
        !           160:                kprintf("NDRV_OUTPUT: m0 = %x\n", m0);
        !           161: #endif
        !           162:                
        !           163:                m1 = m;
        !           164:                rv = Filter_check(&m1);
        !           165:                m = m1;
        !           166:                /*
        !           167:                 * -1 => Not For MacOSX
        !           168:                 * 0 => For Both
        !           169:                 * 1 => For MacOSX
        !           170:                 */
        !           171:                if (rv >= 0)
        !           172:                {       register struct ether_header *eh;
        !           173: 
        !           174:                        if (rv == 0)
        !           175:                        {       if ((m0 = m_dup(m, M_WAIT)) == NULL)
        !           176:                                        ((struct ifnet_blue *)ifp->if_Y)->no_bufs2++;
        !           177:                        } else
        !           178:                        {       m0 = m;
        !           179:                                m = NULL;
        !           180:                        }
        !           181:                        /* Hack alert! */
        !           182:                        eh = mtod(m0, struct ether_header *);
        !           183:                        m0->m_data += sizeof(struct ether_header);
        !           184:                        m0->m_len -= sizeof (struct ether_header);
        !           185:                        m0->m_pkthdr.len -= sizeof(struct ether_header);
        !           186:                        m0->m_flags |= 0x80;
        !           187: #if NDRV_DEBUG
        !           188:                        kprintf("NDRV_OUTPUT: m0 = %x\n", m0);
        !           189: #endif
        !           190:                        new_ether_input(m0, eh, (struct ifnet *)blue_if, 0, 1);
        !           191:                        if (!m)
        !           192:                                return(0);
        !           193:                }
        !           194:        }
        !           195: 
        !           196:        /*
        !           197:         * Output to real device.
        !           198:         *
        !           199:         * Can't do multicast accounting because we don't know
        !           200:         *  (a) if our interface does multicast; and
        !           201:         *  (b) what a multicast address looks like
        !           202:         */
        !           203:        s = splimp();
        !           204: 
        !           205:        /*
        !           206:         * Can't call DLIL to do the job - we don't have a tag
        !           207:         *  and we aren't really a protocol
        !           208:         */
        !           209: 
        !           210:         (*ifp->if_output)(ifp, m);
        !           211:        splx(s);
        !           212:        ifp->if_obytes += m->m_len; /* MP alert! */
        !           213:        blue_if->pkts_out++;
        !           214:        return (0);
        !           215: bad:
        !           216:        if (m)
        !           217:                m_freem(m);
        !           218:        return (error);
        !           219: }
        !           220: 
        !           221: 
        !           222: 
        !           223: 
        !           224: 
        !           225: int ndrv_control(struct socket *so, u_long cmd, caddr_t data,
        !           226:                  struct ifnet *ifp, struct proc *p) 
        !           227: {
        !           228:                return (splitter_ctl(so, (int)cmd, data,
        !           229:                                     ifp));
        !           230: }
        !           231: 
        !           232: int ndrv_attach(struct socket *so, int proto,
        !           233:                    struct proc *p)
        !           234: {
        !           235: 
        !           236:        return local_ndrv_attach(so, proto);
        !           237: }
        !           238: 
        !           239: 
        !           240: 
        !           241: /*
        !           242:  * Destroy state just before socket deallocation.
        !           243:  * Flush data or not depending on the options.
        !           244:  */
        !           245: 
        !           246: int    ndrv_detach(struct socket *so) 
        !           247: {
        !           248:        register struct ndrv_cb *np = sotondrvcb(so);
        !           249: 
        !           250:        if (np == 0) 
        !           251:                return EINVAL;
        !           252:        return local_ndrv_detach(np);
        !           253: }
        !           254: 
        !           255: 
        !           256: /*
        !           257:  * If a socket isn't bound to a single address,
        !           258:  * the ndrv input routine will hand it anything
        !           259:  * within that protocol family (assuming there's
        !           260:  * nothing else around it should go to).
        !           261:  *
        !           262:  * Don't expect this to be used.
        !           263:  */
        !           264: 
        !           265: int ndrv_connect(struct socket *so, struct sockaddr *nam,
        !           266:                            struct proc *p)
        !           267: {
        !           268:        register struct ndrv_cb *np = sotondrvcb(so);
        !           269: 
        !           270:        if (np == 0) 
        !           271:                return EINVAL;
        !           272: 
        !           273:        if (np->nd_faddr) 
        !           274:                return EISCONN;
        !           275:        
        !           276:        bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, sizeof(struct sockaddr_ndrv));
        !           277:        soisconnected(so);
        !           278:        return 0;
        !           279: }
        !           280: 
        !           281: /*
        !           282:  * This is the "driver open" hook - we 'bind' to the
        !           283:  *  named driver.
        !           284:  */
        !           285: int    ndrv_bind(struct socket *so, struct sockaddr *nam,
        !           286:                  struct proc *p)
        !           287: {
        !           288:        register struct ndrv_cb *np = sotondrvcb(so);
        !           289: 
        !           290:        if (np == 0) 
        !           291:                return EINVAL;
        !           292: 
        !           293:        if (np->nd_laddr) 
        !           294:                return EINVAL;                  /* XXX */
        !           295: 
        !           296:        return local_ndrv_bind(so, (struct sockaddr_ndrv *) nam);
        !           297: }
        !           298: 
        !           299: 
        !           300: 
        !           301: 
        !           302: int    ndrv_disconnect(struct socket *so)
        !           303: {
        !           304:        register struct ndrv_cb *np = sotondrvcb(so);
        !           305: 
        !           306:        if (np == 0) 
        !           307:                return EINVAL;
        !           308: 
        !           309:        if (np->nd_faddr == 0)
        !           310:                return ENOTCONN;
        !           311: 
        !           312:        local_ndrv_disconnect(np);
        !           313:        soisdisconnected(so);
        !           314:        return 0;
        !           315: }
        !           316: 
        !           317: /*
        !           318:  * Mark the connection as being incapable of further input.
        !           319:  */
        !           320: int    ndrv_shutdown(struct socket *so)
        !           321: {
        !           322:        socantsendmore(so);
        !           323:        return 0;
        !           324: }
        !           325: 
        !           326: /*
        !           327:  * Ship a packet out.  The ndrv output will pass it
        !           328:  *  to the appropriate driver.  The really tricky part
        !           329:  *  is the destination address...
        !           330:  */
        !           331: int    ndrv_send(struct socket *so, int flags, struct mbuf *m, 
        !           332:                  struct sockaddr *addr, struct mbuf *control,
        !           333:                  struct proc *p)
        !           334: {
        !           335:        int error;
        !           336: 
        !           337:        if (control) 
        !           338:                return EOPNOTSUPP;
        !           339: 
        !           340:        error = ndrv_output(m, so);
        !           341:        m = NULL;
        !           342:        return error;
        !           343: }
        !           344: 
        !           345: 
        !           346: int    ndrv_abort(struct socket *so)
        !           347: {
        !           348:        register struct ndrv_cb *np = sotondrvcb(so);
        !           349: 
        !           350:        if (np == 0) 
        !           351:                return EINVAL;
        !           352: 
        !           353:        local_ndrv_disconnect(np);
        !           354:        sofree(so);
        !           355:        soisdisconnected(so);
        !           356:        return 0;
        !           357: }
        !           358: 
        !           359: int    ndrv_sense(struct socket *so, struct stat *sb)
        !           360: {
        !           361:        /*
        !           362:         * stat: don't bother with a blocksize.
        !           363:         */
        !           364:        return (0);
        !           365: }
        !           366: 
        !           367: int    ndrv_sockaddr(struct socket *so, 
        !           368:                       struct sockaddr **nam)
        !           369: {
        !           370:        register struct ndrv_cb *np = sotondrvcb(so);
        !           371:        int len;
        !           372: 
        !           373:        if (np == 0) 
        !           374:                return EINVAL;
        !           375: 
        !           376:        if (np->nd_laddr == 0) 
        !           377:                return EINVAL;
        !           378: 
        !           379:        len = np->nd_laddr->snd_len;
        !           380:        bcopy((caddr_t)np->nd_laddr, *nam,
        !           381:              (unsigned)len);
        !           382:        return 0;
        !           383: }
        !           384: 
        !           385: 
        !           386: int    ndrv_peeraddr(struct socket *so, 
        !           387:                       struct sockaddr **nam)
        !           388: {
        !           389:        register struct ndrv_cb *np = sotondrvcb(so);
        !           390:        int len;
        !           391: 
        !           392:        if (np == 0) 
        !           393:                return EINVAL;
        !           394: 
        !           395:        if (np->nd_faddr == 0) 
        !           396:                return ENOTCONN;
        !           397: 
        !           398:        len = np->nd_faddr->snd_len;
        !           399:        bcopy((caddr_t)np->nd_faddr, *nam,
        !           400:              (unsigned)len);
        !           401:        return 0;
        !           402: }
        !           403: 
        !           404: 
        !           405: /* Control input */
        !           406: 
        !           407: void   ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
        !           408: 
        !           409: {
        !           410: }
        !           411: 
        !           412: /* Control output */
        !           413: 
        !           414: int    ndrv_ctloutput(struct socket *dummy1, struct sockopt *dummy2)
        !           415: {
        !           416:        return(0);
        !           417: }
        !           418: 
        !           419: /* Drain the queues */
        !           420: void
        !           421: ndrv_drain()
        !           422: {
        !           423: }
        !           424: 
        !           425: /* Sysctl hook for NDRV */
        !           426: int
        !           427: ndrv_sysctl()
        !           428: {
        !           429:        return(0);
        !           430: }
        !           431: 
        !           432: /*
        !           433:  * Allocate an ndrv control block and some buffer space for the socket
        !           434:  */
        !           435: int
        !           436: local_ndrv_attach(register struct socket *so,
        !           437:            register int proto)
        !           438: {      int error;
        !           439:        register struct ndrv_cb *np = sotondrvcb(so);
        !           440: 
        !           441:        if ((so->so_state & SS_PRIV) == 0)
        !           442:                return(EPERM);
        !           443: 
        !           444: #if NDRV_DEBUG
        !           445:        kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
        !           446: #endif
        !           447:        MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
        !           448: #if NDRV_DEBUG
        !           449:        kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
        !           450: #endif
        !           451:        if ((so->so_pcb = (caddr_t)np))
        !           452:                bzero(np, sizeof(*np));
        !           453:        else
        !           454:                return(ENOBUFS);
        !           455:        if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
        !           456:                return(error);
        !           457:        np->nd_signature = NDRV_SIGNATURE;
        !           458:        np->nd_socket = so;
        !           459:        np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
        !           460:        np->nd_proto.sp_protocol = proto;
        !           461:        insque((queue_t)np, (queue_t)&ndrvl);
        !           462: //##### eeccckkk added here to get the kext filter "attached"... TEMP 
        !           463: //     sfilter_init(so);
        !           464:        return(0);
        !           465: }
        !           466: 
        !           467: int
        !           468: local_ndrv_detach(register struct ndrv_cb *np)
        !           469: {      register struct socket *so = np->nd_socket;
        !           470:        extern struct ifnet_blue *blue_if;
        !           471:        extern void splitter_close(struct ndrv_cb *);
        !           472: 
        !           473: #if NDRV_DEBUG
        !           474:        kprintf("NDRV detach: %x, %x\n", so, np);
        !           475: #endif
        !           476:        if (blue_if)
        !           477:                splitter_close(np); /* 'np' is freed within */
        !           478:        so->so_pcb = 0;
        !           479:        sofree(so);
        !           480:        return(0);
        !           481: }
        !           482: 
        !           483: int
        !           484: local_ndrv_disconnect(register struct ndrv_cb *np)
        !           485: {
        !           486: #if NDRV_DEBUG
        !           487:        kprintf("NDRV disconnect: %x\n", np);
        !           488: #endif
        !           489:        if (np->nd_faddr)
        !           490:        {       m_freem(dtom(np->nd_faddr));
        !           491:                np->nd_faddr = 0;
        !           492:        }
        !           493:        if (np->nd_socket->so_state & SS_NOFDREF)
        !           494:                local_ndrv_detach(np);
        !           495:        return(0);
        !           496: }
        !           497: 
        !           498: /*
        !           499:  * Here's where we latch onto the driver and make it ours.
        !           500:  */
        !           501: int
        !           502: local_ndrv_bind(register struct socket *so,
        !           503:          register struct sockaddr_ndrv *sa)
        !           504: {      register char *dname;
        !           505:        register struct ndrv_cb *np;
        !           506:        register struct ifnet *ifp;
        !           507:        extern int name_cmp(struct ifnet *, char *);
        !           508: 
        !           509:        if TAILQ_EMPTY(&ifnet)
        !           510:                return(EADDRNOTAVAIL); /* Quick sanity check */
        !           511:        np = sotondrvcb(so);
        !           512: 
        !           513:        /* I think we just latch onto a copy here; the caller frees */
        !           514: 
        !           515:        
        !           516:        np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
        !           517:        bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
        !           518:        dname = sa->snd_name;
        !           519:        if (dname == NULL)
        !           520:                return(EINVAL);
        !           521: #if NDRV_DEBUG
        !           522:        kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
        !           523: #endif
        !           524:        /* Track down the driver and its ifnet structure.
        !           525:         * There's no internal call for this so we have to dup the code
        !           526:         *  in if.c/ifconf()
        !           527:         */
        !           528:        TAILQ_FOREACH(ifp, &ifnet, if_link) {
        !           529:                if (name_cmp(ifp, dname) == 0)
        !           530:                        break;
        !           531:        }
        !           532: 
        !           533:        if (ifp == NULL)
        !           534:                return(EADDRNOTAVAIL);
        !           535:        /*
        !           536:         * Now, at this point, we should force open the driver and somehow
        !           537:         *  register ourselves to receive packets (a la the bpf).
        !           538:         * However, we have this groaty hack in place that makes it
        !           539:         *  not necessary for blue box purposes (the 'splitter' trick).
        !           540:         * If we want this to be a full-fledged AF, we have to force the
        !           541:         *  open and implement a filter mechanism.
        !           542:         */
        !           543:        np->nd_if = ifp;
        !           544:        return(0);
        !           545: }
        !           546: 
        !           547: /*
        !           548:  * Try to compare a device name (q) with one of the funky ifnet
        !           549:  *  device names (ifp).
        !           550:  */
        !           551: int name_cmp(register struct ifnet *ifp, register char *q)
        !           552: {      register char *r;
        !           553:        register int len;
        !           554:        char buf[IFNAMSIZ];
        !           555:        static char *sprint_d();
        !           556: 
        !           557:        r = buf;
        !           558:        len = strlen(ifp->if_name);
        !           559:        strncpy(r, ifp->if_name, IFNAMSIZ);
        !           560:        r += len;
        !           561:        (void)sprint_d(ifp->if_unit, r, r-buf);
        !           562: #if NDRV_DEBUG
        !           563:        kprintf("Comparing %s, %s\n", buf, q);
        !           564: #endif
        !           565:        return(strncmp(buf, q, IFNAMSIZ));
        !           566: }
        !           567: 
        !           568: /* Hackery - return a string version of a decimal number */
        !           569: static char *
        !           570: sprint_d(n, buf, buflen)
        !           571:         u_int n;
        !           572:         char *buf;
        !           573:         int buflen;
        !           574: {
        !           575:         register char *cp = buf + buflen - 1;
        !           576: 
        !           577:         *cp = 0;
        !           578:         do {
        !           579:                 cp--;
        !           580:                 *cp = "0123456789"[n % 10];
        !           581:                 n /= 10;
        !           582:         } while (n != 0);
        !           583:         return (cp);
        !           584: }
        !           585: 
        !           586: /*
        !           587:  * When closing, dump any enqueued mbufs.
        !           588:  */
        !           589: void
        !           590: ndrv_flushq(register struct ifqueue *q)
        !           591: {      register struct mbuf *m;
        !           592:        register int s;
        !           593:        for (;;)
        !           594:        {       s = splimp();
        !           595:                IF_DEQUEUE(q, m);
        !           596:                if (m == NULL)
        !           597:                        break;
        !           598:                IF_DROP(q);
        !           599:                splx(s);
        !           600:                if (m)
        !           601:                        m_freem(m);
        !           602:        }
        !           603:        splx(s);
        !           604: }
        !           605: 
        !           606: 
        !           607: struct pr_usrreqs ndrv_usrreqs = {
        !           608:        ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
        !           609:        ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach,
        !           610:        ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
        !           611:        pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown,
        !           612:        ndrv_sockaddr, sosend, soreceive, sopoll
        !           613: };
        !           614: 
        !           615: struct domain ndrvdomain;
        !           616: 
        !           617: struct protosw ndrvsw[] =
        !           618: {      {       SOCK_RAW, &ndrvdomain, 0, PR_ATOMIC|PR_ADDR,
        !           619:                0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
        !           620:                0, ndrv_init, 0, 0,
        !           621:                ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
        !           622:        }
        !           623: };
        !           624: 
        !           625: 
        !           626: struct domain ndrvdomain =
        !           627: {      AF_NDRV, "NetDriver", NULL, NULL, NULL,
        !           628:        ndrvsw,
        !           629:        NULL, NULL, 0, 0, 0, 0
        !           630: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.