Annotation of 43BSD/sys/vaxif/if_ddn.c, revision 1.1

1.1     ! root        1: /*     @(#)if_ddn.c    7.1 (Berkeley) 6/5/86 */
        !             2: 
        !             3: 
        !             4: /************************************************************************\
        !             5: 
        !             6:      ________________________________________________________
        !             7:     /                                                        \
        !             8:    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
        !             9:    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
        !            10:    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
        !            11:    |       AAAA AAAA      CCCC              CCCC              |
        !            12:    |      AAAA   AAAA     CCCC              CCCC              |
        !            13:    |     AAAA     AAAA    CCCC              CCCC              |
        !            14:    |    AAAA       AAAA   CCCC              CCCC              |
        !            15:    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
        !            16:    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
        !            17:    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
        !            18:     \________________________________________________________/
        !            19: 
        !            20:        Copyright (c) 1985 by Advanced Computer Communications
        !            21:        720 Santa Barbara Street, Santa Barbara, California  93101
        !            22:        (805) 963-9431
        !            23: 
        !            24:        This software may be duplicated and used on systems
        !            25:        which are licensed to run U.C. Berkeley versions of
        !            26:        the UNIX operating system.  Any duplication of any
        !            27:        part of this software must include a copy of ACC's
        !            28:        copyright notice.
        !            29: 
        !            30: 
        !            31: File:
        !            32:                if_ddn.c
        !            33: 
        !            34: Author:
        !            35:                Art Berggreen
        !            36: 
        !            37: Project:
        !            38:                4.2 DDN X.25 network driver
        !            39: 
        !            40: Function:
        !            41:                This is a network device driver for BSD 4.2 UNIX which
        !            42:                provides an interface between IP and ACC's ACP625
        !            43:                (IF-11/X25) for connecting to the Defense Data Network.
        !            44: 
        !            45: Components:
        !            46: 
        !            47: Revision History:
        !            48:                16-May-1985:    V1.0 - First release.
        !            49:                                Art Berggreen.
        !            50: 
        !            51: \************************************************************************/
        !            52: 
        !            53: 
        !            54: /*     if_ddn.c         V1.0   5/16/85 */
        !            55: 
        !            56: /*
        !            57:  * ACC ACP625 DDN/X.25 Network device driver
        !            58:  */
        !            59: 
        !            60: /* #define DDNDEBUG 1          /* Enable definition for Debug code */
        !            61: 
        !            62: #include "ddn.h"
        !            63: #if NDDN > 0
        !            64: #include "../machine/pte.h"
        !            65: 
        !            66: #include "param.h"
        !            67: #include "systm.h"
        !            68: #include "mbuf.h"
        !            69: #include "buf.h"
        !            70: #include "protosw.h"
        !            71: #include "socket.h"
        !            72: #include "vmmac.h"
        !            73: #include "errno.h"
        !            74: #include "time.h"
        !            75: #include "kernel.h"
        !            76: #include "ioctl.h"
        !            77: 
        !            78: #include "../net/if.h"
        !            79: #include "../net/netisr.h"
        !            80: #include "../net/route.h"
        !            81: 
        !            82: #ifdef INET
        !            83: #include "../netinet/in.h"
        !            84: #include "../netinet/in_systm.h"
        !            85: #include "../netinet/in_var.h"
        !            86: #include "../netinet/ip.h"
        !            87: #endif
        !            88: 
        !            89: #include "../vax/cpu.h"
        !            90: #include "../vax/mtpr.h"
        !            91: #include "if_ddnreg.h"
        !            92: #include "if_ddnvar.h"
        !            93: #include "if_uba.h"
        !            94: #include "../vaxuba/ubareg.h"
        !            95: #include "../vaxuba/ubavar.h"
        !            96: 
        !            97: 
        !            98: 
        !            99: /* declare global functions */
        !           100: 
        !           101: int ddnprobe();
        !           102: int ddnattach();
        !           103: int ddnreset();
        !           104: int ddninit();
        !           105: int ddnoutput();
        !           106: int ddntimer();
        !           107: int ddnioctl();
        !           108: int ddnintr();
        !           109: 
        !           110: /* declare local functions */
        !           111: 
        !           112: static void x25_init();
        !           113: static struct ddn_cb *locate_x25_lcn();
        !           114: static boolean convert_ip_addr();
        !           115: static int convert_x25_addr();
        !           116: static boolean make_x25_call();
        !           117: static void ddn_start();
        !           118: static void ddn_iorq();
        !           119: static void start_chn();
        !           120: static void ddn_data();
        !           121: static void ddn_supr();
        !           122: static void supr_msg();
        !           123: static boolean decode_ring();
        !           124: static void clear_lcn();
        !           125: static void send_restart();
        !           126: static void send_supr();
        !           127: #ifdef DDNDEBUG
        !           128: static void prt_addr();
        !           129: static void prt_bytes();
        !           130: #endif DDNDEBUG
        !           131: 
        !           132: 
        !           133: struct uba_device *ddninfo[NDDN];      /* ptrs to device info */
        !           134: u_short        ddnstd[] = { 0766740, 0 };      /* standard addresses */
        !           135: struct uba_driver ddndriver =          /* device driver info */
        !           136:   {
        !           137:     ddnprobe,                          /* device probe routine */
        !           138:     0,                                 /* slave probe routine */
        !           139:     ddnattach,                         /* device attach routine */
        !           140:     0,                                 /* "dmago" routine */
        !           141:     ddnstd,                            /* device address */
        !           142:     "ddn",                             /* device name */
        !           143:     ddninfo                            /* ptr to device info ptrs */
        !           144:   };
        !           145: 
        !           146: static u_char init_msg[] =
        !           147:   {
        !           148:     LINE_CNTL,                         /* set command code */
        !           149:     0x00,                              /* not used */
        !           150:     0x00,                              /* not used */
        !           151:     0x00,                              /* extension length (set at runtime) */
        !           152:     LINK_DISABLE,                      /* link disable */
        !           153: /*    LINK_LOOPBACK,                   /* loopback mode */
        !           154: /*    LOOP_INTERNAL,                   /*   = internal loopback */
        !           155:     PKT_SIZE,                          /* packet size */
        !           156:     0x80,                              /*   128 - LSB */
        !           157:     0x00,                              /*   128 - MSB */
        !           158:     PKT_WINDOW,                                /* packet window */
        !           159:     0x02,                              /*   = 2 */
        !           160:     LINK_ENABLE                                /* link enable */
        !           161:   };
        !           162: 
        !           163: u_char cb_cmnd[4] =
        !           164:   {
        !           165:     CALL,
        !           166:     0,
        !           167:     0,
        !           168:     0
        !           169:   };
        !           170: 
        !           171: u_char cb_called_addr[16] = {0};
        !           172: 
        !           173: u_char cb_calling_addr[16] = {0};
        !           174: 
        !           175: u_char cb_facilities[64] = {0};
        !           176: 
        !           177: u_char cb_protocol[5] = {0};
        !           178: 
        !           179: u_char cb_user_data[1] = {0};
        !           180: 
        !           181: #ifdef DDNDEBUG
        !           182: int ddn_debug = 1;             /* values 0-8 cause increasing verbosity */
        !           183: #endif DDNDEBUG
        !           184: 
        !           185: 
        !           186: /***********************************************************************\
        !           187: *                                                                      *
        !           188: *      Information for each device unit is maintained in an array      *
        !           189: *      of structures named ddn_softc[].  The array is indexed by       *
        !           190: *      unit number.  Each entry includes the network interface         *
        !           191: *      structure (ddn_if) used by the routing code to locate the       *
        !           192: *      interface,  an array of Logical Channel control blocks which    *
        !           193: *      maintain information about each of the Logical Channels (LCNs)  *
        !           194: *      through which X.25 virtual calls are established, a queue of    *
        !           195: *      I/O requests pending for the UMC, the UNIBUS interrupt vector   *
        !           196: *      for the unit and misc flags.  The Logical Channel Control       *
        !           197: *      blocks maintain information about the state of each LCN,        *
        !           198: *      a queue of outbound data, Half Duplex Channel (HDX) blocks      *
        !           199: *      used for queuing I/O requests to the UMC and an ifuba           *
        !           200: *      structure which records the UNIBUS resources being held by      *
        !           201: *      the LCN.                                                        *
        !           202: *                                                                      *
        !           203: \***********************************************************************/
        !           204: 
        !           205: struct sioq            /* Start I/O queue head */
        !           206:   {
        !           207:     struct hdx_chan    *sq_head;       /* queue head */
        !           208:     struct hdx_chan    *sq_tail;       /* queue tail */
        !           209:   };
        !           210: 
        !           211: struct hdx_chan                /* HDX channel block */
        !           212:   {
        !           213:     struct hdx_chan    *hc_next;       /* link to next HDX channel */
        !           214:     u_char             hc_chan;        /* HDX channel number */
        !           215:     u_char             hc_adx;         /* address bits 17-16 */
        !           216:     u_short            hc_addr;        /* address bits 15-00 */
        !           217:     u_short            hc_cnt;         /* byte count */
        !           218:     u_char             hc_func;        /* I/O function */
        !           219:     u_char             hc_sbfc;        /* I/O subfunction */
        !           220:   };
        !           221: 
        !           222: struct ddn_cb          /* Logical Channel control block */
        !           223:   {
        !           224:     struct in_addr     dc_inaddr;      /* remote Internet address */
        !           225:     u_char             dc_lcn;         /* LCN number */
        !           226:     u_char             dc_state;       /* LCN state */
        !           227:     u_short            dc_timer;       /* LCN timer */
        !           228:     struct ifqueue     dc_oq;          /* LCN output queue */
        !           229:     struct hdx_chan    dc_rchan;       /* LCN read HDX channel */
        !           230:     struct hdx_chan    dc_wchan;       /* LCN write HDX channel */
        !           231:     struct ifuba       dc_ifuba;       /* UNIBUS resources */
        !           232:     u_short            dc_flags;       /* misc flags */
        !           233:   };
        !           234: 
        !           235: struct ddn_softc       /* device control structure */
        !           236:   {
        !           237:     struct ifnet       ddn_if;         /* network-visible interface */
        !           238:     struct ddn_cb      ddn_cb[NDDNCH+1]; /* Logical Channel cntl blks */
        !           239:     struct sioq                ddn_sioq;       /* start I/O queue */
        !           240:     int                        ddn_vector;     /* UNIBUS interrupt vector */
        !           241:     u_short            ddn_flags;      /* misc flags */
        !           242:     struct in_addr     ddn_ipaddr;     /* local IP address */
        !           243:   } ddn_softc[NDDN];
        !           244: 
        !           245: 
        !           246: /***********************************************************************\
        !           247: *                              ddnprobe()                              *
        !           248: *************************************************************************
        !           249: *                                                                      *
        !           250: *      This routine probes the device to obtain the UNIBUS interrupt   *
        !           251: *      vector.  Since the UMC is a soft vector device, we obtain       *
        !           252: *      an unused vector from the uba structure and return that.        *
        !           253: *      The UMC is given the vector and the board is reset.             *
        !           254: *      In order to save the vector in the device info structure, we    *
        !           255: *      place it in a static temporary where the attach routine can     *
        !           256: *      find it and save it in the device info structure.  This is      *
        !           257: *      necessary because probe only provides a pointer to the device   *
        !           258: *      and we have no idea which unit is being referenced.  This       *
        !           259: *      works in 4.2 because the attach routine is called immediately   *
        !           260: *      after a successful probe.                                       *
        !           261: *                                                                      *
        !           262: \***********************************************************************/
        !           263: 
        !           264: #define INIT_DELAY     (100 * 2)       /* time for board initialization */
        !           265:                                        /*   ( in 10 millisecond ticks) */
        !           266: 
        !           267: static int savevec;                    /* static variable for vector */
        !           268: 
        !           269: ddnprobe(reg)
        !           270: caddr_t reg;
        !           271:   {
        !           272:     register int br, cvec;             /* r11, r10 value-result */
        !           273:     register struct ddnregs *addr = (struct ddnregs *)reg;
        !           274:     register int delay_time;
        !           275: 
        !           276: #ifdef lint
        !           277:     br = 0; cvec = br; br = cvec; ddnintr(0);
        !           278: #endif
        !           279: 
        !           280:     cvec = savevec = (uba_hd[numuba].uh_lastiv -= 4);  /* return vector */
        !           281:     br = 0x15;                         /* return bus level */
        !           282: 
        !           283:     addr->ioini = 0;                   /* clear handshake flags */
        !           284:     addr->ionmi = 0;
        !           285:     addr->staack = 0;
        !           286:     addr->xfrgnt = 0;
        !           287:     addr->iovect = cvec >> 2;          /* pass vector to UMC */
        !           288:     addr->csr = DDN_RST;               /* reset the board */
        !           289:     delay_time = mfpr(TODR) + INIT_DELAY;
        !           290:     while(delay_time > mfpr(TODR)) /* wait */ ;
        !           291: 
        !           292:     return (sizeof(struct ddnregs));
        !           293:   }
        !           294: 
        !           295: 
        !           296: /***********************************************************************\
        !           297: *                              ddnattach                               *
        !           298: *************************************************************************
        !           299: *                                                                      *
        !           300: *      This routine attaches the device to the network software.       *
        !           301: *      The network interface structure is filled in.  The device       *
        !           302: *      will be initialized when the system is ready to accept packets. *
        !           303: *                                                                      *
        !           304: \***********************************************************************/
        !           305: 
        !           306: ddnattach(ui)
        !           307: struct uba_device *ui;
        !           308:   {
        !           309:     register struct ddn_softc *ds = &ddn_softc[ui->ui_unit];
        !           310: 
        !           311:     ds->ddn_vector = savevec;          /* save vector from probe() */
        !           312:     ds->ddn_if.if_unit = ui->ui_unit;  /* set unit number */
        !           313:     ds->ddn_if.if_name = "ddn";                /* set device name */
        !           314:     ds->ddn_if.if_mtu = DDNMTU;                /* set max msg size */
        !           315:     ds->ddn_if.if_init = ddninit;      /* set init routine addr */
        !           316:     ds->ddn_if.if_ioctl = ddnioctl;    /* set ioctl routine addr */
        !           317:     ds->ddn_if.if_output = ddnoutput;  /* set output routine addr */
        !           318:     ds->ddn_if.if_reset = ddnreset;    /* set reset routine addr */
        !           319:     ds->ddn_if.if_watchdog = ddntimer; /* set timer routine addr */
        !           320:     if_attach(&ds->ddn_if);
        !           321:   }
        !           322: 
        !           323: 
        !           324: /***********************************************************************\
        !           325: *                              ddnreset()                              *
        !           326: *************************************************************************
        !           327: *                                                                      *
        !           328: *      Reset of interface after UNIBUS reset.                          *
        !           329: *      If interface is on specified uba, reset its state.              *
        !           330: *                                                                      *
        !           331: \***********************************************************************/
        !           332: 
        !           333: ddnreset(unit, uban)
        !           334: int unit, uban;
        !           335:   {
        !           336:     register struct uba_device *ui;
        !           337:     register struct ddnregs *addr;
        !           338:     register int delay_time;
        !           339: 
        !           340:     if (unit >= NDDN || (ui = ddninfo[unit]) == 0 || ui->ui_alive == 0 ||
        !           341:       ui->ui_ubanum != uban)
        !           342:        return;
        !           343: 
        !           344:     printf(" ddn%d", unit);
        !           345: 
        !           346:     addr = (struct ddnregs *)ui->ui_addr;
        !           347:     addr->ioini = 0;                   /* clear handshake flags */
        !           348:     addr->ionmi = 0;
        !           349:     addr->staack = 0;
        !           350:     addr->xfrgnt = 0;
        !           351:     addr->iovect = ddn_softc[unit].ddn_vector >> 2;  /* pass vector to UMC */
        !           352:     addr->csr = DDN_RST;               /* reset the board */
        !           353:     delay_time = mfpr(TODR) + INIT_DELAY;
        !           354:     while(delay_time > mfpr(TODR)) /* wait */ ;
        !           355: 
        !           356:     ddninit(unit);
        !           357:   }
        !           358: 
        !           359: 
        !           360: /***********************************************************************\
        !           361: *                              ddninit()                               *
        !           362: *************************************************************************
        !           363: *                                                                      *
        !           364: *      This routine initializes the interface for operation.  The      *
        !           365: *      device control blocks are initialized, UNIBUS resources are     *
        !           366: *      allocated and an X.25 initialization message is sent to the     *
        !           367: *      UMC.                                                            *
        !           368: *                                                                      *
        !           369: \***********************************************************************/
        !           370: 
        !           371: ddninit(unit)
        !           372: int unit;
        !           373:   {
        !           374:     register struct ddn_softc *ds = &ddn_softc[unit];
        !           375:     register struct ddn_cb *dc;
        !           376:     register struct uba_device *ui = ddninfo[unit];
        !           377:     int lcn, s;
        !           378: 
        !           379: #ifdef DDNDEBUG
        !           380: if (ddn_debug > 0)
        !           381:   {
        !           382: printf("ddn%d: ddninit()\n", unit);
        !           383:   }
        !           384: #endif DDNDEBUG
        !           385: 
        !           386:     if (ds->ddn_if.if_addrlist == 0)   /* if we have no internet addr */
        !           387:        return;                         /*   don't init yet */
        !           388: 
        !           389:     dc = ds->ddn_cb;                   /* setup ptr to first LCN cntl block */
        !           390: 
        !           391:     for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's ... */
        !           392:       {
        !           393:        dc->dc_lcn = lcn;               /* record LCN */
        !           394:        dc->dc_inaddr.s_addr = 0;       /* clear remote internet addr */
        !           395:        dc->dc_state = LC_DOWN;         /* init LCN state */
        !           396:        dc->dc_timer = TMO_OFF;         /* turn LCN timer off */
        !           397: 
        !           398:                /* init LCN output queue */
        !           399: 
        !           400:        dc->dc_oq.ifq_head = (struct mbuf *)0;
        !           401:        dc->dc_oq.ifq_tail = (struct mbuf *)0;
        !           402:        dc->dc_oq.ifq_len = 0;
        !           403:        dc->dc_oq.ifq_maxlen = DDN_OQMAX;
        !           404:        dc->dc_oq.ifq_drops = 0;
        !           405: 
        !           406:                /* init HDX channels */
        !           407: 
        !           408:        dc->dc_rchan.hc_next = (struct hdx_chan *)0;
        !           409:        dc->dc_rchan.hc_chan = lcn * 2;
        !           410:        dc->dc_wchan.hc_next = (struct hdx_chan *)0;
        !           411:        dc->dc_wchan.hc_chan = (lcn * 2) + 1;
        !           412: 
        !           413:                /* init UNIBUS resources */
        !           414: 
        !           415:        if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
        !           416:            0, (int)btoc(DDNMTU)) == 0)
        !           417:          {
        !           418:            printf("ddn%d: failed getting UBA resources for lcn %d\n",
        !           419:                unit, lcn);
        !           420:            ds->ddn_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
        !           421:            return;
        !           422:          }
        !           423: 
        !           424:        dc->dc_flags = 0;               /* initialize flags */
        !           425: 
        !           426:        dc++;                           /* point at next cntl blk */
        !           427:       }
        !           428: 
        !           429:     ds->ddn_sioq.sq_head = (struct hdx_chan *)0;
        !           430:     ds->ddn_sioq.sq_tail = (struct hdx_chan *)0;
        !           431:     ds->ddn_if.if_flags |= IFF_RUNNING;
        !           432: 
        !           433:     s = splimp();
        !           434: 
        !           435:     dc = ds->ddn_cb;                   /* setup ptr to first LCN cntl block */
        !           436: 
        !           437:     for(lcn = 0; lcn <= NDDNCH; lcn++) /* issue reads on all LCNs */
        !           438:       {
        !           439:        ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
        !           440:        dc++;
        !           441:       }
        !           442: 
        !           443:     x25_init(ds);                      /* init the X.25 board */
        !           444: 
        !           445:     splx(s);
        !           446: 
        !           447:     ddntimer(unit);                    /* start timers */
        !           448:   }
        !           449: 
        !           450: 
        !           451: /***********************************************************************\
        !           452: *                              ddnoutput()                             *
        !           453: *************************************************************************
        !           454: *                                                                      *
        !           455: *      This routine is called by the network software when it has      *
        !           456: *      an IP datagram to send out this interface.  An attempt is       *
        !           457: *      made to find a LCN which has a virtual circuit open to the      *
        !           458: *      indicated host.  If an LCN is found the packet is queued for    *
        !           459: *      output on that LCN.                                             *
        !           460: *                                                                      *
        !           461: \***********************************************************************/
        !           462: 
        !           463: ddnoutput(ifp, m0, dst)
        !           464: struct ifnet *ifp;
        !           465: struct mbuf *m0;
        !           466: struct sockaddr_in *dst;
        !           467:   {
        !           468:     register struct mbuf *m = m0;
        !           469:     register struct ddn_softc *ds = &ddn_softc[ifp->if_unit];
        !           470:     register struct ddn_cb *dc;
        !           471:     register struct ifqueue *oq;
        !           472:     int s;
        !           473: 
        !           474:     if ((ds->ddn_if.if_flags & IFF_UP) == 0)
        !           475:        return (ENETDOWN);
        !           476: 
        !           477:     switch (dst->sin_family)
        !           478:       {
        !           479: 
        !           480: #ifdef INET
        !           481:     case AF_INET:
        !           482:        break;
        !           483: #endif INET
        !           484: 
        !           485:     default:
        !           486:        printf("ddn%d: can't handle af%d\n", ifp->if_unit,
        !           487:            dst->sin_family);
        !           488:        m_freem(m0);
        !           489:        return (EAFNOSUPPORT);
        !           490:       }
        !           491: 
        !           492: 
        !           493: #ifdef DDNDEBUG
        !           494: if (ddn_debug > 6)
        !           495:   {
        !           496: printf("ddnoutput(): dst = ");
        !           497: prt_addr(dst->sin_addr.s_addr);
        !           498: printf("\n");
        !           499:   }
        !           500: #endif DDNDEBUG
        !           501: 
        !           502:     s = splimp();
        !           503: 
        !           504:     /* try to find an LCN */
        !           505: 
        !           506:     if (dc = locate_x25_lcn(ds, dst->sin_addr))
        !           507:       {                                                /* if found */
        !           508:        oq = &(dc->dc_oq);                      /*   point to output queue */
        !           509:        dc->dc_state = LC_DATA_IDLE;
        !           510:        dc->dc_timer = TMO_DATA_IDLE;
        !           511:        if (IF_QFULL(oq))                       /*   if q full */
        !           512:          {
        !           513:            IF_DROP(oq);                        /*     drop the data */
        !           514:            m_freem(m);
        !           515:            splx(s);
        !           516:            return (ENOBUFS);
        !           517:          }
        !           518:        IF_ENQUEUE(oq, m);                      /*   otherwise queue it */
        !           519:        ddn_start(ds, dc);                      /*   and try to output */
        !           520:        splx(s);
        !           521:        return (0);
        !           522:       }
        !           523:     else                                       /* if no circuit available */
        !           524:       {
        !           525:        IF_DROP(&ifp->if_snd);                  /*   drop the data */
        !           526:        m_freem(m);
        !           527:        splx(s);
        !           528:        return (EHOSTUNREACH);
        !           529:       }
        !           530: 
        !           531:   }
        !           532: 
        !           533: 
        !           534: /***********************************************************************\
        !           535: *                              ddntimer()                              *
        !           536: *************************************************************************
        !           537: *                                                                      *
        !           538: *      This routine is entered once a second to perform timer          *
        !           539: *      managment.  The LCN table is scanned for active timers,         *
        !           540: *      (nonzero) which are decremented.  If a timer expires            *
        !           541: *      (becomes zero), the proper action is taken.                     *
        !           542: *                                                                      *
        !           543: \***********************************************************************/
        !           544: 
        !           545: int ddntimer(unit)
        !           546: int unit;
        !           547:   {
        !           548:     register struct ddn_softc *ds = &ddn_softc[unit];
        !           549:     register struct ddn_cb *dc;
        !           550:     register int s, lcn;
        !           551: 
        !           552: #ifdef DDNDEBUG
        !           553: if (ddn_debug > 7)
        !           554:   {
        !           555: printf("ddntimer()\n");
        !           556:   }
        !           557: #endif DDNDEBUG
        !           558: 
        !           559:     ds->ddn_if.if_timer = DDN_TIMEOUT;         /* restart timer */
        !           560: 
        !           561:     dc = ds->ddn_cb;
        !           562: 
        !           563:     s = splimp();
        !           564: 
        !           565:     for(lcn = 0; lcn <= NDDNCH; lcn++)         /* scan all LCN's */
        !           566:       {
        !           567:        if (dc->dc_timer && (--(dc->dc_timer) == 0))
        !           568:          {                                     /* if a timer expired */
        !           569:            if (dc->dc_state == LC_RESTART)
        !           570:              {                                 /*   if a restart was out */
        !           571:                send_restart(ds);               /*     send another one */
        !           572:                break;
        !           573:              }
        !           574:            else                                /*   otherwise */
        !           575:              {
        !           576:                clear_lcn(ds, dc);              /*     clear the LCN */
        !           577:              }
        !           578:          }
        !           579:        dc++;
        !           580:       }
        !           581:     splx(s);
        !           582:   }
        !           583: 
        !           584: 
        !           585: /***********************************************************************\
        !           586: *                              ddnioctl()                              *
        !           587: *************************************************************************
        !           588: *                                                                      *
        !           589: *      This routine processes device dependent ioctl's.  Currently,    *
        !           590: *      the only ioctl supported is used to set the host's internet     *
        !           591: *      address for this network interface.                             *
        !           592: *                                                                      *
        !           593: \***********************************************************************/
        !           594: 
        !           595: ddnioctl(ifp, cmd, data)
        !           596:        register struct ifnet *ifp;
        !           597:        int cmd;
        !           598:        caddr_t data;
        !           599: {
        !           600:        struct ifaddr *ifa = (struct ifaddr *) data;
        !           601:        int s = splimp(), error = 0;
        !           602: 
        !           603:        switch (cmd) {
        !           604: 
        !           605:        case SIOCSIFADDR:
        !           606:                if (ifa->ifa_addr.sa_family != AF_INET)
        !           607:                        return(EINVAL);
        !           608:                ifp->if_flags |= IFF_UP;
        !           609:                if ((ifp->if_flags & IFF_RUNNING) == 0)
        !           610:                        ddninit(ifp->if_unit);
        !           611:                ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
        !           612:                break;
        !           613: 
        !           614:        default:
        !           615:                error = EINVAL;
        !           616:                break;
        !           617:        }
        !           618:        splx(s);
        !           619:        return (error);
        !           620: }
        !           621: 
        !           622: 
        !           623: /***********************************************************************\
        !           624: *                              ddnintr()                               *
        !           625: *************************************************************************
        !           626: *                                                                      *
        !           627: *      This is the interrupt handler for UNIBUS interrupts from the    *
        !           628: *      UMC.  The interrupting HDX channel and interrupt type are       *
        !           629: *      obtained from the completion comm regs.  If the interrupt is    *
        !           630: *      an I/O request acknowledge, the next I/O request is passed      *
        !           631: *      to the UMC.  If the interrupt is an I/O completion, the         *
        !           632: *      completion is processed depending on whether it is for the      *
        !           633: *      supervisor or a data channel.                                   *
        !           634: *                                                                      *
        !           635: \***********************************************************************/
        !           636: 
        !           637: ddnintr(unit)
        !           638: int unit;
        !           639:   {
        !           640:     register struct ddn_softc *ds = &ddn_softc[unit];
        !           641:     register struct hdx_chan *hc;
        !           642:     register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
        !           643:     int chan, type, cc, cnt;
        !           644: 
        !           645:     /*
        !           646:      * Check for hardware errors.
        !           647:      */
        !           648:     if (addr->csr & DDN_UER)
        !           649:       {
        !           650:        printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
        !           651:        addr->csr = 0;          /* disable i/f */
        !           652:        return;
        !           653:       }
        !           654: 
        !           655:     /*
        !           656:      * Get logical channel info.
        !           657:      */
        !           658:     if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
        !           659:       {
        !           660:        printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
        !           661:        return;
        !           662:       }
        !           663: 
        !           664:     if (chan & 0x01)
        !           665:        hc = &(ds->ddn_cb[chan/2].dc_wchan);
        !           666:     else
        !           667:        hc = &(ds->ddn_cb[chan/2].dc_rchan);
        !           668: 
        !           669:     type = addr->statyp;
        !           670:     cc = addr->stacc;
        !           671:     cnt = hc->hc_cnt - addr->stacnt;
        !           672: 
        !           673:     /* Figure out what kind of interrupt it was */
        !           674: 
        !           675:     switch(type)
        !           676:       {
        !           677:     case DDNSACK:              /* start i/o accepted */
        !           678:        if (hc != ds->ddn_sioq.sq_head)  /* does ack match waiting req? */
        !           679:          {
        !           680:            printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
        !           681:                unit, chan, hc, ds->ddn_sioq.sq_head);
        !           682:            addr->csr = 0;              /* disable UMC */
        !           683:            return;
        !           684:          }
        !           685: 
        !           686:        /* dequeue old request by copying link to queue head */
        !           687:        /*   and start next I/O request if queue has not gone empty */
        !           688: 
        !           689:        if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
        !           690:          {
        !           691:            start_chn(ds);
        !           692:          }
        !           693:        break;
        !           694: 
        !           695:     case DDNDONE:              /* i/o completion */
        !           696:        switch (cc)
        !           697:          {
        !           698:        case DDNIOCABT:         /* probably VCN flush */
        !           699:            break;
        !           700: 
        !           701:        case DDNIOCERR:
        !           702:            printf("ddn%d: program error ", unit);
        !           703:            goto daterr;
        !           704: 
        !           705:        case DDNIOCOVR:
        !           706:            printf("ddn%d: overrun error ", unit);
        !           707:            goto daterr;
        !           708: 
        !           709:        case DDNIOCUBE:
        !           710:            printf("ddn%d: NXM timeout or UB parity error ", unit);
        !           711: 
        !           712:        daterr:
        !           713:            printf("chan=%d func=%x\n", chan, hc->hc_func);
        !           714:            if (hc->hc_func & DDNRDB)
        !           715:                ds->ddn_if.if_ierrors++;
        !           716:            else
        !           717:                ds->ddn_if.if_oerrors++;
        !           718:          }
        !           719: 
        !           720:        /* was it supervisor or data traffic? */
        !           721: 
        !           722:        if (chan > 1)
        !           723:            ddn_data(unit, chan, cc, cnt);
        !           724:        else
        !           725:            ddn_supr(unit, chan, cc);
        !           726: 
        !           727:       }
        !           728: 
        !           729:     /*
        !           730:      * Ack the interrupt
        !           731:      */
        !           732:     addr->staack = 1;
        !           733:     if (!(addr->ionmi))
        !           734:       {
        !           735:        addr->ionmi = 1;
        !           736:        addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
        !           737:       }
        !           738:   }
        !           739: 
        !           740: 
        !           741: /***********************************************************************\
        !           742: *                              x25_init()                              *
        !           743: *************************************************************************
        !           744: *                                                                      *
        !           745: *      This routine builds and sends an X.25 initialization msg        *
        !           746: *      to the UMC.                                                     *
        !           747: *                                                                      *
        !           748: \***********************************************************************/
        !           749: 
        !           750: static void x25_init(ds)
        !           751: struct ddn_softc *ds;
        !           752:   {
        !           753:     struct mbuf *m;
        !           754: 
        !           755: #ifdef DDNDEBUG
        !           756: if (ddn_debug > 0)
        !           757:   {
        !           758: printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
        !           759:   }
        !           760: #endif DDNDEBUG
        !           761: 
        !           762:     MGET(m, M_DONTWAIT, MT_DATA);      /* try to get X25 init buffer */
        !           763:     if (m == 0)
        !           764:       {
        !           765:        printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
        !           766:        return;
        !           767:       }
        !           768: 
        !           769:     init_msg[3] = sizeof(init_msg) - 4;        /* set cmnd ext length */
        !           770: 
        !           771:     bcopy((caddr_t)init_msg, mtod(m, caddr_t), sizeof(init_msg));
        !           772: 
        !           773:     m->m_len = sizeof(init_msg);       /* set msg length */
        !           774: 
        !           775:     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
        !           776:     ddn_start(ds, &(ds->ddn_cb[0]));
        !           777:   }
        !           778: 
        !           779: 
        !           780: /***********************************************************************\
        !           781: *                      locate_x25_lcn()                                *
        !           782: *************************************************************************
        !           783: *                                                                      *
        !           784: *      This routine tries to locate an X25 LCN associated with a       *
        !           785: *      remote internet address.  A linear search of the LCN table      *
        !           786: *      is made for a matching address.  If the search succeeds, the    *
        !           787: *      LCN is returned.  If the search fails, the LCN table is         *
        !           788: *      searched for an unused table entry.  If an unused table entry   *
        !           789: *      is found, an X25 call is generated to the host specified in     *
        !           790: *      the destination internet address.  If no LCN is available,      *
        !           791: *      zero is returned.                                               *
        !           792: *                                                                      *
        !           793: \***********************************************************************/
        !           794: 
        !           795: static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
        !           796: struct ddn_softc *ds;
        !           797: struct in_addr ip_addr;
        !           798:   {
        !           799:     register int lcn;
        !           800:     register struct ddn_cb *dc;
        !           801: 
        !           802: #ifdef DDNDEBUG
        !           803: if (ddn_debug > 6)
        !           804:   {
        !           805: printf("locate_x25_lcn()\n");
        !           806:   }
        !           807: #endif DDNDEBUG
        !           808: 
        !           809:     dc = &(ds->ddn_cb[1]);
        !           810:     for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for addr match */
        !           811:       {
        !           812:        if (dc->dc_inaddr.s_addr == ip_addr.s_addr)     /* if found */
        !           813:            return(dc);                                 /*   return LCN */
        !           814:        dc++;
        !           815:       }
        !           816: 
        !           817:     dc = &(ds->ddn_cb[1]);
        !           818:     for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for free entry */
        !           819:       {
        !           820:        if (dc->dc_state == LC_IDLE)
        !           821:            break;
        !           822:        dc++;
        !           823:       }
        !           824: 
        !           825:     if (lcn > NDDNCH)                  /* if we didn't find a free entry */
        !           826:         return(0);                     /*   return empty handed */
        !           827: 
        !           828: 
        !           829:     if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
        !           830:       {                                        /*  addr can be converted */
        !           831:        dc->dc_inaddr.s_addr = ip_addr.s_addr;
        !           832:        return(dc);                     /*   and return the LCN */
        !           833:       }
        !           834:     else
        !           835:       {
        !           836:        return(0);                              /* give up */
        !           837:       }
        !           838:   }
        !           839: 
        !           840: 
        !           841: /***********************************************************************\
        !           842: *                      convert_ip_addr()                               *
        !           843: *************************************************************************
        !           844: *                                                                      *
        !           845: *      This routine accepts an internet address and attempts to        *
        !           846: *      translate to an equivalent X25 address.  For DDN this follows   *
        !           847: *      the guidelines in the DDN X25 interface spec.  The resultant    *
        !           848: *      X25 address is stored in the X25 called addr buffer.  The       *
        !           849: *      routine returns TRUE if successfull, FALSE otherwise.           *
        !           850: *                                                                      *
        !           851: *      NOTE: Although IF-11/X25 was designed to accept ASCII coded     *
        !           852: *      digits for the address fields, we only supply the binary        *
        !           853: *      values.  The front-end only uses the low four bits to extract   *
        !           854: *      the binary value from the ASCII digits, so this works out.      *
        !           855: *                                                                      *
        !           856: \***********************************************************************/
        !           857: 
        !           858: static boolean convert_ip_addr(ip_addr, x25addr)
        !           859: struct in_addr ip_addr;
        !           860: u_char x25addr[];
        !           861:   {
        !           862:     register int temp;
        !           863:     union {
        !           864:        struct in_addr ip;
        !           865:        struct {         /*   (assumes Class A network number) */
        !           866:            u_char s_net;
        !           867:            u_char s_host;
        !           868:            u_char s_lh;
        !           869:            u_char s_impno;
        !           870:        } imp;
        !           871:     } imp_addr;
        !           872: 
        !           873:     imp_addr.ip = ip_addr;
        !           874:     x25addr[0] = 14;           /* set addr length */
        !           875: 
        !           876:     x25addr[1] = 0;            /* clear DNIC */
        !           877:     x25addr[2] = 0;
        !           878:     x25addr[3] = 0;
        !           879:     x25addr[4] = 0;
        !           880: 
        !           881:     if (imp_addr.imp.s_host < 64)      /* Physical:  0000 0 IIIHH00 [SS] */
        !           882:       {                                        /*   s_impno -> III, s_host -> HH */
        !           883:        x25addr[5] = 0;         /* set flag bit */
        !           884:        x25addr[6] = imp_addr.imp.s_impno / 100;
        !           885:        x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
        !           886:        x25addr[8] = imp_addr.imp.s_impno % 10;
        !           887:        x25addr[9] = imp_addr.imp.s_host / 10;
        !           888:        x25addr[10] = imp_addr.imp.s_host % 10;
        !           889:       }
        !           890:     else                       /* Logical:   0000 1 RRRRR00 [SS]       */
        !           891:       {                                /*   s_host * 256 + s_impno -> RRRRR    */
        !           892:        temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
        !           893:        x25addr[5] = 1;
        !           894:        x25addr[6] = temp / 10000;
        !           895:        x25addr[7] = (temp % 10000) / 1000;
        !           896:        x25addr[8] = (temp % 1000) / 100;
        !           897:        x25addr[9] = (temp % 100) / 10;
        !           898:        x25addr[10] = temp % 10;
        !           899:       }
        !           900: 
        !           901:     x25addr[11] = 0;           /* clear rest of addr */
        !           902:     x25addr[12] = 0;
        !           903:     x25addr[13] = 0;
        !           904:     x25addr[14] = 0;
        !           905: 
        !           906: #ifdef DDNDEBUG
        !           907: if (ddn_debug > 4)
        !           908:   {
        !           909: printf("convert_ip_addr():  ");
        !           910: prt_addr(ip_addr);
        !           911: printf(" ==> ");
        !           912: prt_bytes(x25addr, 14);
        !           913: printf("\n");
        !           914:   }
        !           915: #endif DDNDEBUG
        !           916: 
        !           917:     return(1);
        !           918:   }
        !           919: 
        !           920: 
        !           921: /***********************************************************************\
        !           922: *                      convert_x25_addr()                              *
        !           923: *************************************************************************
        !           924: *                                                                      *
        !           925: *      This routine accepts an X25 address and attempts to translate   *
        !           926: *      to an equivalent internet address.  For DDN this follows the    *
        !           927: *      guidelines in the DDN X25 interface spec.  The resultant        *
        !           928: *      internet address is returned to the caller.                     *
        !           929: *                                                                      *
        !           930: \***********************************************************************/
        !           931: 
        !           932: static int convert_x25_addr(x25addr)
        !           933: u_char x25addr[];
        !           934:   {
        !           935:     register int cnt, temp;
        !           936:     union {
        !           937:        struct in_addr ip;
        !           938:        struct {         /*   (assumes Class A network number) */
        !           939:            u_char s_net;
        !           940:            u_char s_host;
        !           941:            u_char s_lh;
        !           942:            u_char s_impno;
        !           943:        } imp;
        !           944:     } imp_addr;
        !           945: 
        !           946:     if (((cnt = x25addr[0]) < 12) || (cnt > 14))
        !           947:       {
        !           948:        printf("DDN: illegal X25 address length!\n");
        !           949:        return(0);
        !           950:       }
        !           951: 
        !           952:     switch(x25addr[5] & 0x0f)
        !           953:       {
        !           954:     case 0:                    /* Physical:  0000 0 IIIHH00 [SS]       */
        !           955:        imp_addr.imp.s_impno =
        !           956:                ((int)(x25addr[6] & 0x0f) * 100) +
        !           957:                ((int)(x25addr[7] & 0x0f) * 10)  +
        !           958:                ((int)(x25addr[8] & 0x0f));
        !           959:        
        !           960: 
        !           961:        imp_addr.imp.s_host =
        !           962:                ((int)(x25addr[9] & 0x0f) * 10) +
        !           963:                ((int)(x25addr[10] & 0x0f));
        !           964:         break;
        !           965:     case 1:                    /* Logical:   0000 1 RRRRR00 [SS]       */
        !           966:        temp =    ((int)(x25addr[6] & 0x0f) * 10000)
        !           967:                + ((int)(x25addr[7] & 0x0f) * 1000)
        !           968:                + ((int)(x25addr[8] & 0x0f) * 100)
        !           969:                + ((int)(x25addr[9] & 0x0f) * 10)
        !           970:                + ((int)(x25addr[10] & 0x0f));
        !           971: 
        !           972:        imp_addr.imp.s_host = temp >> 8;
        !           973:        imp_addr.imp.s_impno = temp & 0xff;
        !           974:        break;
        !           975:     default:
        !           976:        printf("DDN: illegal X25 address format!\n");
        !           977:        return(0);
        !           978:       }
        !           979: 
        !           980:     imp_addr.imp.s_lh = 0;
        !           981:     imp_addr.imp.s_net = 0;
        !           982: 
        !           983: #ifdef DDNDEBUG
        !           984: if (ddn_debug > 4)
        !           985:   {
        !           986: printf("convert_x25_addr():  ");
        !           987: prt_bytes(&x25addr[1], cnt);
        !           988: printf(" ==> ");
        !           989: prt_addr(imp_addr.ip);
        !           990: printf("\n");
        !           991:   }
        !           992: #endif DDNDEBUG
        !           993: 
        !           994:     return(imp_addr.ip.s_addr);
        !           995:   }
        !           996: 
        !           997: 
        !           998: /***********************************************************************\
        !           999: *                      make_x25_call()                                 *
        !          1000: *************************************************************************
        !          1001: *                                                                      *
        !          1002: *      This routine places an X25 call using the X25 Call Msg          *
        !          1003: *      buffer.  The calling LCN is placed in the appropriate state     *
        !          1004: *      and a timer is started.                                         *
        !          1005: *                                                                      *
        !          1006: \***********************************************************************/
        !          1007: 
        !          1008: static boolean make_x25_call(ds, dc)
        !          1009: register struct ddn_softc *ds;
        !          1010: register struct ddn_cb *dc;
        !          1011:   {
        !          1012:     register struct mbuf *m_callbfr;
        !          1013:     register caddr_t cb;
        !          1014: 
        !          1015:     MGET(m_callbfr, M_DONTWAIT, MT_DATA);  /* try to get call cmnd buffer */
        !          1016:     if (m_callbfr == 0)
        !          1017:        return(0);
        !          1018: 
        !          1019:     cb = mtod(m_callbfr, caddr_t);
        !          1020: 
        !          1021:     (void)convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
        !          1022: 
        !          1023:     cb_protocol[0] = 4;
        !          1024:     cb_protocol[1] = X25_PROTO_IP;     /* protocol = IP */
        !          1025:     cb_protocol[2] = 0;
        !          1026:     cb_protocol[3] = 0;
        !          1027:     cb_protocol[4] = 0;
        !          1028: 
        !          1029:     cb_facilities[0] = 4;              /* number facility bytes */
        !          1030:     cb_facilities[1] = 0;              /*  options marker */
        !          1031:     cb_facilities[2] = 0;
        !          1032:     cb_facilities[3] = X25_FACIL_DDN;  /*  DDN standard mode */
        !          1033:     cb_facilities[4] = FAC_DDNSTD;
        !          1034: 
        !          1035:     cb_user_data[0] = 0;               /* no user data */
        !          1036: 
        !          1037:     cb_cmnd[0] = CALL;                 /* set command code */
        !          1038:     cb_cmnd[1] = dc->dc_lcn << 1;      /* set channel id */
        !          1039:     cb_cmnd[2] = 0;
        !          1040:     cb_cmnd[3] = (cb_called_addr[0] + 1) +     /* tally up cmnd ext length */
        !          1041:                 (cb_calling_addr[0] + 1) +
        !          1042:                 (cb_protocol[0] + 1) +
        !          1043:                 (cb_facilities[0] + 1) +
        !          1044:                 (cb_user_data[0] + 1);
        !          1045: 
        !          1046:     m_callbfr->m_len = cb_cmnd[3] + 4;
        !          1047: 
        !          1048:     /* copy command header */
        !          1049:     bcopy((caddr_t)cb_cmnd, cb, 4);
        !          1050:     cb += 4;
        !          1051: 
        !          1052:     /* copy called address */
        !          1053:     bcopy((caddr_t)cb_called_addr, cb, cb_called_addr[0] + 1);
        !          1054:     cb += (cb_called_addr[0] + 1);
        !          1055: 
        !          1056:     /* copy calling address */
        !          1057:     bcopy((caddr_t)cb_calling_addr, cb, cb_calling_addr[0] + 1);
        !          1058:     cb += (cb_calling_addr[0] + 1);
        !          1059: 
        !          1060:     /* copy protocol */
        !          1061:     bcopy((caddr_t)cb_protocol, cb, cb_protocol[0] + 1);
        !          1062:     cb += (cb_protocol[0] + 1);
        !          1063: 
        !          1064:     /* copy facilities */
        !          1065:     bcopy((caddr_t)cb_facilities, cb, cb_facilities[0] + 1);
        !          1066:     cb += (cb_facilities[0] + 1);
        !          1067: 
        !          1068:     /* copy user data */
        !          1069:     bcopy((caddr_t)cb_user_data, cb, cb_user_data[0] + 1);
        !          1070:     cb += (cb_user_data[0] + 1);
        !          1071: 
        !          1072:     dc->dc_state = LC_CALL_PENDING;            /* set state */
        !          1073:     dc->dc_timer = TMO_CALL_PENDING;           /* start call timeout */
        !          1074: 
        !          1075: #ifdef DDNDEBUG
        !          1076: if (ddn_debug > 3)
        !          1077:   {
        !          1078: printf("make_x25_call(): call_bfr = ");
        !          1079: prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
        !          1080: printf("\n");
        !          1081:   }
        !          1082: #endif DDNDEBUG
        !          1083: 
        !          1084:     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
        !          1085:     ddn_start(ds, &(ds->ddn_cb[0]));
        !          1086: 
        !          1087:     return(1);
        !          1088:   }
        !          1089: 
        !          1090: 
        !          1091: /***********************************************************************\
        !          1092: *                              ddn_start()                             *
        !          1093: *************************************************************************
        !          1094: *                                                                      *
        !          1095: *      This routine attempts to start output of data queued on a       *
        !          1096: *      specific LCN.  If the LCN was not already busy and data is      *
        !          1097: *      available for output, the data is copied into the LCN's I/O     *
        !          1098: *      buffer and an I/O request queued to the UMC.                    *
        !          1099: *                                                                      *
        !          1100: \***********************************************************************/
        !          1101: 
        !          1102: static void ddn_start(ds, dc)
        !          1103: register struct ddn_softc *ds;
        !          1104: register struct ddn_cb *dc;
        !          1105:   {
        !          1106:     register struct mbuf *m;
        !          1107:     int len;
        !          1108: 
        !          1109:     /*
        !          1110:      * If output isn't active, attempt to
        !          1111:      * start sending a new packet.
        !          1112:      */
        !          1113: 
        !          1114:     if ((dc->dc_flags & DC_OBUSY) ||
        !          1115:        (dc->dc_oq.ifq_len == 0) ||
        !          1116:        ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
        !          1117:       {
        !          1118:        return;
        !          1119:       }
        !          1120: 
        !          1121:     IF_DEQUEUE(&dc->dc_oq, m);
        !          1122: 
        !          1123:     len = if_wubaput(&dc->dc_ifuba, m);        /* copy data to mapped mem */
        !          1124:     dc->dc_flags |= DC_OBUSY;
        !          1125: 
        !          1126:     ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
        !          1127:   }
        !          1128: 
        !          1129: 
        !          1130: /***********************************************************************\
        !          1131: *                              ddn_iorq()                              *
        !          1132: *************************************************************************
        !          1133: *                                                                      *
        !          1134: *      This routine builds UMC I/O requests and queues them for        *
        !          1135: *      delivery to the UMC. If the UMC I/O request comm regs are       *
        !          1136: *      not busy, the I/O request is passed to the UMC.                 *
        !          1137: *                                                                      *
        !          1138: \***********************************************************************/
        !          1139: 
        !          1140: static void ddn_iorq(ds, dc, len, func)
        !          1141: struct ddn_softc *ds;
        !          1142: struct ddn_cb *dc;
        !          1143: int len, func;
        !          1144:   {
        !          1145:     register struct hdx_chan *hc;
        !          1146:     register int info;
        !          1147: 
        !          1148: 
        !          1149:     /* get appropriate UNIBUS mapping info */
        !          1150: 
        !          1151:     if (func & DDNRDB)         /* read or write? */
        !          1152:       {
        !          1153:        hc = &dc->dc_rchan;
        !          1154:        info = dc->dc_ifuba.ifu_r.ifrw_info;
        !          1155:       }
        !          1156:     else
        !          1157:       {
        !          1158:        hc = &dc->dc_wchan;
        !          1159:        info = dc->dc_ifuba.ifu_w.ifrw_info;
        !          1160:       }
        !          1161: 
        !          1162:     /* set channel info */
        !          1163: 
        !          1164:     hc->hc_adx = (u_char)((info & 0x30000) >> 12);
        !          1165:     hc->hc_addr = (u_short)(info & 0xffff);
        !          1166:     hc->hc_cnt = len;
        !          1167:     hc->hc_func = (u_char)func;
        !          1168:     hc->hc_sbfc = 0;
        !          1169: 
        !          1170:     /*
        !          1171:      * If UMC comm regs busy, queue start i/o for later.
        !          1172:      */
        !          1173:     if (ds->ddn_sioq.sq_head)
        !          1174:       {
        !          1175:        (ds->ddn_sioq.sq_tail)->hc_next = hc;
        !          1176:        ds->ddn_sioq.sq_tail = hc;
        !          1177:        hc->hc_next = 0;
        !          1178:        return;
        !          1179:       }
        !          1180: 
        !          1181:     /* start i/o on channel now */
        !          1182: 
        !          1183:     ds->ddn_sioq.sq_head = hc;
        !          1184:     ds->ddn_sioq.sq_tail = hc;
        !          1185:     hc->hc_next = 0;
        !          1186:     start_chn(ds);
        !          1187:   }
        !          1188: 
        !          1189: 
        !          1190: /***********************************************************************\
        !          1191: *                              start_chn()                             *
        !          1192: *************************************************************************
        !          1193: *                                                                      *
        !          1194: *      This routine copies UMC I/O requests into the UMC comm regs     *
        !          1195: *      and notifies the UMC.                                           *
        !          1196: *                                                                      *
        !          1197: \***********************************************************************/
        !          1198: 
        !          1199: static void start_chn(ds)
        !          1200: struct ddn_softc *ds;
        !          1201:   {
        !          1202:     register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
        !          1203:     register struct ddnregs *addr =
        !          1204:        (struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
        !          1205: 
        !          1206:     /*
        !          1207:      * Set up comm regs.
        !          1208:      */
        !          1209:     addr->iochn = hc->hc_chan;
        !          1210:     addr->ioadx = hc->hc_adx;
        !          1211:     addr->ioadl = hc->hc_addr;
        !          1212:     addr->iocnt = hc->hc_cnt;
        !          1213:     addr->iofcn = hc->hc_func;
        !          1214:     addr->iosbf = hc->hc_sbfc;
        !          1215:     addr->ioini = 1;
        !          1216: 
        !          1217:     /* signal UMC if necessary */
        !          1218: 
        !          1219:     if (!(addr->ionmi))
        !          1220:       {
        !          1221:        addr->ionmi = 1;
        !          1222:        addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
        !          1223:       }
        !          1224:   }
        !          1225: 
        !          1226: 
        !          1227: /***********************************************************************\
        !          1228: *                              ddn_data()                              *
        !          1229: *************************************************************************
        !          1230: *                                                                      *
        !          1231: *      This routine is called when a data channel I/O completes.       *
        !          1232: *      If the completion was for a write, an attempt is made to        *
        !          1233: *      start output on the next packet waiting for output on that      *
        !          1234: *      LCN.  If the completion was for a read, the received packet     *
        !          1235: *      is sent to the IP input queue (if no error) and another read    *
        !          1236: *      is started on the LCN.                                          *
        !          1237: *                                                                      *
        !          1238: \***********************************************************************/
        !          1239: 
        !          1240: static void ddn_data(unit, chan, cc, rcnt)
        !          1241: int unit, chan, cc, rcnt;
        !          1242: {
        !          1243:     register struct ddn_softc *ds = &ddn_softc[unit];
        !          1244:     register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
        !          1245:     register struct ifqueue *inq = &ipintrq;
        !          1246:     register struct mbuf *m;
        !          1247: 
        !          1248:     if (chan & 0x01)                   /* was it read or write? */     
        !          1249:       {                                        /*   write, fire up next output */
        !          1250:        ds->ddn_if.if_opackets++;
        !          1251:        dc->dc_flags &= ~DC_OBUSY;
        !          1252:        ddn_start(ds, dc);
        !          1253:       }
        !          1254:     else                               /*   read, process rcvd packet */
        !          1255:       {
        !          1256:        if (cc == DDNIOCOK)
        !          1257:          {                             /* Queue good packet for input */
        !          1258:            ds->ddn_if.if_ipackets++;
        !          1259:            dc->dc_state = LC_DATA_IDLE;
        !          1260:            dc->dc_timer = TMO_DATA_IDLE;
        !          1261:            m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
        !          1262:            if (m)
        !          1263:              {
        !          1264:                if (IF_QFULL(inq))
        !          1265:                  {
        !          1266:                    IF_DROP(inq);
        !          1267:                    m_freem(m);
        !          1268:                  }
        !          1269:                else
        !          1270:                  {
        !          1271:                    IF_ENQUEUE(inq, m);
        !          1272:                    schednetisr(NETISR_IP);
        !          1273:                  }
        !          1274:              }
        !          1275:          }
        !          1276: 
        !          1277:        /* hang a new data read */
        !          1278: 
        !          1279:        ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
        !          1280: 
        !          1281:       }
        !          1282:   }
        !          1283: 
        !          1284: 
        !          1285: /***********************************************************************\
        !          1286: *                              ddn_supr()                              *
        !          1287: *************************************************************************
        !          1288: *                                                                      *
        !          1289: *      This routine is called when a supervisor I/O completes.         *
        !          1290: *      If the completion was for a write, an attempt is made to        *
        !          1291: *      start output on the next supervisor command waiting for         *
        !          1292: *      output.  If the completion was for a read, the received         *
        !          1293: *      supervisor message is processed and another read is started.    *
        !          1294: *                                                                      *
        !          1295: \***********************************************************************/
        !          1296: 
        !          1297: static void ddn_supr(unit, chan, cc)
        !          1298: int unit, chan, cc;
        !          1299: {
        !          1300:     register struct ddn_softc *ds = &ddn_softc[unit];
        !          1301:     u_char *p;
        !          1302: 
        !          1303:     /* was it read or write? */
        !          1304: 
        !          1305:     if (chan & 0x01)
        !          1306:       {
        !          1307:        ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
        !          1308:        ddn_start(ds, &(ds->ddn_cb[0]));
        !          1309:       }
        !          1310:     else
        !          1311:       {
        !          1312:        if (cc == DDNIOCOK)
        !          1313:          {
        !          1314:            p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
        !          1315: 
        !          1316:            /* process supervisor message */
        !          1317: 
        !          1318:            supr_msg(ds, p);
        !          1319: 
        !          1320:          }
        !          1321: 
        !          1322:        /* hang a new supr read */
        !          1323: 
        !          1324:        ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
        !          1325:       }
        !          1326:   }
        !          1327: 
        !          1328: 
        !          1329: /***********************************************************************\
        !          1330: *                              supr_msg()                              *
        !          1331: *************************************************************************
        !          1332: *                                                                      *
        !          1333: *      This routine processes received supervisor messages.            *
        !          1334: *      Depending on the message type, the appropriate action is        *
        !          1335: *      taken.
        !          1336: *                                                                      *
        !          1337: \***********************************************************************/
        !          1338: 
        !          1339: static void supr_msg(ds, p)
        !          1340: struct ddn_softc *ds;
        !          1341: u_char p[];
        !          1342:   {
        !          1343:     register struct ddn_cb *dc;
        !          1344:     register int lcn;
        !          1345:     register struct mbuf *m;
        !          1346: 
        !          1347: #ifdef DDNDEBUG
        !          1348: if (ddn_debug > 5)
        !          1349:   {
        !          1350: printf("supr_msg():  ");
        !          1351: prt_bytes(p, 4+p[3]);
        !          1352: printf("\n");
        !          1353:   }
        !          1354: #endif DDNDEBUG
        !          1355: 
        !          1356:     switch (p[0])
        !          1357:       {
        !          1358:     case LINE_STATUS:                  /*   link status msg */
        !          1359:        if (p[2] == LINK_UP)            /*   if link came up */
        !          1360:          {
        !          1361:            send_restart(ds);           /*     send restart msg */
        !          1362:          }
        !          1363:        else                            /*   if link went down */
        !          1364:          {
        !          1365:            ds->ddn_if.if_flags &= ~IFF_UP;
        !          1366:            dc = ds->ddn_cb;
        !          1367:            for(lcn = 0; lcn <= NDDNCH; lcn++) /*    for all LCN's */
        !          1368:              {
        !          1369:                dc->dc_state = LC_DOWN;  /* set state */
        !          1370:                dc->dc_timer = TMO_OFF;  /* stop timer */
        !          1371:                dc++;
        !          1372:              }
        !          1373:          }
        !          1374:        break;
        !          1375: 
        !          1376:     case RESTART:                      /* restart received */
        !          1377:        if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
        !          1378:            send_supr(ds, RSTRT_ACK, 0, 0);    /*   send restart ack */
        !          1379:        /* fall thru */
        !          1380:     case RSTRT_ACK:                    /* restart ack */
        !          1381:        ds->ddn_if.if_flags |= IFF_UP;
        !          1382:        dc = ds->ddn_cb;
        !          1383:        for(lcn = 0; lcn <= NDDNCH; lcn++)      /* for all LCN's */
        !          1384:          {
        !          1385:            dc->dc_state = LC_IDLE;   /* set state */
        !          1386:            dc->dc_timer = TMO_OFF;   /* stop timer */
        !          1387:            dc->dc_inaddr.s_addr = 0; /* forget address */
        !          1388:            while (dc->dc_oq.ifq_len) /* drop pending data */
        !          1389:              {
        !          1390:                IF_DEQUEUE(&dc->dc_oq, m);
        !          1391:                m_freem(m);
        !          1392:              }
        !          1393:            dc++;
        !          1394:          }
        !          1395:        break;
        !          1396: 
        !          1397:     case ANSWER:                       /* call answered */
        !          1398:        lcn = p[1] / 2;
        !          1399:        dc = &(ds->ddn_cb[lcn]);
        !          1400:        if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
        !          1401:          {
        !          1402:            dc->dc_state = LC_DATA_IDLE;  /* set state */
        !          1403:            dc->dc_timer = TMO_DATA_IDLE; /* start timer */
        !          1404:            ddn_start(ds, dc);            /* try to send data */
        !          1405:          }
        !          1406:        break;
        !          1407: 
        !          1408:     case RING:                         /* incoming call */
        !          1409:        for(lcn = NDDNCH; lcn > 0; lcn--)       /* search LCN's */
        !          1410:          {
        !          1411:            if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
        !          1412:                break;
        !          1413:          }
        !          1414: 
        !          1415:        if (lcn && decode_ring(p))      /* if a free LCN found */
        !          1416:                                        /*   and ring looks ok */
        !          1417:          {
        !          1418:            dc = &(ds->ddn_cb[lcn]);
        !          1419:            dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
        !          1420:            dc->dc_state = LC_DATA_IDLE;  /* set state */
        !          1421:            dc->dc_timer = TMO_DATA_IDLE; /* start timer */
        !          1422:            send_supr(ds, ANSWER, lcn * 2, (int)p[2]); /* send answer */
        !          1423:          }
        !          1424:        else                            /* if no free LCN's */
        !          1425:          {
        !          1426:            send_supr(ds, CLEARVC, (int)p[2], 0); /* clear call */
        !          1427:          }
        !          1428:        break;
        !          1429: 
        !          1430:     case CLEARLC:                      /* clear by LCN */
        !          1431:        lcn = p[1] / 2;                 /* get LCN */
        !          1432:        dc = &(ds->ddn_cb[lcn]);
        !          1433:        if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
        !          1434:          {
        !          1435:            send_supr(ds, CLEARLC, (int)p[1], 0);      /*   ack the clear */
        !          1436:          }
        !          1437:        dc->dc_state = LC_IDLE; /* set state */
        !          1438:        dc->dc_timer = TMO_OFF; /* stop timer */
        !          1439:        dc->dc_inaddr.s_addr = 0; /* forget address */
        !          1440:        while (dc->dc_oq.ifq_len) /* drop pending data */
        !          1441:          {
        !          1442:            IF_DEQUEUE(&dc->dc_oq, m);
        !          1443:            m_freem(m);
        !          1444:          }
        !          1445:        break;
        !          1446: 
        !          1447:     case CLEARVC:                      /* clear by VCN */
        !          1448:        send_supr(ds, CLEARVC, (int)p[1], 0); /* send clear ack */
        !          1449:        break;
        !          1450: 
        !          1451:     case RESET:                                /* X25 reset */
        !          1452:        send_supr(ds, RESET_ACK, (int)p[1], 0); /* send reset ack */
        !          1453:        printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
        !          1454:        break;
        !          1455: 
        !          1456:     case INTERRUPT:                    /* X25 interrupt */
        !          1457:        printf("X25 INTERRUPT on lcn = %d, code = %d\n",        /* log it */
        !          1458:            p[1] / 2, p[2]);
        !          1459:        break;
        !          1460: 
        !          1461:     default:
        !          1462:        printf("ddn%d: supervisor error, code=%x\n",
        !          1463:           ds->ddn_if.if_unit, p[0]);
        !          1464:       }
        !          1465:   }
        !          1466: 
        !          1467: 
        !          1468: /***********************************************************************\
        !          1469: *                              decode_ring()                           *
        !          1470: *************************************************************************
        !          1471: *                                                                      *
        !          1472: *      This routine parses and validates the incoming call msg.        *
        !          1473: *                                                                      *
        !          1474: \***********************************************************************/
        !          1475: 
        !          1476: static boolean decode_ring(p)
        !          1477: register u_char *p;
        !          1478:   {
        !          1479:     register int cnt;
        !          1480: 
        !          1481: #ifdef DDNDEBUG
        !          1482: if (ddn_debug > 3)
        !          1483:   {
        !          1484: printf("decode_ring()\n");
        !          1485:   }
        !          1486: #endif DDNDEBUG
        !          1487: 
        !          1488: 
        !          1489:     p += 3;                    /* skip to cmnd ext length */
        !          1490:     if (*p++ < 5)              /* is count appropriate */
        !          1491:        return(0);              /*   return false if not */
        !          1492: 
        !          1493:     /* called address */
        !          1494:     if ((cnt = *p + 1) > 16)   /* is called addr len legal? */
        !          1495:        return(0);              /*   return false if not */
        !          1496:     bcopy((caddr_t)p, (caddr_t)cb_called_addr, (unsigned)cnt); /* copy field */
        !          1497:     p += cnt;
        !          1498: 
        !          1499:     /* calling address */
        !          1500:     if ((cnt = *p + 1) > 16)   /* is calling addr len legal? */
        !          1501:        return(0);              /*   return false if not */
        !          1502:     bcopy((caddr_t)p, (caddr_t)cb_calling_addr, (unsigned)cnt); /* copy field */
        !          1503:     p += cnt;
        !          1504: 
        !          1505:     /* protocol part of user data */
        !          1506:     if ((cnt = *p + 1) > 5)    /* is protocol len legal? */
        !          1507:        return(0);              /*   return false if not */
        !          1508:     bcopy((caddr_t)p, (caddr_t)cb_protocol, (unsigned)cnt); /* copy field */
        !          1509:     p += cnt;
        !          1510: 
        !          1511:     /* facilities */
        !          1512:     if ((cnt = *p + 1) > 64)   /* is facilities len legal? */
        !          1513:        return(0);              /*   return false if not */
        !          1514:     bcopy((caddr_t)p, (caddr_t)cb_facilities, (unsigned)cnt); /* copy field */
        !          1515:     p += cnt;
        !          1516: 
        !          1517:     /* ignore rest of user data for now */
        !          1518: 
        !          1519:     if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
        !          1520:        return(0);              /* bad if not IP */
        !          1521: 
        !          1522:     return(1);                 /* looks ok */
        !          1523:   }
        !          1524: 
        !          1525: 
        !          1526: /***********************************************************************\
        !          1527: *                              clear_lcn()                             *
        !          1528: *************************************************************************
        !          1529: *                                                                      *
        !          1530: *      This routine clears an X25 circuit and releases any buffers     *
        !          1531: *      queued for transmission.                                        *
        !          1532: *                                                                      *
        !          1533: \***********************************************************************/
        !          1534: 
        !          1535: static void clear_lcn(ds, dc)
        !          1536: struct ddn_softc *ds;
        !          1537: struct ddn_cb *dc;
        !          1538:   {
        !          1539:     register struct mbuf *m;
        !          1540: 
        !          1541: #ifdef DDNDEBUG
        !          1542: if (ddn_debug > 3)
        !          1543:   {
        !          1544: printf("clear_lcn(%d)\n", dc->dc_lcn);
        !          1545:   }
        !          1546: #endif DDNDEBUG
        !          1547: 
        !          1548:     dc->dc_state = LC_CLR_PENDING;  /* set state */
        !          1549:     dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
        !          1550:     dc->dc_inaddr.s_addr = 0;      /* clear associated address */
        !          1551:     while (dc->dc_oq.ifq_len)      /* drop any pending data */
        !          1552:       {
        !          1553:        IF_DEQUEUE(&dc->dc_oq, m);
        !          1554:        m_freem(m);
        !          1555:       }
        !          1556:     send_supr(ds, CLEARLC, (int)dc->dc_lcn * 2, 0);    /* send clear msg */
        !          1557:   }
        !          1558: 
        !          1559: 
        !          1560: /***********************************************************************\
        !          1561: *                              send_restart()                          *
        !          1562: *************************************************************************
        !          1563: *                                                                      *
        !          1564: *      This routine marks all LCNs as being in a restarting state      *
        !          1565: *      and sends a restart command to X25.                             *
        !          1566: *                                                                      *
        !          1567: \***********************************************************************/
        !          1568: 
        !          1569: static void send_restart(ds)
        !          1570: struct ddn_softc *ds;
        !          1571:   {
        !          1572:     register struct ddn_cb *dc;
        !          1573:     register int lcn;
        !          1574:     struct mbuf *m;
        !          1575: 
        !          1576: #ifdef DDNDEBUG
        !          1577: if (ddn_debug > 1)
        !          1578:   {
        !          1579: printf("send_restart()\n");
        !          1580:   }
        !          1581: #endif DDNDEBUG
        !          1582:     dc = ds->ddn_cb;
        !          1583:     for(lcn = 0; lcn <= NDDNCH; lcn++)     /* for all LCN's */
        !          1584:       {
        !          1585:        dc->dc_state = LC_RESTART;  /* set state */
        !          1586:        dc->dc_timer = TMO_RESTART; /* start restart timeout */
        !          1587:        dc->dc_inaddr.s_addr = 0;     /* forget address */
        !          1588:        while (dc->dc_oq.ifq_len)       /* drop any pending data */
        !          1589:          {
        !          1590:            IF_DEQUEUE(&dc->dc_oq, m);
        !          1591:            m_freem(m);
        !          1592:          }
        !          1593:        dc++;
        !          1594:       }
        !          1595: 
        !          1596:     send_supr(ds, RESTART, 0, 0);          /* send restart msg */
        !          1597:   }
        !          1598: 
        !          1599: 
        !          1600: /***********************************************************************\
        !          1601: *                              send_supr()                             *
        !          1602: *************************************************************************
        !          1603: *                                                                      *
        !          1604: *      This routine is used to send short (4 bytes only) supervisor    *
        !          1605: *      commands.                                                       *
        !          1606: *                                                                      *
        !          1607: \***********************************************************************/
        !          1608: 
        !          1609: static void send_supr(ds, cmd, p1, p2)
        !          1610: struct ddn_softc *ds;
        !          1611: int cmd, p1, p2;
        !          1612:   {
        !          1613:     struct mbuf *m;
        !          1614:     register u_char *cp;
        !          1615: 
        !          1616: #ifdef DDNDEBUG
        !          1617: if (ddn_debug > 6)
        !          1618:   {
        !          1619: printf("send_supr():  %x %x %x\n", cmd, p1, p2);
        !          1620:   }
        !          1621: #endif DDNDEBUG
        !          1622: 
        !          1623:     MGET(m, M_DONTWAIT, MT_DATA);
        !          1624: 
        !          1625:     if (m == 0)
        !          1626:       {
        !          1627:        printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
        !          1628:        return;
        !          1629:       }
        !          1630: 
        !          1631:     cp = mtod(m, u_char *);
        !          1632: 
        !          1633:     /* build supervisor message */
        !          1634: 
        !          1635:     *cp++ = (byte)cmd;
        !          1636:     *cp++ = (byte)p1;
        !          1637:     *cp++ = (byte)p2;
        !          1638:     *cp++ = 0;
        !          1639: 
        !          1640:     m->m_len = 4;
        !          1641: 
        !          1642:     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
        !          1643:     ddn_start(ds, &(ds->ddn_cb[0]));
        !          1644: 
        !          1645:   }
        !          1646: 
        !          1647: 
        !          1648: #ifdef DDNDEBUG
        !          1649: 
        !          1650: /***********************************************************************\
        !          1651: *                              prt_addr()                              *
        !          1652: *************************************************************************
        !          1653: *                                                                      *
        !          1654: *      This routine is used to print internet addresses in the         *
        !          1655: *      standard A.B.C.D format.                                        *
        !          1656: *                                                                      *
        !          1657: \***********************************************************************/
        !          1658: 
        !          1659: static void prt_addr(addr)
        !          1660: struct in_addr addr;
        !          1661:   {
        !          1662:     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
        !          1663:   }
        !          1664: 
        !          1665: /***********************************************************************\
        !          1666: *                              prt_bytes()                             *
        !          1667: *************************************************************************
        !          1668: *                                                                      *
        !          1669: *      This routine is used to print a string of bytes in hex.         *
        !          1670: *                                                                      *
        !          1671: \***********************************************************************/
        !          1672: 
        !          1673: static void prt_bytes(bp, cnt)
        !          1674: u_char *bp;
        !          1675: int cnt;
        !          1676:   {
        !          1677:     while(cnt--)
        !          1678:       {
        !          1679:        printf(" %x", *bp++ & 0xff);
        !          1680:       }
        !          1681:   }
        !          1682: 
        !          1683: #endif DDNDEBUG
        !          1684: 
        !          1685: #endif NDDN

unix.superglobalmegacorp.com

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