Annotation of 43BSD/sys/vaxif/if_ddn.c, revision 1.1.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.