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
convert_ip_addr defined in line 858; used 3 times
convert_x25_addr defined in line 932; used 2 times
ddn_data defined in line 1240; used 2 times
ddn_iorq defined in line 1140; used 5 times
ddn_start defined in line 1102; used 8 times
ddn_supr defined in line 1297; used 2 times
ddnattach defined in line 306; used 2 times
ddninit defined in line 371; used 4 times
ddnintr defined in line 637; used 2 times
ddnioctl defined in line 595; used 2 times
ddnoutput defined in line 463; used 2 times
ddnprobe defined in line 269; used 2 times
ddnreset defined in line 333; used 2 times
ddntimer defined in line 545; used 3 times
decode_ring defined in line 1476; used 2 times
locate_x25_lcn defined in line 795; used 2 times
make_x25_call defined in line 1008; used 2 times
prt_addr defined in line 1659; used 4 times
prt_bytes defined in line 1673; used 5 times
send_restart defined in line 1569; used 3 times
send_supr defined in line 1609; used 9 times
start_chn defined in line 1199; used 3 times
supr_msg defined in line 1339; used 2 times
x25_init defined in line 750; used 2 times

Defined variables

cb_called_addr defined in line 171; used 6 times
cb_calling_addr defined in line 173; used 7 times
cb_cmnd defined in line 163; used 6 times
cb_facilities defined in line 175; used 10 times
cb_protocol defined in line 177; used 12 times
cb_user_data defined in line 179; used 5 times
ddn_debug defined in line 182; used 13 times
ddn_softc defined in line 243; used 9 times
ddndriver defined in line 135; never used
ddninfo defined in line 133; used 5 times
ddnstd defined in line 134; used 1 times
init_msg defined in line 146; used 5 times
savevec defined in line 267; used 2 times

Defined struct's

ddn_cb defined in line 222; used 27 times
ddn_softc defined in line 235; used 34 times
hdx_chan defined in line 211; used 22 times
sioq defined in line 205; used 2 times
  • in line 239(2)

Defined macros

INIT_DELAY defined in line 264; used 2 times
Last modified: 1986-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4271
Valid CSS Valid XHTML 1.0 Strict