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

unix.superglobalmegacorp.com

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