Annotation of 43BSDTahoe/sys/netimp/if_imp.c, revision 1.1.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.