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