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