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