Annotation of 43BSDReno/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 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.