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

unix.superglobalmegacorp.com

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