1 /* @(#)if_ddn.c 6.5 (Berkeley) 02/23/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; 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 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, p[2]); /* send answer */ 1423 } 1424 else /* if no free LCN's */ 1425 { 1426 send_supr(ds, CLEARVC, 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, 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, p[1], 0); /* send clear ack */ 1449 break; 1450 1451 case RESET: /* X25 reset */ 1452 send_supr(ds, RESET_ACK, 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(p, cb_called_addr, 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(p, cb_calling_addr, 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(p, cb_protocol, 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(p, cb_facilities, 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, 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 1686