# 2.11BSD#431 - /usr/src/sys/vaxif/if_ddn.c

##### Functions

    ddnattach         X
    ddninit           X
    ddnintr           X
    ddnioctl          X
    ddnoutput         X
    ddnprobe          X
    ddnreset          X
    ddntimer          X

##### Variables

    cb_called_addr    X
    cb_calling_addr   X
    cb_cmnd           X
    cb_facilities     X
    cb_protocol       X
    cb_user_data      X
    ddn_debug         X
    ddn_softc         X
    ddndriver         X
    ddninfo           X
    ddnstd            X

##### Macros

    INIT_DELAY        X

##### struct's

    ddn_cb            X
    ddn_softc         X
    hdx_chan          X
    sioq              X

       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

#### Defined functions

clear_lcn defined in line 1535; used 2 times

- in line 124, 576

convert_ip_addr defined in line 858; used 3 times

- in line 114, 829, 1021

convert_x25_addr defined in line 932; used 2 times

- in line 115, 1419

ddn_data defined in line 1240; used 2 times

- in line 120, 723

ddn_iorq defined in line 1140; used 5 times

- in line 118, 439, 1126, 1279, 1324

ddn_start defined in line 1102; used 8 times

- in line 117, 519, 776, 1085, 1252, 1308, 1404, 1643

ddn_supr defined in line 1297; used 2 times

- in line 121, 725

ddnattach defined in line 306; used 2 times

- in line 102, 139

ddninit defined in line 371; used 4 times

- in line 104, 315, 356, 610

ddnintr defined in line 637; used 2 times

- in line 108, 277

ddnioctl defined in line 595; used 2 times

- in line 107, 316

ddnoutput defined in line 463; used 2 times

- in line 105, 317

ddnprobe defined in line 269; used 2 times

- in line 101, 137

ddnreset defined in line 333; used 2 times

- in line 103, 318

ddntimer defined in line 545; used 3 times

- in line 106, 319, 447

decode_ring defined in line 1476; used 2 times

- in line 123, 1415

locate_x25_lcn defined in line 795; used 2 times

- in line 113, 506

make_x25_call defined in line 1008; used 2 times

- in line 116, 829

prt_addr defined in line 1659; used 4 times

- in line 128, 497, 910, 989

prt_bytes defined in line 1673; used 5 times

- in line 129, 912, 987, 1079, 1351

send_restart defined in line 1569; used 3 times

- in line 125, 571, 1361

send_supr defined in line 1609; used 9 times

- in line 126, 1378, 1422-1426(2), 1435, 1448-1452(2), 1556, 1596

start_chn defined in line 1199; used 3 times

- in line 119, 691, 1186

supr_msg defined in line 1339; used 2 times

- in line 122, 1318

x25_init defined in line 750; used 2 times

- in line 112, 443

#### Defined variables

cb_called_addr defined in line 171; used 6 times

- in line 829, 1040, 1053-1054(3), 1496

cb_calling_addr defined in line 173; used 7 times

- in line 1021, 1041, 1057-1058(3), 1419, 1502

cb_cmnd defined in line 163; used 6 times

- in line 1037-1040(4), 1046-1049(2)

cb_facilities defined in line 175; used 10 times

- in line 1029-1033(5), 1043, 1065-1066(3), 1514

cb_protocol defined in line 177; used 12 times

- in line 1023-1027(5), 1042, 1061-1062(3), 1508, 1519(2)

cb_user_data defined in line 179; used 5 times

- in line 1035, 1044, 1069-1070(3)

ddn_debug defined in line 182; used 13 times

- in line 380, 494, 553, 756, 803, 907, 984, 1076, 1348, 1482, 1542, 1577, 1617

ddn_softc defined in line 243; used 9 times

- in line 309, 351, 374, 469, 548, 611, 640, 1243, 1300

ddndriver defined in line 135; never used
ddninfo defined in line 133; used 5 times

- in line 143, 340, 376, 642, 1204

ddnstd defined in line 134; used 1 times

- in line 141

init_msg defined in line 146; used 5 times

- in line 769-773(5)

savevec defined in line 267; used 2 times

- in line 280, 311

#### Defined struct's

ddn_cb defined in line 222; used 27 times

- in line 113, 238(2), 375(2), 470(2), 549(2), 795-800(4), 1010(2), 1104(2), 1142(2), 1244(2), 1343(2), 1537(2), 1572(2)

ddn_softc defined in line 235; used 34 times

- in line 309(2), 374(2), 469(2), 548(2), 640(2), 751(2), 796(2), 1009(2), 1103(2), 1141(2), 1200(2), 1243(2), 1300(2), 1340(2), 1536(2), 1570(2), 1610(2)

hdx_chan defined in line 211; used 22 times

- in line 207-213(4), 229-230(4), 408-410(4), 429-430(4), 641(2), 1145(2), 1202(2)

sioq defined in line 205; used 2 times

- in line 239(2)

#### Defined macros

INIT_DELAY defined in line 264; used 2 times

- in line 289, 353

Last modified: 1986-06-06 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 295 |