1 /* @(#)if_ddn.c 6.3 (Berkeley) 12/19/85 */ 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; 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 struct endevice *enaddr; 603 604 switch (cmd) { 605 606 case SIOCSIFADDR: 607 if (ifa->ifa_addr.sa_family != AF_INET) 608 return(EINVAL); 609 ifp->if_flags |= IFF_UP; 610 if ((ifp->if_flags & IFF_RUNNING) == 0) 611 ddninit(ifp->if_unit); 612 ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr; 613 break; 614 615 default: 616 error = EINVAL; 617 break; 618 } 619 splx(s); 620 return (error); 621 } 622 623 624 /***********************************************************************\ 625 * ddnintr() * 626 ************************************************************************* 627 * * 628 * This is the interrupt handler for UNIBUS interrupts from the * 629 * UMC. The interrupting HDX channel and interrupt type are * 630 * obtained from the completion comm regs. If the interrupt is * 631 * an I/O request acknowledge, the next I/O request is passed * 632 * to the UMC. If the interrupt is an I/O completion, the * 633 * completion is processed depending on whether it is for the * 634 * supervisor or a data channel. * 635 * * 636 \***********************************************************************/ 637 638 ddnintr(unit) 639 int unit; 640 { 641 register struct ddn_softc *ds = &ddn_softc[unit]; 642 register struct hdx_chan *hc; 643 register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr; 644 int chan, type, cc, cnt; 645 646 /* 647 * Check for hardware errors. 648 */ 649 if (addr->csr & DDN_UER) 650 { 651 printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS); 652 addr->csr = 0; /* disable i/f */ 653 return; 654 } 655 656 /* 657 * Get logical channel info. 658 */ 659 if ((chan = addr->stachn) >= ((NDDNCH+1)*2)) 660 { 661 printf("ddn%d: unknown channel, chan=%d\n", unit, chan); 662 return; 663 } 664 665 if (chan & 0x01) 666 hc = &(ds->ddn_cb[chan/2].dc_wchan); 667 else 668 hc = &(ds->ddn_cb[chan/2].dc_rchan); 669 670 type = addr->statyp; 671 cc = addr->stacc; 672 cnt = hc->hc_cnt - addr->stacnt; 673 674 /* Figure out what kind of interrupt it was */ 675 676 switch(type) 677 { 678 case DDNSACK: /* start i/o accepted */ 679 if (hc != ds->ddn_sioq.sq_head) /* does ack match waiting req? */ 680 { 681 printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n", 682 unit, chan, hc, ds->ddn_sioq.sq_head); 683 addr->csr = 0; /* disable UMC */ 684 return; 685 } 686 687 /* dequeue old request by copying link to queue head */ 688 /* and start next I/O request if queue has not gone empty */ 689 690 if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next) 691 { 692 start_chn(ds); 693 } 694 break; 695 696 case DDNDONE: /* i/o completion */ 697 switch (cc) 698 { 699 case DDNIOCABT: /* probably VCN flush */ 700 break; 701 702 case DDNIOCERR: 703 printf("ddn%d: program error ", unit); 704 goto daterr; 705 706 case DDNIOCOVR: 707 printf("ddn%d: overrun error ", unit); 708 goto daterr; 709 710 case DDNIOCUBE: 711 printf("ddn%d: NXM timeout or UB parity error ", unit); 712 713 daterr: 714 printf("chan=%d func=%x\n", chan, hc->hc_func); 715 if (hc->hc_func & DDNRDB) 716 ds->ddn_if.if_ierrors++; 717 else 718 ds->ddn_if.if_oerrors++; 719 } 720 721 /* was it supervisor or data traffic? */ 722 723 if (chan > 1) 724 ddn_data(unit, chan, cc, cnt); 725 else 726 ddn_supr(unit, chan, cc, cnt); 727 728 } 729 730 /* 731 * Ack the interrupt 732 */ 733 addr->staack = 1; 734 if (!(addr->ionmi)) 735 { 736 addr->ionmi = 1; 737 addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI; 738 } 739 } 740 741 742 /***********************************************************************\ 743 * x25_init() * 744 ************************************************************************* 745 * * 746 * This routine builds and sends an X.25 initialization msg * 747 * to the UMC. * 748 * * 749 \***********************************************************************/ 750 751 static void x25_init(ds) 752 struct ddn_softc *ds; 753 { 754 struct mbuf *m; 755 register u_char *bp; 756 757 #ifdef DDNDEBUG 758 if (ddn_debug > 0) 759 { 760 printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit); 761 } 762 #endif DDNDEBUG 763 764 MGET(m, M_DONTWAIT, MT_DATA); /* try to get X25 init buffer */ 765 if (m == 0) 766 { 767 printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit); 768 return; 769 } 770 771 init_msg[3] = sizeof(init_msg) - 4; /* set cmnd ext length */ 772 773 bcopy(init_msg, mtod(m, u_char *), sizeof(init_msg)); 774 775 m->m_len = sizeof(init_msg); /* set msg length */ 776 777 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m); 778 ddn_start(ds, &(ds->ddn_cb[0])); 779 } 780 781 782 /***********************************************************************\ 783 * locate_x25_lcn() * 784 ************************************************************************* 785 * * 786 * This routine tries to locate an X25 LCN associated with a * 787 * remote internet address. A linear search of the LCN table * 788 * is made for a matching address. If the search succeeds, the * 789 * LCN is returned. If the search fails, the LCN table is * 790 * searched for an unused table entry. If an unused table entry * 791 * is found, an X25 call is generated to the host specified in * 792 * the destination internet address. If no LCN is available, * 793 * zero is returned. * 794 * * 795 \***********************************************************************/ 796 797 static struct ddn_cb *locate_x25_lcn(ds, ip_addr) 798 struct ddn_softc *ds; 799 struct in_addr ip_addr; 800 { 801 register int lcn; 802 register struct ddn_cb *dc; 803 struct mbuf *m_callbfr; 804 805 #ifdef DDNDEBUG 806 if (ddn_debug > 6) 807 { 808 printf("locate_x25_lcn()\n"); 809 } 810 #endif DDNDEBUG 811 812 dc = &(ds->ddn_cb[1]); 813 for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for addr match */ 814 { 815 if (dc->dc_inaddr.s_addr == ip_addr.s_addr) /* if found */ 816 return(dc); /* return LCN */ 817 dc++; 818 } 819 820 dc = &(ds->ddn_cb[1]); 821 for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for free entry */ 822 { 823 if (dc->dc_state == LC_IDLE) 824 break; 825 dc++; 826 } 827 828 if (lcn > NDDNCH) /* if we didn't find a free entry */ 829 return(0); /* return empty handed */ 830 831 832 if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc)) 833 { /* addr can be converted */ 834 dc->dc_inaddr.s_addr = ip_addr.s_addr; 835 return(dc); /* and return the LCN */ 836 } 837 else 838 { 839 return(0); /* give up */ 840 } 841 } 842 843 844 /***********************************************************************\ 845 * convert_ip_addr() * 846 ************************************************************************* 847 * * 848 * This routine accepts an internet address and attempts to * 849 * translate to an equivalent X25 address. For DDN this follows * 850 * the guidelines in the DDN X25 interface spec. The resultant * 851 * X25 address is stored in the X25 called addr buffer. The * 852 * routine returns TRUE if successfull, FALSE otherwise. * 853 * * 854 * NOTE: Although IF-11/X25 was designed to accept ASCII coded * 855 * digits for the address fields, we only supply the binary * 856 * values. The front-end only uses the low four bits to extract * 857 * the binary value from the ASCII digits, so this works out. * 858 * * 859 \***********************************************************************/ 860 861 static boolean convert_ip_addr(ip_addr, x25addr) 862 struct in_addr ip_addr; 863 u_char x25addr[]; 864 { 865 register int temp; 866 union { 867 struct in_addr ip; 868 struct { /* (assumes Class A network number) */ 869 u_char s_net; 870 u_char s_host; 871 u_char s_lh; 872 u_char s_impno; 873 } imp; 874 } imp_addr; 875 876 imp_addr.ip = ip_addr; 877 x25addr[0] = 14; /* set addr length */ 878 879 x25addr[1] = 0; /* clear DNIC */ 880 x25addr[2] = 0; 881 x25addr[3] = 0; 882 x25addr[4] = 0; 883 884 if (imp_addr.imp.s_host < 64) /* Physical: 0000 0 IIIHH00 [SS] */ 885 { /* s_impno -> III, s_host -> HH */ 886 x25addr[5] = 0; /* set flag bit */ 887 x25addr[6] = imp_addr.imp.s_impno / 100; 888 x25addr[7] = (imp_addr.imp.s_impno % 100) / 10; 889 x25addr[8] = imp_addr.imp.s_impno % 10; 890 x25addr[9] = imp_addr.imp.s_host / 10; 891 x25addr[10] = imp_addr.imp.s_host % 10; 892 } 893 else /* Logical: 0000 1 RRRRR00 [SS] */ 894 { /* s_host * 256 + s_impno -> RRRRR */ 895 temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno; 896 x25addr[5] = 1; 897 x25addr[6] = temp / 10000; 898 x25addr[7] = (temp % 10000) / 1000; 899 x25addr[8] = (temp % 1000) / 100; 900 x25addr[9] = (temp % 100) / 10; 901 x25addr[10] = temp % 10; 902 } 903 904 x25addr[11] = 0; /* clear rest of addr */ 905 x25addr[12] = 0; 906 x25addr[13] = 0; 907 x25addr[14] = 0; 908 909 #ifdef DDNDEBUG 910 if (ddn_debug > 4) 911 { 912 printf("convert_ip_addr(): "); 913 prt_addr(ip_addr); 914 printf(" ==> "); 915 prt_bytes(x25addr, 14); 916 printf("\n"); 917 } 918 #endif DDNDEBUG 919 920 return(1); 921 } 922 923 924 /***********************************************************************\ 925 * convert_x25_addr() * 926 ************************************************************************* 927 * * 928 * This routine accepts an X25 address and attempts to translate * 929 * to an equivalent internet address. For DDN this follows the * 930 * guidelines in the DDN X25 interface spec. The resultant * 931 * internet address is returned to the caller. * 932 * * 933 \***********************************************************************/ 934 935 static int convert_x25_addr(x25addr) 936 u_char x25addr[]; 937 { 938 register int cnt, temp; 939 union { 940 struct in_addr ip; 941 struct { /* (assumes Class A network number) */ 942 u_char s_net; 943 u_char s_host; 944 u_char s_lh; 945 u_char s_impno; 946 } imp; 947 } imp_addr; 948 949 if (((cnt = x25addr[0]) < 12) || (cnt > 14)) 950 { 951 printf("DDN: illegal X25 address length!\n"); 952 return(0); 953 } 954 955 switch(x25addr[5] & 0x0f) 956 { 957 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 958 imp_addr.imp.s_impno = 959 ((int)(x25addr[6] & 0x0f) * 100) + 960 ((int)(x25addr[7] & 0x0f) * 10) + 961 ((int)(x25addr[8] & 0x0f)); 962 963 964 imp_addr.imp.s_host = 965 ((int)(x25addr[9] & 0x0f) * 10) + 966 ((int)(x25addr[10] & 0x0f)); 967 break; 968 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 969 temp = ((int)(x25addr[6] & 0x0f) * 10000) 970 + ((int)(x25addr[7] & 0x0f) * 1000) 971 + ((int)(x25addr[8] & 0x0f) * 100) 972 + ((int)(x25addr[9] & 0x0f) * 10) 973 + ((int)(x25addr[10] & 0x0f)); 974 975 imp_addr.imp.s_host = temp >> 8; 976 imp_addr.imp.s_impno = temp & 0xff; 977 break; 978 default: 979 printf("DDN: illegal X25 address format!\n"); 980 return(0); 981 } 982 983 imp_addr.imp.s_lh = 0; 984 imp_addr.imp.s_net = 0; 985 986 #ifdef DDNDEBUG 987 if (ddn_debug > 4) 988 { 989 printf("convert_x25_addr(): "); 990 prt_bytes(&x25addr[1], cnt); 991 printf(" ==> "); 992 prt_addr(imp_addr.ip); 993 printf("\n"); 994 } 995 #endif DDNDEBUG 996 997 return(imp_addr.ip.s_addr); 998 } 999 1000 1001 /***********************************************************************\ 1002 * make_x25_call() * 1003 ************************************************************************* 1004 * * 1005 * This routine places an X25 call using the X25 Call Msg * 1006 * buffer. The calling LCN is placed in the appropriate state * 1007 * and a timer is started. * 1008 * * 1009 \***********************************************************************/ 1010 1011 static boolean make_x25_call(ds, dc) 1012 register struct ddn_softc *ds; 1013 register struct ddn_cb *dc; 1014 { 1015 register struct mbuf *m_callbfr; 1016 register u_char *cb; 1017 1018 MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd buffer */ 1019 if (m_callbfr == 0) 1020 return(0); 1021 1022 cb = mtod(m_callbfr, u_char *); 1023 1024 convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr); 1025 1026 cb_protocol[0] = 4; 1027 cb_protocol[1] = X25_PROTO_IP; /* protocol = IP */ 1028 cb_protocol[2] = 0; 1029 cb_protocol[3] = 0; 1030 cb_protocol[4] = 0; 1031 1032 cb_facilities[0] = 4; /* number facility bytes */ 1033 cb_facilities[1] = 0; /* options marker */ 1034 cb_facilities[2] = 0; 1035 cb_facilities[3] = X25_FACIL_DDN; /* DDN standard mode */ 1036 cb_facilities[4] = FAC_DDNSTD; 1037 1038 cb_user_data[0] = 0; /* no user data */ 1039 1040 cb_cmnd[0] = CALL; /* set command code */ 1041 cb_cmnd[1] = dc->dc_lcn << 1; /* set channel id */ 1042 cb_cmnd[2] = 0; 1043 cb_cmnd[3] = (cb_called_addr[0] + 1) + /* tally up cmnd ext length */ 1044 (cb_calling_addr[0] + 1) + 1045 (cb_protocol[0] + 1) + 1046 (cb_facilities[0] + 1) + 1047 (cb_user_data[0] + 1); 1048 1049 m_callbfr->m_len = cb_cmnd[3] + 4; 1050 1051 /* copy command header */ 1052 bcopy(cb_cmnd, cb, 4); 1053 cb += 4; 1054 1055 /* copy called address */ 1056 bcopy(cb_called_addr, cb, cb_called_addr[0] + 1); 1057 cb += (cb_called_addr[0] + 1); 1058 1059 /* copy calling address */ 1060 bcopy(cb_calling_addr, cb, cb_calling_addr[0] + 1); 1061 cb += (cb_calling_addr[0] + 1); 1062 1063 /* copy protocol */ 1064 bcopy(cb_protocol, cb, cb_protocol[0] + 1); 1065 cb += (cb_protocol[0] + 1); 1066 1067 /* copy facilities */ 1068 bcopy(cb_facilities, cb, cb_facilities[0] + 1); 1069 cb += (cb_facilities[0] + 1); 1070 1071 /* copy user data */ 1072 bcopy(cb_user_data, cb, cb_user_data[0] + 1); 1073 cb += (cb_user_data[0] + 1); 1074 1075 dc->dc_state = LC_CALL_PENDING; /* set state */ 1076 dc->dc_timer = TMO_CALL_PENDING; /* start call timeout */ 1077 1078 #ifdef DDNDEBUG 1079 if (ddn_debug > 3) 1080 { 1081 printf("make_x25_call(): call_bfr = "); 1082 prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len); 1083 printf("\n"); 1084 } 1085 #endif DDNDEBUG 1086 1087 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr); 1088 ddn_start(ds, &(ds->ddn_cb[0])); 1089 1090 return(1); 1091 } 1092 1093 1094 /***********************************************************************\ 1095 * ddn_start() * 1096 ************************************************************************* 1097 * * 1098 * This routine attempts to start output of data queued on a * 1099 * specific LCN. If the LCN was not already busy and data is * 1100 * available for output, the data is copied into the LCN's I/O * 1101 * buffer and an I/O request queued to the UMC. * 1102 * * 1103 \***********************************************************************/ 1104 1105 static void ddn_start(ds, dc) 1106 register struct ddn_softc *ds; 1107 register struct ddn_cb *dc; 1108 { 1109 register struct mbuf *m; 1110 int len; 1111 1112 /* 1113 * If output isn't active, attempt to 1114 * start sending a new packet. 1115 */ 1116 1117 if ((dc->dc_flags & DC_OBUSY) || 1118 (dc->dc_oq.ifq_len == 0) || 1119 ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE))) 1120 { 1121 return; 1122 } 1123 1124 IF_DEQUEUE(&dc->dc_oq, m); 1125 1126 len = if_wubaput(&dc->dc_ifuba, m); /* copy data to mapped mem */ 1127 dc->dc_flags |= DC_OBUSY; 1128 1129 ddn_iorq(ds, dc, len, DDNWRT+DDNEOS); 1130 } 1131 1132 1133 /***********************************************************************\ 1134 * ddn_iorq() * 1135 ************************************************************************* 1136 * * 1137 * This routine builds UMC I/O requests and queues them for * 1138 * delivery to the UMC. If the UMC I/O request comm regs are * 1139 * not busy, the I/O request is passed to the UMC. * 1140 * * 1141 \***********************************************************************/ 1142 1143 static void ddn_iorq(ds, dc, len, func) 1144 struct ddn_softc *ds; 1145 struct ddn_cb *dc; 1146 int len, func; 1147 { 1148 register struct hdx_chan *hc; 1149 register int info; 1150 1151 1152 /* get appropriate UNIBUS mapping info */ 1153 1154 if (func & DDNRDB) /* read or write? */ 1155 { 1156 hc = &dc->dc_rchan; 1157 info = dc->dc_ifuba.ifu_r.ifrw_info; 1158 } 1159 else 1160 { 1161 hc = &dc->dc_wchan; 1162 info = dc->dc_ifuba.ifu_w.ifrw_info; 1163 } 1164 1165 /* set channel info */ 1166 1167 hc->hc_adx = (u_char)((info & 0x30000) >> 12); 1168 hc->hc_addr = (u_short)(info & 0xffff); 1169 hc->hc_cnt = len; 1170 hc->hc_func = (u_char)func; 1171 hc->hc_sbfc = 0; 1172 1173 /* 1174 * If UMC comm regs busy, queue start i/o for later. 1175 */ 1176 if (ds->ddn_sioq.sq_head) 1177 { 1178 (ds->ddn_sioq.sq_tail)->hc_next = hc; 1179 ds->ddn_sioq.sq_tail = hc; 1180 hc->hc_next = 0; 1181 return; 1182 } 1183 1184 /* start i/o on channel now */ 1185 1186 ds->ddn_sioq.sq_head = hc; 1187 ds->ddn_sioq.sq_tail = hc; 1188 hc->hc_next = 0; 1189 start_chn(ds); 1190 } 1191 1192 1193 /***********************************************************************\ 1194 * start_chn() * 1195 ************************************************************************* 1196 * * 1197 * This routine copies UMC I/O requests into the UMC comm regs * 1198 * and notifies the UMC. * 1199 * * 1200 \***********************************************************************/ 1201 1202 static void start_chn(ds) 1203 struct ddn_softc *ds; 1204 { 1205 register struct hdx_chan *hc = ds->ddn_sioq.sq_head; 1206 register struct ddnregs *addr = 1207 (struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr; 1208 1209 /* 1210 * Set up comm regs. 1211 */ 1212 addr->iochn = hc->hc_chan; 1213 addr->ioadx = hc->hc_adx; 1214 addr->ioadl = hc->hc_addr; 1215 addr->iocnt = hc->hc_cnt; 1216 addr->iofcn = hc->hc_func; 1217 addr->iosbf = hc->hc_sbfc; 1218 addr->ioini = 1; 1219 1220 /* signal UMC if necessary */ 1221 1222 if (!(addr->ionmi)) 1223 { 1224 addr->ionmi = 1; 1225 addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI; 1226 } 1227 } 1228 1229 1230 /***********************************************************************\ 1231 * ddn_data() * 1232 ************************************************************************* 1233 * * 1234 * This routine is called when a data channel I/O completes. * 1235 * If the completion was for a write, an attempt is made to * 1236 * start output on the next packet waiting for output on that * 1237 * LCN. If the completion was for a read, the received packet * 1238 * is sent to the IP input queue (if no error) and another read * 1239 * is started on the LCN. * 1240 * * 1241 \***********************************************************************/ 1242 1243 static void ddn_data(unit, chan, cc, rcnt) 1244 int unit, chan, cc, rcnt; 1245 { 1246 register struct ddn_softc *ds = &ddn_softc[unit]; 1247 register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]); 1248 register struct ifqueue *inq = &ipintrq; 1249 register struct mbuf *m; 1250 1251 if (chan & 0x01) /* was it read or write? */ 1252 { /* write, fire up next output */ 1253 ds->ddn_if.if_opackets++; 1254 dc->dc_flags &= ~DC_OBUSY; 1255 ddn_start(ds, dc); 1256 } 1257 else /* read, process rcvd packet */ 1258 { 1259 if (cc == DDNIOCOK) 1260 { /* Queue good packet for input */ 1261 ds->ddn_if.if_ipackets++; 1262 dc->dc_state = LC_DATA_IDLE; 1263 dc->dc_timer = TMO_DATA_IDLE; 1264 m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if); 1265 if (m) 1266 { 1267 if (IF_QFULL(inq)) 1268 { 1269 IF_DROP(inq); 1270 m_freem(m); 1271 } 1272 else 1273 { 1274 IF_ENQUEUE(inq, m); 1275 schednetisr(NETISR_IP); 1276 } 1277 } 1278 } 1279 1280 /* hang a new data read */ 1281 1282 ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR); 1283 1284 } 1285 } 1286 1287 1288 /***********************************************************************\ 1289 * ddn_supr() * 1290 ************************************************************************* 1291 * * 1292 * This routine is called when a supervisor I/O completes. * 1293 * If the completion was for a write, an attempt is made to * 1294 * start output on the next supervisor command waiting for * 1295 * output. If the completion was for a read, the received * 1296 * supervisor message is processed and another read is started. * 1297 * * 1298 \***********************************************************************/ 1299 1300 static void ddn_supr(unit, chan, cc, rcnt) 1301 int unit, chan, cc, rcnt; 1302 { 1303 register struct ddn_softc *ds = &ddn_softc[unit]; 1304 u_char *p; 1305 1306 /* was it read or write? */ 1307 1308 if (chan & 0x01) 1309 { 1310 ds->ddn_cb[0].dc_flags &= ~DC_OBUSY; 1311 ddn_start(ds, &(ds->ddn_cb[0])); 1312 } 1313 else 1314 { 1315 if (cc == DDNIOCOK) 1316 { 1317 p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr); 1318 1319 /* process supervisor message */ 1320 1321 supr_msg(ds, p); 1322 1323 } 1324 1325 /* hang a new supr read */ 1326 1327 ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR); 1328 } 1329 } 1330 1331 1332 /***********************************************************************\ 1333 * supr_msg() * 1334 ************************************************************************* 1335 * * 1336 * This routine processes received supervisor messages. * 1337 * Depending on the message type, the appropriate action is * 1338 * taken. 1339 * * 1340 \***********************************************************************/ 1341 1342 static void supr_msg(ds, p) 1343 struct ddn_softc *ds; 1344 u_char p[]; 1345 { 1346 register struct ddn_cb *dc; 1347 register int lcn; 1348 register struct mbuf *m; 1349 1350 #ifdef DDNDEBUG 1351 if (ddn_debug > 5) 1352 { 1353 printf("supr_msg(): "); 1354 prt_bytes(p, 4+p[3]); 1355 printf("\n"); 1356 } 1357 #endif DDNDEBUG 1358 1359 switch (p[0]) 1360 { 1361 case LINE_STATUS: /* link status msg */ 1362 if (p[2] == LINK_UP) /* if link came up */ 1363 { 1364 send_restart(ds); /* send restart msg */ 1365 } 1366 else /* if link went down */ 1367 { 1368 ds->ddn_if.if_flags &= ~IFF_UP; 1369 dc = ds->ddn_cb; 1370 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */ 1371 { 1372 dc->dc_state = LC_DOWN; /* set state */ 1373 dc->dc_timer = TMO_OFF; /* stop timer */ 1374 dc++; 1375 } 1376 } 1377 break; 1378 1379 case RESTART: /* restart received */ 1380 if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */ 1381 send_supr(ds, RSTRT_ACK, 0, 0); /* send restart ack */ 1382 /* fall thru */ 1383 case RSTRT_ACK: /* restart ack */ 1384 ds->ddn_if.if_flags |= IFF_UP; 1385 dc = ds->ddn_cb; 1386 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */ 1387 { 1388 dc->dc_state = LC_IDLE; /* set state */ 1389 dc->dc_timer = TMO_OFF; /* stop timer */ 1390 dc->dc_inaddr.s_addr = 0; /* forget address */ 1391 while (dc->dc_oq.ifq_len) /* drop pending data */ 1392 { 1393 IF_DEQUEUE(&dc->dc_oq, m); 1394 m_freem(m); 1395 } 1396 dc++; 1397 } 1398 break; 1399 1400 case ANSWER: /* call answered */ 1401 lcn = p[1] / 2; 1402 dc = &(ds->ddn_cb[lcn]); 1403 if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */ 1404 { 1405 dc->dc_state = LC_DATA_IDLE; /* set state */ 1406 dc->dc_timer = TMO_DATA_IDLE; /* start timer */ 1407 ddn_start(ds, dc); /* try to send data */ 1408 } 1409 break; 1410 1411 case RING: /* incoming call */ 1412 for(lcn = NDDNCH; lcn > 0; lcn--) /* search LCN's */ 1413 { 1414 if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */ 1415 break; 1416 } 1417 1418 if (lcn && decode_ring(p)) /* if a free LCN found */ 1419 /* and ring looks ok */ 1420 { 1421 dc = &(ds->ddn_cb[lcn]); 1422 dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr); 1423 dc->dc_state = LC_DATA_IDLE; /* set state */ 1424 dc->dc_timer = TMO_DATA_IDLE; /* start timer */ 1425 send_supr(ds, ANSWER, lcn * 2, p[2]); /* send answer */ 1426 } 1427 else /* if no free LCN's */ 1428 { 1429 send_supr(ds, CLEARVC, p[2], 0); /* clear call */ 1430 } 1431 break; 1432 1433 case CLEARLC: /* clear by LCN */ 1434 lcn = p[1] / 2; /* get LCN */ 1435 dc = &(ds->ddn_cb[lcn]); 1436 if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */ 1437 { 1438 send_supr(ds, CLEARLC, p[1], 0); /* ack the clear */ 1439 } 1440 dc->dc_state = LC_IDLE; /* set state */ 1441 dc->dc_timer = TMO_OFF; /* stop timer */ 1442 dc->dc_inaddr.s_addr = 0; /* forget address */ 1443 while (dc->dc_oq.ifq_len) /* drop pending data */ 1444 { 1445 IF_DEQUEUE(&dc->dc_oq, m); 1446 m_freem(m); 1447 } 1448 break; 1449 1450 case CLEARVC: /* clear by VCN */ 1451 send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */ 1452 break; 1453 1454 case RESET: /* X25 reset */ 1455 send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */ 1456 printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */ 1457 break; 1458 1459 case INTERRUPT: /* X25 interrupt */ 1460 printf("X25 INTERRUPT on lcn = %d, code = %d\n", /* log it */ 1461 p[1] / 2, p[2]); 1462 break; 1463 1464 default: 1465 printf("ddn%d: supervisor error, code=%x\n", 1466 ds->ddn_if.if_unit, p[0]); 1467 } 1468 } 1469 1470 1471 /***********************************************************************\ 1472 * decode_ring() * 1473 ************************************************************************* 1474 * * 1475 * This routine parses and validates the incoming call msg. * 1476 * * 1477 \***********************************************************************/ 1478 1479 static boolean decode_ring(p) 1480 register u_char *p; 1481 { 1482 register int cnt; 1483 1484 #ifdef DDNDEBUG 1485 if (ddn_debug > 3) 1486 { 1487 printf("decode_ring()\n"); 1488 } 1489 #endif DDNDEBUG 1490 1491 1492 p += 3; /* skip to cmnd ext length */ 1493 if (*p++ < 5) /* is count appropriate */ 1494 return(0); /* return false if not */ 1495 1496 /* called address */ 1497 if ((cnt = *p + 1) > 16) /* is called addr len legal? */ 1498 return(0); /* return false if not */ 1499 bcopy(p, cb_called_addr, cnt); /* copy field */ 1500 p += cnt; 1501 1502 /* calling address */ 1503 if ((cnt = *p + 1) > 16) /* is calling addr len legal? */ 1504 return(0); /* return false if not */ 1505 bcopy(p, cb_calling_addr, cnt); /* copy field */ 1506 p += cnt; 1507 1508 /* protocol part of user data */ 1509 if ((cnt = *p + 1) > 5) /* is protocol len legal? */ 1510 return(0); /* return false if not */ 1511 bcopy(p, cb_protocol, cnt); /* copy field */ 1512 p += cnt; 1513 1514 /* facilities */ 1515 if ((cnt = *p + 1) > 64) /* is facilities len legal? */ 1516 return(0); /* return false if not */ 1517 bcopy(p, cb_facilities, cnt); /* copy field */ 1518 p += cnt; 1519 1520 /* ignore rest of user data for now */ 1521 1522 if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP)) 1523 return(0); /* bad if not IP */ 1524 1525 return(1); /* looks ok */ 1526 } 1527 1528 1529 /***********************************************************************\ 1530 * clear_lcn() * 1531 ************************************************************************* 1532 * * 1533 * This routine clears an X25 circuit and releases any buffers * 1534 * queued for transmission. * 1535 * * 1536 \***********************************************************************/ 1537 1538 static void clear_lcn(ds, dc) 1539 struct ddn_softc *ds; 1540 struct ddn_cb *dc; 1541 { 1542 register struct mbuf *m; 1543 1544 #ifdef DDNDEBUG 1545 if (ddn_debug > 3) 1546 { 1547 printf("clear_lcn(%d)\n", dc->dc_lcn); 1548 } 1549 #endif DDNDEBUG 1550 1551 dc->dc_state = LC_CLR_PENDING; /* set state */ 1552 dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */ 1553 dc->dc_inaddr.s_addr = 0; /* clear associated address */ 1554 while (dc->dc_oq.ifq_len) /* drop any pending data */ 1555 { 1556 IF_DEQUEUE(&dc->dc_oq, m); 1557 m_freem(m); 1558 } 1559 send_supr(ds, CLEARLC, dc->dc_lcn * 2, 0); /* send clear msg */ 1560 } 1561 1562 1563 /***********************************************************************\ 1564 * send_restart() * 1565 ************************************************************************* 1566 * * 1567 * This routine marks all LCNs as being in a restarting state * 1568 * and sends a restart command to X25. * 1569 * * 1570 \***********************************************************************/ 1571 1572 static void send_restart(ds) 1573 struct ddn_softc *ds; 1574 { 1575 register struct ddn_cb *dc; 1576 register int lcn; 1577 struct mbuf *m; 1578 1579 #ifdef DDNDEBUG 1580 if (ddn_debug > 1) 1581 { 1582 printf("send_restart()\n"); 1583 } 1584 #endif DDNDEBUG 1585 dc = ds->ddn_cb; 1586 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */ 1587 { 1588 dc->dc_state = LC_RESTART; /* set state */ 1589 dc->dc_timer = TMO_RESTART; /* start restart timeout */ 1590 dc->dc_inaddr.s_addr = 0; /* forget address */ 1591 while (dc->dc_oq.ifq_len) /* drop any pending data */ 1592 { 1593 IF_DEQUEUE(&dc->dc_oq, m); 1594 m_freem(m); 1595 } 1596 dc++; 1597 } 1598 1599 send_supr(ds, RESTART, 0, 0); /* send restart msg */ 1600 } 1601 1602 1603 /***********************************************************************\ 1604 * send_supr() * 1605 ************************************************************************* 1606 * * 1607 * This routine is used to send short (4 bytes only) supervisor * 1608 * commands. * 1609 * * 1610 \***********************************************************************/ 1611 1612 static void send_supr(ds, cmd, p1, p2) 1613 struct ddn_softc *ds; 1614 int cmd, p1, p2; 1615 { 1616 struct mbuf *m; 1617 register u_char *cp; 1618 1619 #ifdef DDNDEBUG 1620 if (ddn_debug > 6) 1621 { 1622 printf("send_supr(): %x %x %x\n", cmd, p1, p2); 1623 } 1624 #endif DDNDEBUG 1625 1626 MGET(m, M_DONTWAIT, MT_DATA); 1627 1628 if (m == 0) 1629 { 1630 printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit); 1631 return; 1632 } 1633 1634 cp = mtod(m, u_char *); 1635 1636 /* build supervisor message */ 1637 1638 *cp++ = (byte)cmd; 1639 *cp++ = (byte)p1; 1640 *cp++ = (byte)p2; 1641 *cp++ = 0; 1642 1643 m->m_len = 4; 1644 1645 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m); 1646 ddn_start(ds, &(ds->ddn_cb[0])); 1647 1648 } 1649 1650 1651 #ifdef DDNDEBUG 1652 1653 /***********************************************************************\ 1654 * prt_addr() * 1655 ************************************************************************* 1656 * * 1657 * This routine is used to print internet addresses in the * 1658 * standard A.B.C.D format. * 1659 * * 1660 \***********************************************************************/ 1661 1662 static void prt_addr(addr) 1663 struct in_addr addr; 1664 { 1665 printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno); 1666 } 1667 1668 /***********************************************************************\ 1669 * prt_bytes() * 1670 ************************************************************************* 1671 * * 1672 * This routine is used to print a string of bytes in hex. * 1673 * * 1674 \***********************************************************************/ 1675 1676 static void prt_bytes(bp, cnt) 1677 u_char *bp; 1678 int cnt; 1679 { 1680 while(cnt--) 1681 { 1682 printf(" %x", *bp++ & 0xff); 1683 } 1684 } 1685 1686 #endif DDNDEBUG 1687 1688 #endif NDDN 1689