Annotation of 43BSDTahoe/sys/netimp/if_imp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted
        !             6:  * provided that the above copyright notice and this paragraph are
        !             7:  * duplicated in all such forms and that any documentation,
        !             8:  * advertising materials, and other materials related to such
        !             9:  * distribution and use acknowledge that the software was developed
        !            10:  * by the University of California, Berkeley.  The name of the
        !            11:  * University may not be used to endorse or promote products derived
        !            12:  * from this software without specific prior written permission.
        !            13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            15:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            16:  *
        !            17:  *     @(#)if_imp.c    7.8 (Berkeley) 6/29/88
        !            18:  */
        !            19: 
        !            20: #include "imp.h"
        !            21: #if NIMP > 0
        !            22: /*
        !            23:  * ARPANET IMP (PSN) interface driver.
        !            24:  *
        !            25:  * The IMP-host protocol (AHIP) is handled here, leaving
        !            26:  * hardware specifics to the lower level interface driver.
        !            27:  */
        !            28: #include "param.h"
        !            29: #include "systm.h"
        !            30: #include "mbuf.h"
        !            31: #include "buf.h"
        !            32: #include "protosw.h"
        !            33: #include "socket.h"
        !            34: #include "time.h"
        !            35: #include "kernel.h"
        !            36: #include "errno.h"
        !            37: #include "ioctl.h"
        !            38: #include "syslog.h"
        !            39: 
        !            40: #include "../machine/mtpr.h"
        !            41: 
        !            42: #include "../net/if.h"
        !            43: #include "../net/netisr.h"
        !            44: #include "../netinet/in.h"
        !            45: #include "../netinet/in_systm.h"
        !            46: #include "../netinet/in_var.h"
        !            47: #include "../netinet/ip.h"
        !            48: #include "../netinet/ip_var.h"
        !            49: #define IMPMESSAGES
        !            50: /* define IMPLEADERS here to get leader printing code */
        !            51: #include "if_imp.h"
        !            52: #include "if_imphost.h"
        !            53: 
        !            54: struct imp_softc imp_softc[NIMP];
        !            55: #ifndef lint
        !            56: int    nimp = NIMP;                    /* for netstat */
        !            57: #endif
        !            58: struct ifqueue impintrq;
        !            59: int    impqmaxlen = IFQ_MAXLEN;
        !            60: int    imphqlen = 12 + IMP_MAXHOSTMSG; /* max packets to queue per host */
        !            61: 
        !            62: int    imppri = LOG_ERR;
        !            63: #ifdef IMPLEADERS
        !            64: int    impprintfs = 0;
        !            65: #endif
        !            66: #ifdef IMPINIT
        !            67: int    imptraceinit = 0;
        !            68: #endif
        !            69: 
        !            70: 
        !            71: #define HOSTDEADTIMER  (30 * PR_SLOWHZ)        /* How long to wait when down */
        !            72: 
        !            73: int    impdown(), impinit(), impioctl(), impoutput(), imptimo();
        !            74: 
        !            75: /*
        !            76:  * IMP attach routine.  Called from hardware device attach routine
        !            77:  * at configuration time with a pointer to the device structure.
        !            78:  * Sets up local state and returns pointer to base of ifnet+impcb
        !            79:  * structures.  This is then used by the device's attach routine
        !            80:  * set up its back pointers. 
        !            81:  */
        !            82: struct imp_softc *
        !            83: impattach(hwname, hwunit, reset)
        !            84:        char *hwname;
        !            85:        int hwunit;
        !            86:        int (*reset)();
        !            87: {
        !            88:        struct imp_softc *sc;
        !            89:        register struct ifnet *ifp;
        !            90:        static int impunit;
        !            91: 
        !            92: #ifdef lint
        !            93:        impintr();
        !            94: #endif
        !            95:        if (impunit >= NIMP) {
        !            96:                printf("imp%d: not configured\n", impunit++);
        !            97:                return (0);
        !            98:        }
        !            99:        sc = &imp_softc[impunit];
        !           100:        ifp = &sc->imp_if;
        !           101:        sc->imp_cb.ic_hwname = hwname;
        !           102:        sc->imp_cb.ic_hwunit = hwunit;
        !           103:        ifp->if_unit = impunit;
        !           104:        ifp->if_name = "imp";
        !           105:        ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
        !           106:        ifp->if_reset = reset;
        !           107:        ifp->if_init = impinit;
        !           108:        ifp->if_ioctl = impioctl;
        !           109:        ifp->if_output = impoutput;
        !           110:        ifp->if_watchdog = imptimo;
        !           111:        if_attach(ifp);
        !           112:        impunit++;
        !           113:        return (sc);
        !           114: }
        !           115: 
        !           116: /*
        !           117:  * IMP initialization routine: call hardware module to
        !           118:  * setup resources, init state and get ready for
        !           119:  * NOOPs the IMP should send us, and that we want to drop.
        !           120:  */
        !           121: impinit(unit)
        !           122:        int unit;
        !           123: {
        !           124:        int s;
        !           125:        register struct imp_softc *sc = &imp_softc[unit];
        !           126: 
        !           127:        if (sc->imp_if.if_addrlist == 0)
        !           128:                return;
        !           129:        s = splimp();
        !           130: #ifdef IMPINIT
        !           131:        if (imptraceinit)
        !           132:                log(imppri, "impinit\n");
        !           133: #endif
        !           134:        sc->imp_state = IMPS_WINIT;
        !           135:        if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0)
        !           136:                sc->imp_if.if_flags &= ~IFF_UP;
        !           137:        impintrq.ifq_maxlen = impqmaxlen;
        !           138:        splx(s);
        !           139: }
        !           140: 
        !           141: /*
        !           142:  * ARPAnet 1822/AHIP input routine.
        !           143:  * Called from hardware input interrupt routine to handle 1822
        !           144:  * IMP-host messages.  Data messages are passed to higher-level
        !           145:  * protocol processors on the basis of link number.
        !           146:  * Other type messages (control) are handled here.
        !           147:  */
        !           148: impinput(unit, m)
        !           149:        int unit;
        !           150:        register struct mbuf *m;
        !           151: {
        !           152:        register struct control_leader *cp;
        !           153: #define        ip      ((struct imp_leader *)cp)
        !           154:        register struct imp_softc *sc = &imp_softc[unit];
        !           155:        struct ifnet *ifp;
        !           156:        register struct host *hp;
        !           157:        register struct ifqueue *inq;
        !           158:        struct sockaddr_in *sin;
        !           159:        int s;
        !           160: 
        !           161:        /*
        !           162:         * Pull the interface pointer out of the mbuf
        !           163:         * and save for later; adjust mbuf to look at rest of data.
        !           164:         */
        !           165:        ifp = *(mtod(m, struct ifnet **));
        !           166:        IF_ADJ(m);
        !           167:        /* verify leader length. */
        !           168:        if (m->m_len < sizeof(struct control_leader) &&
        !           169:            (m = m_pullup(m, sizeof(struct control_leader))) == 0)
        !           170:                return;
        !           171:        cp = mtod(m, struct control_leader *);
        !           172:        if (cp->dl_mtype == IMPTYPE_DATA &&
        !           173:            m->m_len < sizeof(struct imp_leader)) {
        !           174:                if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0)
        !           175:                        return;
        !           176:                cp = mtod(m, struct control_leader *);
        !           177:        }
        !           178: #ifdef IMPLEADERS
        !           179:        if (impprintfs)
        !           180:                printleader("impinput", ip);
        !           181: #endif
        !           182:        inq = &impintrq;
        !           183: 
        !           184:        /* check leader type */
        !           185:        if (cp->dl_format != IMP_NFF) {
        !           186:                /*
        !           187:                 * We get 1822L NOOPs and RESET
        !           188:                 * at initialization.
        !           189:                 */
        !           190: #ifdef IMPINIT
        !           191:                if (imptraceinit)
        !           192:                        log(imppri, "input, format %x mtype %d\n",
        !           193:                            cp->dl_format, cp->dl_mtype);
        !           194: #endif
        !           195:                if (cp->dl_format != IMP_1822L_I2H ||
        !           196:                    (cp->dl_mtype != IMPTYPE_NOOP &&
        !           197:                    cp->dl_mtype != IMPTYPE_RESET)) {
        !           198:                        sc->imp_garbage++;
        !           199:                        sc->imp_if.if_collisions++;     /* XXX */
        !           200:                }
        !           201:        } else switch (cp->dl_mtype) {
        !           202: 
        !           203:        case IMPTYPE_DATA:
        !           204:                /*
        !           205:                 * Data for a protocol.  Dispatch to the appropriate
        !           206:                 * protocol routine (running at software interrupt).
        !           207:                 * If this isn't a raw interface, advance pointer
        !           208:                 * into mbuf past leader.
        !           209:                 */
        !           210:                switch (cp->dl_link) {
        !           211: 
        !           212:                case IMPLINK_IP:
        !           213:                        m->m_len -= sizeof(struct imp_leader);
        !           214:                        m->m_off += sizeof(struct imp_leader);
        !           215:                        schednetisr(NETISR_IP);
        !           216:                        inq = &ipintrq;
        !           217:                        break;
        !           218: 
        !           219:                default:
        !           220:                        break;
        !           221:                }
        !           222:                break;
        !           223: 
        !           224:        /*
        !           225:         * IMP leader error.  Reset the IMP and discard the packet.
        !           226:         */
        !           227:        case IMPTYPE_BADLEADER:
        !           228:                /*
        !           229:                 * According to 1822 document, this message
        !           230:                 * will be generated in response to the
        !           231:                 * first noop sent to the IMP after
        !           232:                 * the host resets the IMP interface.
        !           233:                 */
        !           234: #ifdef IMPINIT
        !           235:                if (imptraceinit)
        !           236:                        log(imppri, "badleader\n");
        !           237: #endif
        !           238:                if (sc->imp_state != IMPS_INIT) {
        !           239:                        impmsg(sc, "leader error");
        !           240:                        sc->imp_msgready = 0;
        !           241:                        hostreset(unit);
        !           242:                        impnoops(sc);
        !           243:                        sc->imp_garbage++;
        !           244:                }
        !           245:                break;
        !           246: 
        !           247:        /*
        !           248:         * IMP going down.  Print message, and if not immediate,
        !           249:         * set off a timer to insure things will be reset at the
        !           250:         * appropriate time.
        !           251:         */
        !           252:        case IMPTYPE_DOWN:
        !           253:            {   int type, when;
        !           254: 
        !           255:                type = cp->dl_link & IMP_DMASK;
        !           256:                when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT;
        !           257: #ifdef IMPINIT
        !           258:                if (imptraceinit)
        !           259:                        log(imppri, "input DOWN %s %d\n",
        !           260:                            impmessage[type], when * IMPDOWN_WHENUNIT);
        !           261: #endif
        !           262:                if (type != IMPDOWN_GOING && when)
        !           263:                        impmsg(sc, "going down %s in %d minutes",
        !           264:                            (u_int)impmessage[type], when * IMPDOWN_WHENUNIT);
        !           265:                else
        !           266:                        impmsg(sc, "going down %s", (u_int)impmessage[type]);
        !           267:                if (sc->imp_state != IMPS_UP)
        !           268:                        break;
        !           269:                if (type == IMPDOWN_GOING) {
        !           270:                        sc->imp_state = IMPS_GOINGDOWN;
        !           271:                        timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz);
        !           272:                } else if (when == 0)
        !           273:                        sc->imp_state = IMPS_WINIT;
        !           274:                sc->imp_dropcnt = 0;
        !           275:                break;
        !           276:            }
        !           277: 
        !           278:        /*
        !           279:         * A NOP, usually seen during the initialization sequence.
        !           280:         * Compare the local address with that in the message.
        !           281:         * Reset the local address notion if it doesn't match.
        !           282:         */
        !           283:        case IMPTYPE_NOOP:
        !           284: #ifdef IMPINIT
        !           285:                if (imptraceinit)
        !           286:                        log(imppri, "noop\n");
        !           287: #endif
        !           288:                if (sc->imp_state == IMPS_WINIT) {
        !           289:                        sc->imp_dropcnt = 0;
        !           290:                        impnoops(sc);
        !           291:                        sc->imp_state = IMPS_INIT;
        !           292:                }
        !           293:                sc->imp_dropcnt++;
        !           294:                if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) {
        !           295:                        struct in_addr leader_addr;
        !           296: 
        !           297:                        sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
        !           298:                        imp_leader_to_addr(&leader_addr, cp, &sc->imp_if);
        !           299:                        if (sin->sin_addr.s_addr != leader_addr.s_addr) {
        !           300:                                impmsg(sc, "address reset to x%x (%d/%d)",
        !           301:                                        ntohl(leader_addr.s_addr),
        !           302:                                        (u_int)cp->dl_host,
        !           303:                                        ntohs(cp->dl_imp));
        !           304:                                sin->sin_addr.s_addr = leader_addr.s_addr;
        !           305:                        }
        !           306:                }
        !           307:                break;
        !           308: 
        !           309:        /*
        !           310:         * RFNM or INCOMPLETE message, decrement rfnm count
        !           311:         * and prepare to send next message.
        !           312:         * If the rfnm allows another queued
        !           313:         * message to be sent, bump msgready
        !           314:         * and start IMP if idle.
        !           315:         * We could pass incomplete's up to the next level,
        !           316:         * but this currently isn't needed.
        !           317:         * Pass "bad" incompletes and rfnms to the raw socket.
        !           318:         */
        !           319:        case IMPTYPE_INCOMPLETE:
        !           320:                sc->imp_incomplete++;
        !           321:                /* FALL THROUGH */
        !           322:        case IMPTYPE_RFNM:
        !           323:                if ((hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host,
        !           324:                    unit)) == 0 || hp->h_rfnm == 0) {
        !           325:                        sc->imp_badrfnm++;
        !           326:                        if (hp)
        !           327:                                hostfree(hp);
        !           328:                        break;
        !           329:                }
        !           330:                imprestarthost(sc, hp);
        !           331:                if (cp->dl_mtype == IMPTYPE_RFNM)
        !           332:                        goto drop;
        !           333:                break;
        !           334: 
        !           335:        /*
        !           336:         * Host or IMP can't be reached.  Flush any packets
        !           337:         * awaiting transmission and release the host structure.
        !           338:         * Enqueue for notifying protocols at software interrupt time.
        !           339:         */
        !           340:        case IMPTYPE_HOSTDEAD:
        !           341:        case IMPTYPE_HOSTUNREACH:
        !           342:                if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) {
        !           343:                        hp->h_flags |= (1 << (int)cp->dl_mtype);
        !           344:                        sc->imp_msgready -=
        !           345:                           MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
        !           346:                        hp->h_rfnm = 0;
        !           347:                        hostflush(hp);
        !           348:                        hp->h_timer = HOSTDEADTIMER;
        !           349:                }
        !           350:                break;
        !           351: 
        !           352:        /*
        !           353:         * Error in data.  Clear RFNM status for this host and send
        !           354:         * noops to the IMP to clear the interface.
        !           355:         */
        !           356:        case IMPTYPE_BADDATA:
        !           357:                impmsg(sc, "data error");
        !           358:                if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) {
        !           359:                        sc->imp_msgready -=
        !           360:                           MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
        !           361:                        if (hp->h_rfnm)
        !           362:                                hostrelease(hp);
        !           363:                        else
        !           364:                                hostfree(hp);
        !           365:                }
        !           366:                impnoops(sc);
        !           367:                break;
        !           368: 
        !           369:        /*
        !           370:         * Interface reset.
        !           371:         */
        !           372:        case IMPTYPE_RESET:
        !           373: #ifdef IMPINIT
        !           374:                if (imptraceinit)
        !           375:                        log(imppri, "reset complete\n");
        !           376: #endif
        !           377:                if (sc->imp_state != IMPS_INIT) {
        !           378:                        impmsg(sc, "interface reset");
        !           379:                        impnoops(sc);
        !           380:                }
        !           381:                /* clear RFNM counts */
        !           382:                sc->imp_msgready = 0;
        !           383:                hostreset(unit);
        !           384:                if (sc->imp_state != IMPS_DOWN) {
        !           385:                        sc->imp_state = IMPS_UP;
        !           386:                        sc->imp_if.if_flags |= IFF_UP;
        !           387: #ifdef IMPINIT
        !           388:                        if (imptraceinit)
        !           389:                                log(imppri, "IMP UP\n");
        !           390: #endif
        !           391:                }
        !           392:                break;
        !           393: 
        !           394:        default:
        !           395:                sc->imp_garbage++;
        !           396:                sc->imp_if.if_collisions++;             /* XXX */
        !           397:                break;
        !           398:        }
        !           399: 
        !           400:        if (inq == &impintrq)
        !           401:                schednetisr(NETISR_IMP);
        !           402:        /*
        !           403:         * Re-insert interface pointer in the mbuf chain
        !           404:         * for the next protocol up.
        !           405:         */
        !           406:        if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) {
        !           407:                struct mbuf *n;
        !           408: 
        !           409:                MGET(n, M_DONTWAIT, MT_HEADER);
        !           410:                if (n == 0)
        !           411:                        goto drop;
        !           412:                n->m_next = m;
        !           413:                m = n;
        !           414:                m->m_len = 0;
        !           415:                m->m_off = MMINOFF + sizeof(struct ifnet  *);
        !           416:        }
        !           417:        m->m_off -= sizeof(struct ifnet *);
        !           418:        m->m_len += sizeof(struct ifnet *);
        !           419:        *(mtod(m, struct ifnet **)) = ifp;
        !           420: 
        !           421:        s = splimp();
        !           422:        if (!IF_QFULL(inq)) {
        !           423:                IF_ENQUEUE(inq, m);
        !           424:                splx(s);
        !           425:                return;
        !           426:        }
        !           427:        splx(s);
        !           428:        IF_DROP(inq);
        !           429: drop:
        !           430:        m_freem(m);
        !           431: #undef ip
        !           432: }
        !           433: 
        !           434: /*
        !           435:  * Bring the IMP down after notification.
        !           436:  */
        !           437: impdown(sc)
        !           438:        struct imp_softc *sc;
        !           439: {
        !           440:        int s = splimp();
        !           441: 
        !           442:        if (sc->imp_state == IMPS_GOINGDOWN) {
        !           443:                sc->imp_state = IMPS_WINIT;
        !           444:                impmsg(sc, "marked down");
        !           445:                sc->imp_msgready = 0;
        !           446:                hostreset(sc->imp_if.if_unit);
        !           447:                if_down(&sc->imp_if);
        !           448:        }
        !           449: #ifdef IMPINIT
        !           450:        else if (imptraceinit)
        !           451:                log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state);
        !           452: #endif
        !           453:        splx(s);
        !           454: }
        !           455: 
        !           456: /*VARARGS2*/
        !           457: impmsg(sc, fmt, a1)
        !           458:        struct imp_softc *sc;
        !           459:        char *fmt;
        !           460:        u_int a1;
        !           461: {
        !           462: 
        !           463:        log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1);
        !           464: }
        !           465: 
        !           466: struct sockproto impproto = { PF_IMPLINK };
        !           467: struct sockaddr_in impdst = { AF_IMPLINK };
        !           468: struct sockaddr_in impsrc = { AF_IMPLINK };
        !           469: 
        !           470: /*
        !           471:  * Pick up the IMP "error" messages enqueued earlier,
        !           472:  * passing these up to the higher level protocol
        !           473:  * and the raw interface.
        !           474:  */
        !           475: impintr()
        !           476: {
        !           477:        register struct mbuf *m;
        !           478:        register struct control_leader *cp;
        !           479:        struct ifnet *ifp;
        !           480:        int s;
        !           481: 
        !           482:        for (;;) {
        !           483:                s = splimp();
        !           484:                IF_DEQUEUEIF(&impintrq, m, ifp);
        !           485:                splx(s);
        !           486:                if (m == 0)
        !           487:                        return;
        !           488: 
        !           489:                cp = mtod(m, struct control_leader *);
        !           490:                imp_leader_to_addr(&impsrc.sin_addr, cp, ifp);
        !           491:                impproto.sp_protocol = cp->dl_link;
        !           492:                impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
        !           493: 
        !           494:                if (cp->dl_mtype == IMPTYPE_HOSTDEAD ||
        !           495:                    cp->dl_mtype == IMPTYPE_HOSTUNREACH)
        !           496:                        switch (cp->dl_link) {
        !           497: 
        !           498:                        case IMPLINK_IP:
        !           499:                                pfctlinput((int)cp->dl_mtype,
        !           500:                                    (struct sockaddr *)&impsrc);
        !           501:                                break;
        !           502:                        default:
        !           503:                                raw_ctlinput((int)cp->dl_mtype,
        !           504:                                    (struct sockaddr *)&impsrc);
        !           505:                                break;
        !           506:                        }
        !           507: 
        !           508:                raw_input(m, &impproto, (struct sockaddr *)&impsrc,
        !           509:                  (struct sockaddr *)&impdst);
        !           510:        }
        !           511: }
        !           512: 
        !           513: /*
        !           514:  * ARPAnet 1822 output routine.
        !           515:  * Called from higher level protocol routines to set up messages for
        !           516:  * transmission to the imp.  Sets up the header and calls impsnd to
        !           517:  * enqueue the message for this IMP's hardware driver.
        !           518:  */
        !           519: impoutput(ifp, m0, dst)
        !           520:        register struct ifnet *ifp;
        !           521:        struct mbuf *m0;
        !           522:        struct sockaddr *dst;
        !           523: {
        !           524:        register struct imp_leader *imp;
        !           525:        register struct mbuf *m = m0;
        !           526:        caddr_t pkt = mtod(m, caddr_t);
        !           527:        int error = 0;
        !           528: 
        !           529:        /*
        !           530:         * Don't even try if the IMP is unavailable.
        !           531:         */
        !           532:        if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) {
        !           533:                error = ENETDOWN;
        !           534:                goto drop;
        !           535:        }
        !           536: 
        !           537:        /*
        !           538:         * If AF_IMPLINK, leader exists; just send.
        !           539:         * Otherwise, construct leader according to address family.
        !           540:         */
        !           541:        if (dst->sa_family != AF_IMPLINK) {
        !           542:                /*
        !           543:                 * Add IMP leader.  If there's not enough space in the
        !           544:                 * first mbuf, allocate another.  If that should fail, we
        !           545:                 * drop this sucker.
        !           546:                 */
        !           547:                if (m->m_off > MMAXOFF ||
        !           548:                    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
        !           549:                        MGET(m, M_DONTWAIT, MT_HEADER);
        !           550:                        if (m == 0) {
        !           551:                                error = ENOBUFS;
        !           552:                                goto drop;
        !           553:                        }
        !           554:                        m->m_next = m0;
        !           555:                        m->m_len = sizeof(struct imp_leader);
        !           556:                } else {
        !           557:                        m->m_off -= sizeof(struct imp_leader);
        !           558:                        m->m_len += sizeof(struct imp_leader);
        !           559:                }
        !           560:                imp = mtod(m, struct imp_leader *);
        !           561:                imp->il_format = IMP_NFF;
        !           562:                imp->il_mtype = IMPTYPE_DATA;
        !           563:                imp->il_flags = 0;
        !           564:                imp->il_htype = 0;
        !           565:                imp->il_subtype = 0;
        !           566: 
        !           567:                switch (dst->sa_family) {
        !           568: 
        !           569:                case AF_INET:
        !           570:                        imp->il_link = IMPLINK_IP;
        !           571:                        imp_addr_to_leader((struct control_leader *)imp,
        !           572:                                ((struct sockaddr_in *)dst)->sin_addr.s_addr);
        !           573:                        imp->il_length = htons(ntohs((u_short)
        !           574:                            ((struct ip *)pkt)->ip_len) << 3);
        !           575:                        break;
        !           576: 
        !           577:                default:
        !           578:                        printf("imp%d: can't handle af%d\n", ifp->if_unit, 
        !           579:                                dst->sa_family);
        !           580:                        error = EAFNOSUPPORT;
        !           581:                        m0 = m;
        !           582:                        goto drop;
        !           583:                }
        !           584:        }
        !           585:        return (impsnd(ifp, m));
        !           586: drop:
        !           587:        m_freem(m0);
        !           588:        return (error);
        !           589: }
        !           590: 
        !           591: /* 
        !           592:  * Put a message on an interface's output queue. 
        !           593:  * Perform RFNM counting: no more than 8 message may be
        !           594:  * in flight to any one host.
        !           595:  */
        !           596: impsnd(ifp, m)             
        !           597:        struct ifnet *ifp;
        !           598:        struct mbuf *m;
        !           599: {
        !           600:        register struct control_leader *imp;
        !           601:        register struct host *hp;
        !           602:        register struct imp_softc *sc = &imp_softc[ifp->if_unit];
        !           603:        int s, error = 0;
        !           604: 
        !           605:        imp = mtod(m, struct control_leader *);
        !           606: 
        !           607:        /*
        !           608:         * Do RFNM counting for data messages
        !           609:         * (no more than 8 outstanding to any host).
        !           610:         * Queue data messages per host if 8 are already outstanding
        !           611:         * or if the hardware interface is already doing output.
        !           612:         * Increment imp_msgready if the message could be sent now,
        !           613:         * but must be queued because the imp output is busy.
        !           614:         */ 
        !           615:        s = splimp();
        !           616:        if (imp->dl_mtype == IMPTYPE_DATA) {
        !           617:                hp = hostenter((int)imp->dl_imp, (int)imp->dl_host,
        !           618:                    ifp->if_unit);
        !           619:                if (hp) {
        !           620:                        if (hp->h_flags & (HF_DEAD|HF_UNREACH))
        !           621:                                error = hp->h_flags & HF_DEAD ?
        !           622:                                    EHOSTDOWN : EHOSTUNREACH;
        !           623:                        else if (hp->h_rfnm < IMP_MAXHOSTMSG &&
        !           624:                            sc->imp_cb.ic_oactive == 0) {
        !           625:                                /*
        !           626:                                 * Send without queuing;
        !           627:                                 * adjust rfnm count and timer.
        !           628:                                 */
        !           629:                                if (hp->h_rfnm++ == 0)
        !           630:                                    hp->h_timer = RFNMTIMER;
        !           631:                                goto send;
        !           632:                        } else if (hp->h_rfnm + hp->h_qcnt < imphqlen) {
        !           633:                                HOST_ENQUE(hp, m);
        !           634:                                if (hp->h_rfnm + hp->h_qcnt <= IMP_MAXHOSTMSG)
        !           635:                                        sc->imp_msgready++;
        !           636:                        } else {
        !           637:                                error = ENOBUFS;
        !           638:                                IF_DROP(&ifp->if_snd);
        !           639:                        }
        !           640:                } else
        !           641:                        error = ENOBUFS;
        !           642:        } else if (sc->imp_cb.ic_oactive == 0)
        !           643:                goto send;
        !           644:        else
        !           645:                IF_ENQUEUE(&ifp->if_snd, m);
        !           646: 
        !           647:        splx(s);
        !           648:        if (error)
        !           649:                m_freem(m);
        !           650:        return (error);
        !           651: 
        !           652: send:
        !           653:        sc->imp_if.if_timer = IMP_OTIMER;
        !           654:        (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
        !           655:        splx(s);
        !           656:        return (0);
        !           657: }
        !           658: 
        !           659: /*
        !           660:  * Start another output operation on IMP; called from hardware
        !           661:  * transmit-complete interrupt routine at splimp or from imp routines
        !           662:  * when output is not in progress.  If there are any packets on shared
        !           663:  * output queue, send them, otherwise send the next data packet for a host.
        !           664:  * Host data packets are sent round-robin based on destination by walking
        !           665:  * the host list.
        !           666:  */
        !           667: impstart(sc)
        !           668:        register struct imp_softc *sc;
        !           669: {
        !           670:        register struct mbuf *m;
        !           671:        int first = 1;                          /* XXX */
        !           672:        register struct host *hp;
        !           673:        int index;
        !           674: 
        !           675:        IF_DEQUEUE(&sc->imp_if.if_snd, m);
        !           676:        if (m) {
        !           677:                sc->imp_if.if_timer = IMP_OTIMER;
        !           678:                (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
        !           679:                return;
        !           680:        }
        !           681:        if (sc->imp_msgready) {
        !           682:                if ((m = sc->imp_hostq) == 0 && (m = sc->imp_hosts) == 0)
        !           683:                        panic("imp msgready");
        !           684:                index = sc->imp_hostent;
        !           685:                for (hp = &mtod(m, struct hmbuf *)->hm_hosts[index]; ;
        !           686:                    hp++, index++) {
        !           687:                        if (index >= HPMBUF) {
        !           688:                                if ((m = m->m_next) == 0)
        !           689:                                        m = sc->imp_hosts;
        !           690:                                index = 0;
        !           691:                                hp = mtod(m, struct hmbuf *)->hm_hosts;
        !           692:                                first = 0;              /* XXX */
        !           693:                        }
        !           694:                        if (hp->h_qcnt && hp->h_rfnm < IMP_MAXHOSTMSG) {
        !           695:                                /*
        !           696:                                 * Found host entry with another message
        !           697:                                 * to send.  Deliver it to the IMP.
        !           698:                                 * Start with succeeding host next time.
        !           699:                                 */
        !           700:                                impstarthost(sc, hp);
        !           701:                                sc->imp_hostq = m;
        !           702:                                sc->imp_hostent = index + 1;
        !           703:                                return;
        !           704:                        }
        !           705:                        if (m == sc->imp_hostq && !first &&
        !           706:                            index + 1 >= sc->imp_hostent) {     /* XXX */
        !           707:                                log(imppri, "imp: can't find %d msgready\n",
        !           708:                                    sc->imp_msgready);
        !           709:                                sc->imp_msgready = 0;
        !           710:                                break;
        !           711:                        }
        !           712:                }
        !           713:        }
        !           714:        sc->imp_if.if_timer = 0;
        !           715: }
        !           716: 
        !           717: /*
        !           718:  * Restart output for a host that has received a RFNM
        !           719:  * or incomplete or has timed out while waiting for a RFNM.
        !           720:  * Must be called at splimp.
        !           721:  */
        !           722: imprestarthost(sc, hp)
        !           723:        register struct imp_softc *sc;
        !           724:        struct host *hp;
        !           725: {
        !           726: 
        !           727:        if (--hp->h_rfnm > 0)
        !           728:                hp->h_timer = RFNMTIMER;
        !           729:        /*
        !           730:         * If the RFNM moved a queued message into the window,
        !           731:         * update msgready and start IMP if idle.
        !           732:         */
        !           733:        if (hp->h_qcnt > IMP_MAXHOSTMSG - 1 - hp->h_rfnm) {
        !           734:                sc->imp_msgready++;
        !           735:                if (sc->imp_cb.ic_oactive == 0)
        !           736:                        impstarthost(sc, hp);
        !           737:        }
        !           738:        if (hp->h_rfnm == 0 && hp->h_qcnt == 0)
        !           739:                hostidle(hp);
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * Send the next message queued for a host
        !           744:  * when ready to send another message to the IMP.
        !           745:  * Called only when output is not in progress.
        !           746:  * Bump RFNM counter and start RFNM timer
        !           747:  * when we send the message to the IMP.
        !           748:  * Must be called at splimp.
        !           749:  */
        !           750: impstarthost(sc, hp)
        !           751:        register struct imp_softc *sc;
        !           752:        register struct host *hp;
        !           753: {
        !           754:        struct mbuf *m;
        !           755: 
        !           756:        if (hp->h_rfnm++ == 0)
        !           757:                hp->h_timer = RFNMTIMER;
        !           758:        HOST_DEQUE(hp, m);
        !           759:        sc->imp_if.if_timer = IMP_OTIMER;
        !           760:        (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
        !           761:        sc->imp_msgready--;
        !           762: }
        !           763: 
        !           764: /*
        !           765:  * "Watchdog" timeout.  When the output timer expires,
        !           766:  * we assume we have been blocked by the imp.
        !           767:  * No need to restart, just collect statistics.
        !           768:  */
        !           769: imptimo(unit)
        !           770:        int unit;
        !           771: {
        !           772: 
        !           773:        imp_softc[unit].imp_block++;
        !           774: }
        !           775: 
        !           776: /*
        !           777:  * Put three 1822 NOOPs at the head of the output queue. 
        !           778:  * Part of host-IMP initialization procedure.
        !           779:  * (Should return success/failure, but noone knows
        !           780:  * what to do with this, so why bother?)
        !           781:  * This routine is always called at splimp, so we don't
        !           782:  * protect the call to IF_PREPEND.
        !           783:  */
        !           784: impnoops(sc)             
        !           785:        register struct imp_softc *sc;
        !           786: {
        !           787:        register i;
        !           788:        register struct mbuf *m;
        !           789:        register struct control_leader *cp;
        !           790: 
        !           791: #ifdef IMPINIT
        !           792:        if (imptraceinit)
        !           793:                log(imppri, "impnoops\n");
        !           794: #endif
        !           795:        for (i = 0; i < IMP_NOOPCNT; i++) { 
        !           796:                if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) 
        !           797:                        return;
        !           798:                m->m_len = sizeof(struct control_leader);
        !           799:                cp = mtod(m, struct control_leader *);
        !           800:                cp->dl_format = IMP_NFF;
        !           801:                cp->dl_link = i;
        !           802:                cp->dl_mtype = IMPTYPE_NOOP;
        !           803:                IF_PREPEND(&sc->imp_if.if_snd, m);
        !           804:        }
        !           805:        if (sc->imp_cb.ic_oactive == 0)
        !           806:                impstart(sc);
        !           807: }
        !           808: 
        !           809: /*
        !           810:  * Process an ioctl request.
        !           811:  */
        !           812: impioctl(ifp, cmd, data)
        !           813:        register struct ifnet *ifp;
        !           814:        int cmd;
        !           815:        caddr_t data;
        !           816: {
        !           817:        struct ifaddr *ifa = (struct ifaddr *) data;
        !           818:        int s = splimp(), error = 0;
        !           819: #define sc     ((struct imp_softc *)ifp)
        !           820: 
        !           821:        switch (cmd) {
        !           822: 
        !           823:        case SIOCSIFADDR:
        !           824:                if (ifa->ifa_addr.sa_family != AF_INET) {
        !           825:                        error = EINVAL;
        !           826:                        break;
        !           827:                }
        !           828:                if ((ifp->if_flags & IFF_UP) == 0)
        !           829:                        impinit(ifp->if_unit);
        !           830:                break;
        !           831: 
        !           832:        case SIOCSIFFLAGS:
        !           833:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !           834:                    sc->imp_state != IMPS_DOWN) {
        !           835:                        if (sc->imp_cb.ic_down &&
        !           836:                            (*sc->imp_cb.ic_down)(sc->imp_cb.ic_hwunit)) {
        !           837:                                sc->imp_state = IMPS_DOWN;
        !           838:                                sc->imp_msgready = 0;
        !           839:                                hostreset(ifp->if_unit);
        !           840:                                if_down(ifp);
        !           841:                        }
        !           842:                } else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN)
        !           843:                        impinit(ifp->if_unit);
        !           844:                break;
        !           845: 
        !           846:        default:
        !           847:                error = EINVAL;
        !           848:                break;
        !           849:        }
        !           850:        splx(s);
        !           851:        return (error);
        !           852: }
        !           853: 
        !           854: #ifdef IMPLEADERS
        !           855: printleader(routine, ip)
        !           856:        char *routine;
        !           857:        register struct imp_leader *ip;
        !           858: {
        !           859:        printf("%s: ", routine);
        !           860:        printbyte((char *)ip, 12);
        !           861:        printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
        !           862:                ip->il_flags);
        !           863:        if (ip->il_mtype <= IMPTYPE_READY)
        !           864:                printf("%s,", impleaders[ip->il_mtype]);
        !           865:        else
        !           866:                printf("%x,", ip->il_mtype);
        !           867:        printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
        !           868:                ntohs(ip->il_imp));
        !           869:        if (ip->il_link == IMPLINK_IP)
        !           870:                printf("ip,");
        !           871:        else
        !           872:                printf("%x,", ip->il_link);
        !           873:        printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
        !           874: }
        !           875: 
        !           876: printbyte(cp, n)
        !           877:        register char *cp;
        !           878:        int n;
        !           879: {
        !           880:        register i, j, c;
        !           881: 
        !           882:        for (i=0; i<n; i++) {
        !           883:                c = *cp++;
        !           884:                for (j=0; j<2; j++)
        !           885:                        putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
        !           886:                putchar(' ', 0);
        !           887:        }
        !           888:        putchar('\n', 0);
        !           889: }
        !           890: #endif
        !           891: 
        !           892: /*
        !           893:  * Routine to convert from IMP Leader to InterNet Address.
        !           894:  *
        !           895:  * This procedure is necessary because IMPs may be assigned Class A, B, or C
        !           896:  * network numbers, but only have 8 bits in the leader to reflect the
        !           897:  * IMP "network number".  The strategy is to take the network number from
        !           898:  * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
        !           899:  * from the leader.
        !           900:  *
        !           901:  * There is no support for "Logical Hosts".
        !           902:  *
        !           903:  * Class A:    Net.Host.0.Imp
        !           904:  * Class B:    Net.net.Host.Imp
        !           905:  * Class C:    Net.net.net.(Host4|Imp4)
        !           906:  */
        !           907: imp_leader_to_addr(ap, cp, ifp)
        !           908:        struct in_addr *ap;
        !           909:        register struct control_leader *cp;
        !           910:        struct ifnet *ifp;
        !           911: {
        !           912:        register u_long final;
        !           913:        register struct sockaddr_in *sin;
        !           914:        int imp = ntohs(cp->dl_imp);
        !           915: 
        !           916:        sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
        !           917:        final = ntohl(sin->sin_addr.s_addr);
        !           918: 
        !           919:        if (IN_CLASSA(final)) {
        !           920:                final &= IN_CLASSA_NET;
        !           921:                final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16);
        !           922:        } else if (IN_CLASSB(final)) {
        !           923:                final &= IN_CLASSB_NET;
        !           924:                final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8);
        !           925:        } else {
        !           926:                final &= IN_CLASSC_NET;
        !           927:                final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4);
        !           928:        }
        !           929:        ap->s_addr = htonl(final);
        !           930: }
        !           931: 
        !           932: /*
        !           933:  * Function to take InterNet address and fill in IMP leader fields.
        !           934:  */
        !           935: imp_addr_to_leader(imp, a)
        !           936:        register struct control_leader *imp;
        !           937:        u_long a;
        !           938: {
        !           939:        register u_long addr = ntohl(a);
        !           940: 
        !           941:        imp->dl_network = 0;    /* !! */
        !           942: 
        !           943:        if (IN_CLASSA(addr)) {
        !           944:                imp->dl_host = ((addr>>16) & 0xFF);
        !           945:                imp->dl_imp = addr & 0xFF;
        !           946:        } else if (IN_CLASSB(addr)) {
        !           947:                imp->dl_host = ((addr>>8) & 0xFF);
        !           948:                imp->dl_imp = addr & 0xFF;
        !           949:        } else {
        !           950:                imp->dl_host = ((addr>>4) & 0xF);
        !           951:                imp->dl_imp = addr & 0xF;
        !           952:        }
        !           953:        imp->dl_imp = htons(imp->dl_imp);
        !           954: }
        !           955: #endif

unix.superglobalmegacorp.com

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