1 /*************************************************************************/ 2 /* */ 3 /* */ 4 /* ________________________________________________________ */ 5 /* / \ */ 6 /* | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */ 7 /* | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */ 8 /* | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */ 9 /* | AAAA AAAA CCCC CCCC | */ 10 /* | AAAA AAAA CCCC CCCC | */ 11 /* | AAAA AAAA CCCC CCCC | */ 12 /* | AAAA AAAA CCCC CCCC | */ 13 /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */ 14 /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */ 15 /* | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */ 16 /* \________________________________________________________/ */ 17 /* */ 18 /* Copyright (c) 1986 by Advanced Computer Communications */ 19 /* 720 Santa Barbara Street, Santa Barbara, California 93101 */ 20 /* (805) 963-9431 */ 21 /* */ 22 /* */ 23 /* File: if_dda.c */ 24 /* */ 25 /* Project: DDN-X.25 Network Interface Driver for ACP 5250 */ 26 /* and ACP 6250 */ 27 /* */ 28 /* Function: This is a network interface driver supporting */ 29 /* the ACP5250/6250 under UNIX versions 4.2, 4.3, */ 30 /* 4.3-tahoe, Ultrix versions 1.2 and 2.0, and */ 31 /* under VMS, TWG WIN/VX and TGV Multinet. */ 32 /* */ 33 /* Components: required: if_dda.c, if_ddareg.h, if_ddavar.h, */ 34 /* and one of: if_dda_uqbus.c if_dda_bibus.c */ 35 /* optional: if_pi.c, if_pivar.h, if_x29.c, */ 36 /* if_vmsx29.c */ 37 /* */ 38 /*************************************************************************/ 39 40 41 #include "dda.h" 42 43 #if NDDA > 0 44 45 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 46 /*%% %%*/ 47 /*%% SYSTEM CONFIGURATION %%*/ 48 /*%% %%*/ 49 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 50 51 #if !defined(ACC_ULTRIX) && !defined(ACC_BSD) && !defined(ACC_VMS) 52 ERROR 53 an ACC OS specific option must be defined in your config file 54 ERROR 55 #endif 56 57 /* 58 * now define the un-set options to zero 59 */ 60 #if !defined(ACC_ULTRIX) 61 #define ACC_ULTRIX 00 62 #endif 63 64 #if !defined(ACC_BSD) 65 #define ACC_BSD 00 66 #endif 67 68 #if !defined(ACC_VMS) 69 #define ACC_VMS 00 70 #endif 71 72 /* 73 * the define DDA_MSGQ enables the message queue. this adds 2k to the 74 * data size of the driver. It should only be used during driver development 75 */ 76 77 /*#define DDA_MSGQ /* uncomment this to enable message queue */ 78 79 /* 80 * The following line disables the use of the histogram facilities. This 81 * value (DDA_HISTOGRAM) is automatically undefined for all 4.2 and ULTRIX 82 * 1.2 systems which do not support the histogram facilities. 83 */ 84 85 #define DDA_HISTOGRAM /* comment this out to disable histogram */ 86 87 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 88 /*%% %%*/ 89 /*%% INCLUDE FILES %%*/ 90 /*%% %%*/ 91 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 92 93 #ifndef SIMULATION /* real unix system */ 94 #include "../machine/pte.h" /* page table entries */ 95 #include "../h/param.h" 96 #include "../h/systm.h" 97 #include "../h/mbuf.h" 98 #include "../h/buf.h" 99 #include "../h/protosw.h" 100 #include "../h/socket.h" 101 #include "../h/vmmac.h" 102 #include "../h/errno.h" 103 #include "../h/dir.h" 104 #include "../h/user.h" 105 #include "../h/kernel.h" 106 #include "../h/ioctl.h" 107 108 #include "../vax/cpu.h" 109 #include "../vax/mtpr.h" 110 111 #include "../net/if.h" 112 #include "../net/netisr.h" 113 #include "../net/route.h" 114 #include "../netinet/in.h" 115 #include "../netinet/in_systm.h" 116 # if ACC_BSD > 42 || ACC_ULTRIX > 12 117 # include "../netinet/in_var.h" 118 # endif 119 #include "../netinet/ip.h" 120 #include "../netinet/ip_var.h" 121 122 #include "../vaxif/if_ddareg.h" 123 #include "../vaxif/if_ddavar.h" 124 125 #else SIMULATION 126 #include "machine/pte.h" /* page table entries */ 127 128 #include "h/param.h" 129 #include "h/systm.h" 130 #include "h/mbuf.h" 131 #include "h/buf.h" 132 #include "h/protosw.h" 133 #include "h/socket.h" 134 #include "h/vmmac.h" 135 #include "h/errno.h" 136 #include "h/dir.h" 137 #include "h/user.h" 138 #include "h/kernel.h" 139 #include "h/ioctl.h" 140 141 #include "vax/cpu.h" 142 #include "vax/mtpr.h" 143 144 #include "net/if.h" 145 #include "net/netisr.h" 146 #include "net/route.h" 147 #include "netinet/in.h" 148 #include "netinet/in_systm.h" 149 # if ACC_BSD > 42 || ACC_ULTRIX > 12 150 # include "netinet/in_var.h" 151 # endif 152 #include "netinet/ip.h" 153 #include "netinet/ip_var.h" 154 #include "if_ddareg.h" 155 #include "if_ddavar.h" 156 157 # ifndef SIOCACPCONFIG 158 # define SIOCACPCONFIG _IOWR(i,40,struct ifreq) 159 # endif 160 # ifndef INET 161 # define INET 1 162 # endif 163 164 extern struct ifqueue ipintrq; /* IP input queue */ 165 #endif SIMULATION 166 167 #if ACC_VMS > 00 168 # ifdef eunice 169 # define WINS 170 # else 171 # define MULTINET 172 # endif 173 #endif 174 175 #if ACC_VMS > 00 176 # ifdef WINS 177 # include <vms/adpdef.h> /* Define Adapters */ 178 # include <vms/dcdef.h> /* Define AT$_UBA, adapter type */ 179 # else MULTINET 180 # include "../vaxif/if_ddaioctl.h" /* not in ioctl.h */ 181 # endif 182 #endif 183 184 /* disable histogram functions for BSD 4.2 and ULTRIX 1.2 */ 185 186 #if ACC_BSD == 42 || ACC_ULTRIX == 12 187 # undef DDA_HISTOGRAM 188 #endif 189 190 /* Ultrix doesn't have syslog, so use printf instead. Since the two 191 * functions take different arg list formats, embed the open paren in 192 * the defined symbol; provide DDAELOG to close the call while keeping 193 * parentheses matched. The argument to DDALOG is ignored for printf; 194 * for log(), debugging messages use LOG_DEBUG, all others use LOG_ERR. 195 */ 196 #if (ACC_BSD > 42 || ACC_VMS > 00) && !defined(SIMULATION) 197 # include "syslog.h" 198 # define DDALOG(s) log( s, 199 #else 200 # define DDALOG(s) printf( 201 #endif 202 #define DDAELOG ) 203 204 #ifndef DDADEBUG 205 #define PRIVATE static /* hide our internal functions */ 206 #else 207 #define PRIVATE /* let the world see them */ 208 #endif 209 210 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 211 /*%% %%*/ 212 /*%% GLOBAL FUNCTIONS %%*/ 213 /*%% %%*/ 214 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 215 216 int ddaprobe(); 217 int ddaattach(); 218 int ddareset(); 219 int ddainit(); 220 int ddaoutput(); 221 int ddatimer(); 222 int ddaioctl(); 223 int ddainta(); /* service interrupt "a" from front end */ 224 int ddaintb(); /* service interrupt "b" from front end */ 225 226 227 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 228 /*%% %%*/ 229 /*%% LOCAL FUNCTIONS %%*/ 230 /*%% %%*/ 231 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 232 233 PRIVATE void send_config(); 234 PRIVATE struct dda_cb *locate_x25_lcn(); 235 PRIVATE struct dda_cb *find_free_lcn(); 236 PRIVATE boolean convert_ip_addr(); 237 PRIVATE u_long convert_x25_addr(); 238 PRIVATE boolean make_x25_call(); 239 PRIVATE void dda_start(); 240 PRIVATE void dda_rrq(); 241 PRIVATE void dda_wrq(); 242 PRIVATE int start_chn(); 243 PRIVATE void dda_data(); 244 PRIVATE void dda_supr(); 245 PRIVATE void supr_msg(); 246 PRIVATE boolean decode_ring(); 247 PRIVATE void decode_answer(); 248 PRIVATE void clear_lcn(); 249 PRIVATE void send_restart(); 250 PRIVATE void send_supr(); 251 PRIVATE void start_supr(); 252 PRIVATE void abort_io(); 253 PRIVATE void prt_addr(); 254 255 #ifdef DDA_PAD_OR_RAW 256 PRIVATE int dda_decode_type(); 257 #endif 258 259 #ifdef DDA_PADOPT 260 PRIVATE void x29_data(); 261 PRIVATE void x29_supr(); 262 PRIVATE void x29_init(); 263 #endif DDA_PADOPT 264 265 #ifdef DDA_RAWOPT 266 PRIVATE void pi_data(); 267 PRIVATE void pi_supr(); 268 PRIVATE void pi_init(); 269 PRIVATE int pi_circuit_to_handle_protocol(); 270 #endif DDA_RAWOPT 271 272 #ifdef DDADEBUG 273 PRIVATE void prt_bytes(); 274 #endif 275 276 PRIVATE char *fmt_x25(); 277 278 #ifdef DDA_HISTOGRAM 279 PRIVATE void hist_init(); /* histogram functions */ 280 PRIVATE void hist_lcn_state(); 281 PRIVATE void hist_all_lcns(); 282 PRIVATE void hist_link_state(); 283 PRIVATE void hist_read(); 284 PRIVATE int hist_copyout(); 285 286 #else DDA_HISTOGRAM /* make all histogram functions no-op's */ 287 #define hist_init(a,b) 288 #define hist_lcn_state(a,b,c) 289 #define hist_all_lcns(a,b) 290 #define hist_link_state(a,b,c) 291 #define hist_read(a) 292 #define hist_copyout(a,b) 293 #endif DDA_HISTOGRAM 294 295 296 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 297 /*%% %%*/ 298 /*%% LOCAL VARIABLES %%*/ 299 /*%% %%*/ 300 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 301 302 PRIVATE int tmo_data_idle = TMO_DATA_IDLE; /* idle circuit timeout for 303 * all boards */ 304 305 PRIVATE int nddach[4] = { /* number of channels currently in use */ 306 NDDACH_DEFAULT, NDDACH_DEFAULT, 307 NDDACH_DEFAULT, NDDACH_DEFAULT }; 308 309 PRIVATE char *dda_product; /* name of product, like "ACP5250" */ 310 PRIVATE int dda_hasmaint; /* do we have a maintenance board? */ 311 312 /* the message bits are used in the DMESG macros defined in if_ddavar.h */ 313 /* word 1 and 2 (msgs 0 - 63) are reserved for the IP interface */ 314 /* word 3 (msgs 64 - 95) are reserved for the PI interface */ 315 /* word 4 (msgs 96 - 127) are reserved for the X.29 interface */ 316 /* word 5 and 6 (msgs 128 - 191) are reserved for debugging main module*/ 317 /* word 7 (msgs 192 - 223) are reserved for debugging the PI */ 318 /* word 8 (msgs 224 - 255) are reserved for debugging X29 */ 319 /* word 9 (msgs 256 - 287) are reserved for call logging */ 320 #define NDMESGWORDS 9 321 #define MAXDMSGS (NDMESGWORDS * 32) 322 PRIVATE long ddamsgs[NDDA][NDMESGWORDS]; 323 /* | | | | | | | | | 324 * default: all informational messages on, /--/--/--/ | | | | | 325 * all debug messages off, --------------------/---/---/---/ | 326 * log busys, but not calls or I/O aborts ---------------------/ 327 */ 328 329 /* Must be as large as the larger of (trtab, ddactl, dnload): */ 330 char dda_iobuf[sizeof(struct ddactl)]; 331 332 struct dda_softc dda_softc[NDDA]; /* per device infomation */ 333 334 /* header for building command to be sent to the front end in */ 335 /* response to ACPCONFIG user command */ 336 337 PRIVATE u_char acpconfig_msg[] = { 338 LINE_CNTL, /* set command code */ 339 0x00, /* not used */ 340 0x00, /* not used */ 341 0x00, /* extension length (set at runtime) */ 342 0x00, /* cmd space */ 343 0x00, 344 0x00, 345 0x00, 346 0x00 347 }; 348 349 PRIVATE u_char bfr_size_msg[] = 350 { 351 SET_BFR_SIZE, /* set command code */ 352 0x00, /* not used */ 353 0x00, /* not used */ 354 0x01, /* extension length */ 355 0x00, /* cmd space */ 356 0x00, 357 0x00, 358 0x00, 359 0x00 360 }; 361 362 PRIVATE u_char ddacb_cmnd[4] = { CALL, 0, 0, 0 }; 363 PRIVATE u_char ddacb_called_addr[16] = {0}; 364 PRIVATE u_char ddacb_calling_addr[16] = {0}; 365 PRIVATE u_char ddacb_facilities[64] = {0}; 366 PRIVATE u_char ddacb_protocol[5] = {0}; 367 PRIVATE u_char ddacb_user_data[64] = {0}; 368 369 #ifdef DDADEBUG 370 u_char dda_silo_counter; 371 u_char dda_debug_silo[256]; 372 #endif 373 374 /* Table of baud rate values and the associated parameter for the Set */ 375 /* System Parameters message, ddainit_msg. The 'parameter1' is nonzero */ 376 /* for valid baud rate divisors. These are nominal baud rates. */ 377 378 PRIVATE struct baud { 379 char b_value; 380 u_char parameter1; /* first byte of baud rate setting */ 381 u_char parameter2; /* second byte of baud rate setting */ 382 } ddabaud_rate[] = { 383 { 1, 0x02, 0x00 }, /* 2.00M */ 384 { 2, 0x03, 0x00 }, /* 1.33M */ 385 { 3, 0x04, 0x00 }, /* 1.00M */ 386 { 4, 0x08, 0x00 }, /* 500K */ 387 { 5, 0x10, 0x00 }, /* 250K */ 388 { 6, 0x28, 0x00 }, /* 100K */ 389 { 7, 0x3e, 0x00 }, /* 64K */ 390 { 8, 0x47, 0x00 }, /* 56K */ 391 { 9, 0x85, 0x00 }, /* 30K */ 392 { 10, 0xd0, 0x00 }, /* 19.2K */ 393 { 11, 0xa1, 0x01 }, /* 9600 */ 394 { 12, 0x41, 0x03 }, /* 4800 */ 395 { 13, 0x83, 0x06 }, /* 2400 */ 396 { 14, 0x05, 0x0d }, /* 1200 */ 397 { 0, 0, 0 } 398 }; 399 400 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 401 /*%% %%*/ 402 /*%% Address Translation Table for Internet <-> X.25 addresses %%*/ 403 /*%% %%*/ 404 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 405 406 #define DDANATT 32 /* number of addr translation table entries */ 407 PRIVATE int dda_num_addr_tr[NDDA] = {0}; /* number of address 408 * translations */ 409 410 /* currently stored */ 411 PRIVATE struct dda_addr_tr { /* X.25 PDN address translation table */ 412 u_long ip_addr; /* internet address */ 413 u_char x25_addr[MAXADDRLEN]; /* X.25 address */ 414 } dda_addr_tr[NDDA][DDANATT] = {{ 0L, ""}}; /* null */ 415 416 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 417 /*%% %%*/ 418 /*%% Aliasing of IP address for 4.2 ==> 4.3 compatibility %%*/ 419 /*%% Note: this union is not required in 4.2, since the s_net %%*/ 420 /*%% field and its friends are in an include file. We use it to %%*/ 421 /*%% minimize the number of #ifdef dependencies in the code. %%*/ 422 /*%% %%*/ 423 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 424 425 #ifdef s_net /* 4.2 */ 426 # undef s_net 427 # undef s_host 428 # undef s_lh 429 # undef s_impno 430 #endif 431 432 union imp_addr { 433 struct in_addr ip; 434 struct imp { 435 u_char s_net; 436 u_char s_host; 437 u_char s_lh; 438 u_char s_impno; 439 } imp; 440 }; 441 442 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 443 /*%% %%*/ 444 /*%% GLOBAL ROUTINES %%*/ 445 /*%% %%*/ 446 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 447 448 #ifdef ACP_BI 449 #include "if_dda_bibus.c" 450 #else 451 #include "if_dda_uqbus.c" 452 #endif 453 454 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 455 /*%% DDAIOCTL() %%*/ 456 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 457 /* */ 458 /* Purpose: */ 459 /* */ 460 /* This routine processes device dependent ioctl's. Supported */ 461 /* ioctls set the host's internet address for this network */ 462 /* interface, or send Set System Parameters Message to the ACP. */ 463 /* The logic for setting the interface address must remain */ 464 /* compatible with both ifconfig and acpconfig programs. */ 465 /* If the ioctl comes from the acpconfig program, the front end */ 466 /* is not initialized because the user will specify explicitly */ 467 /* what parameters are desired. If the ioctl comes from the */ 468 /* ifconfig program, the fron end is initialized with default */ 469 /* parameters in the ddainit_msg array. */ 470 /* */ 471 /* Call: ddaioctl(ifp, cmd, data) */ 472 /* Argument: ifp: pointer to the network interface data */ 473 /* structure, ifnet */ 474 /* cmd: identifies the type of ioctl */ 475 /* data: information for the ioctl */ 476 /* Returns: 0 for success, or the nonzero error value: */ 477 /* EINVAL invalid ioctl request */ 478 /* Called by: network software, address of this routine is */ 479 /* defined in af_inet network interface struct */ 480 /* Calls to: splimp() */ 481 /* if_rtinit() */ 482 /* in_netof() */ 483 /* in_lnaof() */ 484 /* ddainit() */ 485 /* send_config() */ 486 /* DDALOG() */ 487 /* splx() */ 488 /* */ 489 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 490 491 #ifdef MULTINET 492 volatile int StatQuery_Completed; /* Polled for board stat ioctl */ 493 #endif 494 495 ddaioctl(ifp, cmd, data) 496 register struct ifnet *ifp; 497 int cmd; 498 caddr_t data; 499 { 500 register struct dda_softc *ds = &dda_softc[ifp->if_unit]; 501 struct ifreq *ifr = (struct ifreq *) data; 502 503 #if defined(DDA_PADOPT) && defined(WINS) 504 int prealloc_x29(); /* Preallocate UCBs for X29 */ 505 #endif 506 507 #if ACC_BSD == 42 || ACC_ULTRIX == 12 508 struct sockaddr_in *sin = (struct sockaddr_in *) & ifr->ifr_addr; 509 #else 510 struct ifaddr *ifa = ds->dda_if.if_addrlist; 511 #endif 512 513 int s; 514 int error = 0; 515 int i; 516 register struct dda_addr_tr *atp, *btp; 517 struct trtab *tr; 518 struct ddactl *da; 519 char arg2[MAXADDRLEN], code; 520 521 #ifdef DDADEBUG 522 if (DDADBCH(4, ifp->if_unit)) { 523 DDALOG(LOG_DEBUG) "dda%d: ioctl()\n", ifp->if_unit DDAELOG; 524 } 525 #endif DDADEBUG 526 527 /* 528 * This may not be necessary here, but under some flavors of BSDish 529 * systems (2.0ULTRIX) this routine is apparently called at splimp(). In 530 * the case that we are currently processing ioctls issued from acpconfig 531 * in /etc/rc, the board may not have come on line yet - so we need to be 532 * able to process the B interrupt while in the delay loop below. 533 */ 534 #ifndef MULTINET 535 s = spl0(); 536 #endif 537 538 switch (cmd) { 539 case SIOCSIFADDR: 540 if (!suser()) 541 return EACCES; 542 543 #if ACC_BSD == 42 || ACC_ULTRIX == 12 544 if (ifp->if_flags & IFF_RUNNING) 545 if_rtinit(ifp, -1); /* delete previous route */ 546 ifp->if_addr = *(struct sockaddr *) sin; 547 ifp->if_net = in_netof(sin->sin_addr); 548 ifp->if_host[0] = in_lnaof(sin->sin_addr); 549 if (ifp->if_flags & IFF_RUNNING) 550 if_rtinit(ifp, RTF_UP); 551 else 552 ddainit(ifp->if_unit); 553 ds->dda_ipaddr.s_addr = ((struct sockaddr_in *) & ifp->if_addr)->sin_addr.s_addr; 554 #else /* 4.3 networking */ 555 if (ifa->ifa_addr.sa_family != AF_INET) 556 return (EINVAL); 557 if ((ifp->if_flags & IFF_RUNNING) == 0) 558 ddainit(ifp->if_unit); 559 ds->dda_ipaddr = IA_SIN(ifa)->sin_addr; 560 #endif /* 4.3 networking */ 561 break; 562 563 case SIOCACPCONFIG: 564 /* process ioctl from acpconfig program */ 565 566 code = *(ifr->ifr_data); 567 568 /********************************************************* 569 * * 570 * Commands n, h, q, and r are non-privileged * 571 * * 572 *********************************************************/ 573 574 if (!suser() && code != 'n' && code != 'h' && code != 'q' && code != 'r') 575 return EACCES; 576 577 #if ACC_BSD == 42 || ACC_ULTRIX == 12 578 sin = (struct sockaddr_in *) & ds->dda_if.if_addr; 579 if (in_netof(sin->sin_addr) == 0) 580 #else 581 if (ds->dda_if.if_addrlist == 0) 582 #endif 583 { 584 error = EDESTADDRREQ; /* error, no internet address */ 585 goto exit; 586 } 587 /* for command to set baud rate, look up the value for the */ 588 /* baud rate divisor in the ddabaud_rate table, put value */ 589 /* in the Set System Parameters message, ddainit_msg */ 590 591 if (code >= 1 && code <= 14) { 592 register struct baud *p; 593 594 if (error = diags_completed(ds)) 595 goto exit; 596 for (p = ddabaud_rate; p->b_value; p++) { 597 if ((*(ifr->ifr_data) - p->b_value) == 0) 598 break; 599 } 600 /* if internal clock not set, do so */ 601 if ((ds->dda_init & DDA_INTCLOCK) == 0) { 602 ds->dda_init |= DDA_INTCLOCK; 603 acpconfig_msg[MSG_OFFSET] = CLOCK_CNTL; 604 acpconfig_msg[MSG_OFFSET + 1] = INTERNAL_CLOCK; 605 acpconfig_msg[MSG_OFFSET + 2] = BAUD_CNTL; 606 acpconfig_msg[MSG_OFFSET + 3] = p->parameter1; 607 acpconfig_msg[MSG_OFFSET + 4] = p->parameter2; 608 acpconfig_msg[MSG_LENGTH] = 5; 609 } else { 610 acpconfig_msg[MSG_OFFSET] = BAUD_CNTL; 611 acpconfig_msg[MSG_OFFSET + 1] = p->parameter1; 612 acpconfig_msg[MSG_OFFSET + 2] = p->parameter2; 613 acpconfig_msg[MSG_LENGTH] = 3; 614 } 615 616 if ((p->b_value == 0) || (p->parameter1 == 0)) 617 error = EINVAL; /* baud rate value invalid */ 618 else 619 send_config(ds, acpconfig_msg); /* send message to front end */ 620 goto exit; 621 } 622 switch (code) { 623 case 'a': /* Add address translation table entry */ 624 if (error = diags_completed(ds)) 625 goto exit; 626 if (dda_num_addr_tr[ifp->if_unit] >= DDANATT) { /* table already full */ 627 error = ENOMEM; 628 goto exit; 629 } 630 631 /* 632 * Copy in user arguments and point "tr" at them. Then scan the 633 * translation table and either find location to insert or flag 634 * error 635 */ 636 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) { 637 error = EFAULT; 638 goto exit; 639 } 640 tr = (struct trtab *) dda_iobuf; 641 for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0]; 642 i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) { 643 if (atp->ip_addr == tr->ipaddr) { 644 if (bcmp((char *) atp->x25_addr, 645 (char *) tr->x25addr, MAXADDRLEN)) { 646 error = EADDRINUSE; 647 goto exit; 648 } else /* addresses are the same, just ignore ioctl */ 649 goto exit; 650 } 651 if (atp->ip_addr > tr->ipaddr) /* insert entry here */ 652 break; 653 } 654 for (btp = &dda_addr_tr[ifp->if_unit][dda_num_addr_tr[ifp->if_unit]]; 655 btp > atp; btp--) { /* open up space for a new entry */ 656 btp->ip_addr = (btp - 1)->ip_addr; 657 bcopy((btp - 1)->x25_addr, btp->x25_addr, MAXADDRLEN); 658 } 659 atp->ip_addr = tr->ipaddr; 660 bcopy(tr->x25addr, atp->x25_addr, MAXADDRLEN); 661 dda_num_addr_tr[ifp->if_unit]++; /* one more table entry */ 662 goto exit; 663 664 case 'D': 665 if (error = diags_completed(ds)) 666 goto exit; 667 /* clear table for use by 'r' flag of acpconfig */ 668 for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0]; 669 i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) { 670 atp->ip_addr = 0L; 671 atp->x25_addr[0] = 0; 672 } 673 dda_num_addr_tr[ifp->if_unit] = 0; 674 goto exit; 675 676 case 'd': /* Delete address translation table entry */ 677 if (error = diags_completed(ds)) 678 goto exit; 679 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) { 680 error = EFAULT; 681 goto exit; 682 } 683 tr = (struct trtab *) dda_iobuf; 684 error = EFAULT; /* in case inet address not in table */ 685 for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0]; 686 i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) { 687 if (atp->ip_addr == tr->ipaddr) { 688 error = 0; /* found it: cancel error */ 689 for (; i < dda_num_addr_tr[ifp->if_unit] - 1; i++, atp++) { 690 atp->ip_addr = (atp + 1)->ip_addr; 691 bcopy((atp + 1)->x25_addr, atp->x25_addr, MAXADDRLEN); 692 } 693 atp->ip_addr = 0L; /* clear last vacated entry */ 694 atp->x25_addr[0] = 0; 695 dda_num_addr_tr[ifp->if_unit]--; /* one fewer table 696 * entries */ 697 break; 698 } 699 } 700 goto exit; 701 702 703 case 'f': /* -f facility status */ 704 705 /* 706 * The first byte of the "msg" selects the flow control parameter 707 * and the "drval" field holds the status (on or off). 708 */ 709 if (error = diags_completed(ds)) 710 goto exit; 711 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 712 error = EFAULT; 713 goto exit; 714 } 715 if (ds->dda_firmrev < 0x21) { /* need 2.0 or above ROMs */ 716 error = ENOPROTOOPT; 717 goto exit; 718 } 719 da = (struct ddactl *) dda_iobuf; 720 switch (da->msg[0]) { 721 case 0: /* packet */ 722 if (da->drval) 723 ds->dda_init |= DDA_PKTNEG; 724 else 725 ds->dda_init &= ~DDA_PKTNEG; 726 break; 727 case 1: /* window */ 728 if (da->drval) 729 ds->dda_init |= DDA_WNDNEG; 730 else 731 ds->dda_init &= ~DDA_WNDNEG; 732 break; 733 } 734 goto exit; 735 736 case 'o': /* Set options */ 737 if (error = diags_completed(ds)) 738 goto exit; 739 if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */ 740 error = ENOPROTOOPT; 741 goto exit; 742 } 743 if (ds->dda_state != S_DISABLED) { /* must bring link down */ 744 error = EINPROGRESS; 745 goto exit; 746 } 747 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 748 error = EFAULT; 749 goto exit; 750 } 751 da = (struct ddactl *) dda_iobuf; 752 acpconfig_msg[MSG_OFFSET] = PKT_OPTIONS; 753 acpconfig_msg[MSG_OFFSET + 1] = da->msg[0]; 754 acpconfig_msg[MSG_LENGTH] = 2; 755 #ifdef DDADEBUG 756 if (DDADBCH(4, ifp->if_unit)) { 757 DDALOG(LOG_DEBUG) "dda%d: acpconfig_msg is %x %x %x\n", 758 ifp->if_unit, acpconfig_msg[MSG_LENGTH], 759 acpconfig_msg[MSG_OFFSET], acpconfig_msg[MSG_OFFSET + 1] DDAELOG; 760 } 761 #endif DDADEBUG 762 763 send_config(ds, acpconfig_msg); 764 goto exit; 765 766 case 'N': /* read network id */ 767 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 768 error = EFAULT; 769 goto exit; 770 } 771 da = (struct ddactl *) dda_iobuf; 772 ds->dda_net_id = da->drval; 773 goto exit; 774 775 case 'r': /* Read address translation table entry */ 776 777 /* 778 * The value stored in "ipaddr" is not an address, but an index 779 * of a translation table entry to read out. The x25_addr field 780 * in the input structure is not used. 781 */ 782 if (error = diags_completed(ds)) 783 goto exit; 784 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) { 785 error = EFAULT; 786 goto exit; 787 } 788 tr = (struct trtab *) dda_iobuf; 789 i = tr->ipaddr; 790 if (i >= DDANATT) { /* scanned the whole table */ 791 error = EFAULT; 792 goto exit; 793 } 794 tr->ipaddr = dda_addr_tr[ifp->if_unit][i].ip_addr; 795 bcopy(dda_addr_tr[ifp->if_unit][i].x25_addr, tr->x25addr, MAXADDRLEN); 796 if (copyout(tr, ifr->ifr_data, sizeof(struct trtab))) 797 error = EFAULT; 798 goto exit; 799 800 #ifdef DDA_HISTOGRAM 801 case 'h': /* read histogram */ 802 if (error = diags_completed(ds)) 803 goto exit; 804 hist_read(ifp->if_unit); 805 if (hist_copyout(ifp->if_unit, ifr->ifr_data)) 806 error = EFAULT; 807 goto exit; 808 809 case 'H': /* read and reset histogram */ 810 if (error = diags_completed(ds)) 811 goto exit; 812 hist_read(ifp->if_unit); 813 if (hist_copyout(ifp->if_unit, ifr->ifr_data)) 814 error = EFAULT; 815 else 816 hist_init(ifp->if_unit, 1); 817 goto exit; 818 #endif DDA_HISTOGRAM 819 820 case 'v': /* -v variable value */ 821 822 /* 823 * There are two "variables" in the driver which can be set via 824 * ioctl: packet size, and window size. The "drval" field holds 825 * the value and the first byte of the "msg" selects the variable. 826 * Note that the selector is another little undocumented piece of 827 * the interface between here and the acpconfig program. It is 828 * coupled to the ordering of a little string table inside that 829 * program; new parameters should be added at the end, not the 830 * middle! 831 */ 832 /* No check to see if powerup diags are completed */ 833 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 834 error = EFAULT; 835 goto exit; 836 } 837 da = (struct ddactl *) dda_iobuf; 838 switch (da->msg[0]) { 839 case 0: /* set logging (obsolete) */ 840 case 1: /* set debug (obsolete) */ 841 case 2: /* set debug unit (obsolete) */ 842 error = EINVAL; 843 break; 844 845 /* 846 * For both packet and window sizes, we check that the link 847 * is currently down. The new parameters will be sent to the 848 * FEP when the link is next brought up. See processing for 849 * -u flag. 850 */ 851 case 3: /* set packetsize */ 852 if (error = diags_completed(ds)) 853 goto exit; 854 if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */ 855 error = ENOPROTOOPT; 856 goto exit; 857 } 858 if (ds->dda_state != S_DISABLED) { /* must bring link down */ 859 error = EINPROGRESS; 860 goto exit; 861 } 862 863 /* 864 * X.25 (1984) section 7.2.2.1.1 says 12 (4096 byte packets) 865 * BBN report 5760 (September 1984) 14.2.1.2 says 10. We just 866 * check for 12. 867 */ 868 if (da->drval < 4 || da->drval > 12) 869 error = EINVAL; 870 else { 871 int packetsize = 1 << da->drval; 872 873 acpconfig_msg[MSG_LENGTH] = 3; 874 acpconfig_msg[MSG_OFFSET] = MAX_PKT_SZ; /* Max negotiable */ 875 /* pkt size */ 876 acpconfig_msg[MSG_OFFSET + 1] = packetsize & 0xFF; 877 acpconfig_msg[MSG_OFFSET + 2] = (packetsize >> 8) & 0xFF; 878 send_config(ds, acpconfig_msg); 879 } 880 break; 881 882 case 4: /* set windowsize */ 883 if (error = diags_completed(ds)) 884 goto exit; 885 if (ds->dda_firmrev < 0x21) { /* need 2.0 or above ROMs */ 886 error = ENOPROTOOPT; 887 goto exit; 888 } 889 if (ds->dda_state != S_DISABLED) { /* must bring link down */ 890 error = EINPROGRESS; 891 goto exit; 892 } 893 if (da->drval < 1 || da->drval > 127) 894 error = EINVAL; 895 else { 896 acpconfig_msg[MSG_LENGTH] = 2; 897 acpconfig_msg[MSG_OFFSET] = MAX_PKT_WN; /* Max negotiable */ 898 /* pkt window */ 899 acpconfig_msg[MSG_OFFSET + 1] = da->drval; 900 send_config(ds, acpconfig_msg); 901 } 902 break; 903 } 904 goto exit; 905 906 case 'm': /* -m message */ 907 if (error = diags_completed(ds)) 908 goto exit; 909 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 910 error = EFAULT; 911 goto exit; 912 } 913 da = (struct ddactl *) dda_iobuf; 914 send_config(ds, da->msg); 915 goto exit; 916 917 case 'n': /* -n svc_count */ 918 if (error = diags_completed(ds)) 919 goto exit; 920 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 921 error = EFAULT; 922 goto exit; 923 } 924 if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */ 925 error = ENOPROTOOPT; 926 goto exit; 927 } 928 da = (struct ddactl *) dda_iobuf; 929 i = 0; /* i holds the return value */ 930 if (da->drval == 0) 931 i = nddach[ifp->if_unit]; 932 else if (ds->dda_state != S_DISABLED) { /* must bring link down */ 933 error = EINPROGRESS; 934 goto exit; 935 } else { 936 if (!suser()) { 937 error = EACCES; 938 goto exit; 939 } 940 if (da->drval < 1 || da->drval > NDDACH) 941 error = EINVAL; 942 else { 943 acpconfig_msg[MSG_LENGTH] = 2; 944 acpconfig_msg[MSG_OFFSET] = SVC_LIMIT; 945 acpconfig_msg[MSG_OFFSET + 1] = da->drval; 946 nddach[ifp->if_unit] = da->drval; 947 send_config(ds, acpconfig_msg); 948 } 949 } 950 if (copyout(&i, ifr->ifr_data, sizeof(int))) 951 error = EFAULT; 952 goto exit; 953 954 case 'c': /* -c msgnum -- dis/enable driver mesg */ 955 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 956 error = EFAULT; 957 goto exit; 958 } 959 da = (struct ddactl *) dda_iobuf; 960 if (da->drval < 0 || da->drval >= MAXDMSGS) 961 error = EINVAL; 962 else { 963 u_char new_val; 964 965 DMESGTOG(ifp->if_unit, da->drval); 966 new_val = DMESGVAL(ifp->if_unit, da->drval) ? 1 : 0; 967 /* 1 means disabled, 0 means enabled */ 968 if (copyout(&new_val, ifr->ifr_data, sizeof(u_char))) 969 error = EFAULT; 970 } 971 goto exit; 972 973 case 't': /* -t sec -- set data idle timeout */ 974 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 975 error = EFAULT; 976 goto exit; 977 } 978 da = (struct ddactl *) dda_iobuf; 979 if (da->drval < 1) 980 error = EINVAL; 981 else 982 tmo_data_idle = da->drval / DDA_TIMEOUT; 983 goto exit; 984 985 case 'q': /* driver/FE/shm/silo state queries */ 986 if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) { 987 error = EFAULT; 988 goto exit; 989 } 990 da = (struct ddactl *) dda_iobuf; 991 switch (da->msg[0]) { 992 case 0: /* front end state query */ 993 if ((error = diags_completed(ds)) == 0) { 994 int s2 = splimp(); 995 996 /* need 2.0 or above ROMs */ 997 if (ds->dda_firmrev < 0x21) { 998 error = ENOPROTOOPT; 999 splx(s2); /* We got it and woke up */ 1000 break; 1001 } 1002 #ifdef MULTINET 1003 StatQuery_Completed = 0; 1004 send_supr(ds, STATQUERY, 0, 0); 1005 splx(s2); /* drop ioctl so we can be scheduled */ 1006 while (!StatQuery_Completed); 1007 #else MULTINET 1008 send_supr(ds, STATQUERY, 0, 0); 1009 sleep(dda_iobuf, PSLEP); /* Interruptible with ^C */ 1010 splx(s2); /* We got it and woke up */ 1011 #endif MULTINET 1012 1013 if (copyout(dda_iobuf, ifr->ifr_data, 1014 sizeof(struct ddactl))) 1015 error = EFAULT; 1016 } 1017 break; 1018 case 1: /* driver state query */ 1019 da->msg[0] = ds->dda_state; 1020 da->msg[1] = ds->dda_init; 1021 da->msg[2] = ds->dda_flags; 1022 da->msg[3] = ds->dda_firmrev; 1023 if (copyout(dda_iobuf, ifr->ifr_data, 1024 sizeof(struct ddactl))) 1025 error = EFAULT; 1026 break; 1027 #ifdef DDADEBUG 1028 case 2: /* debug query */ 1029 if (copyout(dda_debug_silo, ifr->ifr_data, 256)) 1030 error = EFAULT; 1031 break; 1032 #endif 1033 #if defined(DDADEBUG) && defined(ACP_BI) 1034 case 3: /* shm/biic query (temporary) */ 1035 { 1036 register struct uba_device *ui = ddainfo[ifp->if_unit]; 1037 dda_dump_shm((SYSGEN_BLOCK *) ds->dda_mapreg); 1038 dda_dump_biic_regs((struct biic_regs *) ui->ui_addr); 1039 } 1040 break; 1041 #endif 1042 default: 1043 error = EINVAL; 1044 } 1045 goto exit; 1046 1047 case '0': /* -u 0 */ 1048 if (error = diags_completed(ds)) 1049 goto exit; 1050 acpconfig_msg[MSG_OFFSET] = LINK_DISABLE; 1051 acpconfig_msg[MSG_LENGTH] = 1; 1052 hist_link_state(ifp->if_unit, ds->dda_state, S_GOING_DOWN); 1053 ds->dda_state = S_GOING_DOWN; 1054 break; 1055 case '1': /* -u 1 */ 1056 if (error = diags_completed(ds)) 1057 goto exit; 1058 acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK; 1059 acpconfig_msg[MSG_OFFSET + 1] = LOOP_NONE; 1060 acpconfig_msg[MSG_OFFSET + 2] = DTE_DCE_MODE; 1061 acpconfig_msg[MSG_OFFSET + 3] = DTE; 1062 acpconfig_msg[MSG_OFFSET + 4] = LINK_ENABLE; 1063 acpconfig_msg[MSG_LENGTH] = 5; 1064 ds->dda_state = S_COMING_UP; 1065 hist_init(ifp->if_unit, 0); 1066 break; 1067 case '2': /* -u 2 */ 1068 if (error = diags_completed(ds)) 1069 goto exit; 1070 acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK; 1071 acpconfig_msg[MSG_OFFSET + 1] = LOOP_NONE; 1072 acpconfig_msg[MSG_OFFSET + 2] = DTE_DCE_MODE; 1073 acpconfig_msg[MSG_OFFSET + 3] = DCE; 1074 acpconfig_msg[MSG_OFFSET + 4] = LINK_ENABLE; 1075 acpconfig_msg[MSG_LENGTH] = 5; 1076 ds->dda_state = S_COMING_UP; 1077 hist_init(ifp->if_unit, 0); 1078 break; 1079 case '3': /* -u 3 */ 1080 if (error = diags_completed(ds)) 1081 goto exit; 1082 acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK; 1083 acpconfig_msg[MSG_OFFSET + 1] = LOOP_EXTERNAL; 1084 acpconfig_msg[MSG_OFFSET + 2] = LINK_ENABLE; 1085 acpconfig_msg[MSG_LENGTH] = 3; 1086 ds->dda_state = S_COMING_UP; 1087 hist_init(ifp->if_unit, 0); 1088 break; 1089 case '4': /* -u 4 */ 1090 if (error = diags_completed(ds)) 1091 goto exit; 1092 acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK; 1093 acpconfig_msg[MSG_OFFSET + 1] = LOOP_INTERNAL; 1094 acpconfig_msg[MSG_OFFSET + 2] = LINK_ENABLE; 1095 acpconfig_msg[MSG_LENGTH] = 3; 1096 ds->dda_state = S_COMING_UP; 1097 hist_init(ifp->if_unit, 0); 1098 break; 1099 case 'b': /* -b 0 */ 1100 if (error = diags_completed(ds)) 1101 goto exit; 1102 acpconfig_msg[MSG_OFFSET] = CLOCK_CNTL; 1103 acpconfig_msg[MSG_OFFSET + 1] = EXTERNAL_CLOCK; 1104 acpconfig_msg[MSG_LENGTH] = 2; 1105 ds->dda_init &= ~DDA_INTCLOCK; 1106 break; 1107 case 'S': /* select DDN standard X.25 service */ 1108 /* -s 0 or -s standard */ 1109 if (error = diags_completed(ds)) 1110 goto exit; 1111 if (ds->dda_if.if_flags & IFF_UP && ds->dda_init & DDA_PDN) { 1112 error = EALREADY; 1113 goto exit; /* no PDN->DDN mode change if running */ 1114 } 1115 ds->dda_init &= ~(DDA_BASIC | DDA_PDN); 1116 ds->dda_init |= DDA_STANDARD; 1117 goto exit; 1118 case 'T': /* select DDN basic X.25 service */ 1119 /* -s 1 or -s basic */ 1120 if (error = diags_completed(ds)) 1121 goto exit; 1122 if (ds->dda_if.if_flags & IFF_UP && ds->dda_init & DDA_PDN) { 1123 error = EALREADY; 1124 goto exit; /* no PDN->DDN mode change if running */ 1125 } 1126 ds->dda_init &= ~(DDA_PDN | DDA_STANDARD); 1127 ds->dda_init |= DDA_BASIC; 1128 goto exit; 1129 case 'U': /* select X.25 Public Data Network service */ 1130 /* -s 2 or -s pdn */ 1131 if (error = diags_completed(ds)) 1132 goto exit; 1133 if (ds->dda_if.if_flags & IFF_UP && (ds->dda_init & 1134 (DDA_BASIC | DDA_STANDARD))) { 1135 error = EALREADY; 1136 goto exit; /* no DDN->PDN mode change if running */ 1137 } 1138 ds->dda_init &= ~(DDA_BASIC | DDA_STANDARD); 1139 ds->dda_init |= DDA_PDN; 1140 goto exit; 1141 1142 case 'e': /* set buffer size */ 1143 /* -e size size is encoded in second byte */ 1144 if (error = diags_completed(ds)) 1145 goto exit; 1146 1147 /* 1148 * check to see if we have newer at least version 2.2 roms. 1149 */ 1150 if (ds->dda_firmrev < 0x22) { 1151 error = ENOPROTOOPT; 1152 goto exit; 1153 } 1154 if (ds->dda_if.if_flags & IFF_UP) { 1155 error = EALREADY; 1156 goto exit; /* no PDN->DDN mode change if running */ 1157 } 1158 bfr_size_msg[MSG_OFFSET] = ifr->ifr_data[1]; 1159 send_config(ds, bfr_size_msg); 1160 bufreset(ifp->if_unit); 1161 goto exit; 1162 1163 #ifdef ACP_BI 1164 case 'L': 1165 { struct dda_dnload dl; 1166 if (copyin(ifr->ifr_data, &dl, sizeof(struct dda_dnload))) { 1167 error = EFAULT; 1168 goto exit; 1169 } 1170 error = dda_dload(ifp->if_unit, &dl); 1171 goto exit; 1172 } 1173 #endif 1174 1175 #if defined(DDA_PADOPT) && defined(WINS) 1176 case 'x': /* Preallocate UCBs for X29 -- VMS only */ 1177 printf("Preallocated %d PTYs for X29\n", prealloc_x29()); 1178 goto exit; 1179 #endif 1180 1181 case 'z': /* reset specified front-end device, -z */ 1182 /* second parm is supposed to be uban, but ddareset doesn't care about it */ 1183 ddareset(ifp->if_unit, 0); 1184 goto exit; 1185 default: 1186 error = EINVAL; 1187 goto exit; 1188 } 1189 if ((*(ifr->ifr_data) != '0') && (ds->dda_init & DDA_PDN) && 1190 #if ACC_BSD == 42 || ACC_ULTRIX == 12 1191 (convert_ip_addr(sin->sin_addr, (u_char *) arg2, ds) == 0) 1192 #else 1193 (convert_ip_addr(ds->dda_ipaddr, (u_char *) arg2, ds) == 0) 1194 #endif 1195 ) { 1196 error = EADDRNOTAVAIL; 1197 goto exit; 1198 } 1199 send_config(ds, acpconfig_msg); 1200 break; 1201 1202 default: 1203 error = EINVAL; 1204 } 1205 1206 exit: 1207 #ifndef MULTINET 1208 splx(s); 1209 #endif 1210 return (error); 1211 } 1212 1213 1214 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1215 /*%% DDAOUTPUT() %%*/ 1216 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1217 /* */ 1218 /* Purpose: */ 1219 /* */ 1220 /* This routine is called by the network software when it has an */ 1221 /* IP datagram to send out this interface. An attempt is made */ 1222 /* to find a LCN which has a virtual circuit open to the */ 1223 /* indicated host. If an LCN is found the packet is queued for */ 1224 /* output on that LCN. */ 1225 /* */ 1226 /* Call: ddaoutput(ifp, m0, dst) */ 1227 /* Arguments: ifp: locates the network interface, ifnet */ 1228 /* m0: locates an mbuf buffer */ 1229 /* dst: is the socket destination address */ 1230 /* Returns: 0 for success, or one of following nonzero */ 1231 /* error indications: */ 1232 /* ENETDOWN */ 1233 /* EAFNOSUPPORT */ 1234 /* ENOBUFS */ 1235 /* Called by: network software, address of this routine is */ 1236 /* defined in the dda_if network interface struct */ 1237 /* Calls to: DDALOG() */ 1238 /* m_freem() */ 1239 /* splimp() */ 1240 /* locate_x25_lcn() */ 1241 /* IF_QFULL() */ 1242 /* IF_DROP() */ 1243 /* splx() */ 1244 /* IF_ENQUEUE() */ 1245 /* dda_start() */ 1246 /* */ 1247 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1248 1249 ddaoutput(ifp, m0, dst) 1250 struct ifnet *ifp; 1251 struct mbuf *m0; 1252 struct sockaddr_in *dst; 1253 { 1254 register struct mbuf *m = m0; 1255 register struct dda_softc *ds = &dda_softc[ifp->if_unit]; 1256 register struct dda_cb *dc; 1257 register struct ifqueue *oq; 1258 struct mbuf *prev; 1259 int s; 1260 union imp_addr imp_addr; 1261 1262 #ifdef DDADEBUG 1263 if (DDADBCH(1, ifp->if_unit)) { 1264 imp_addr.ip = dst->sin_addr; 1265 DDALOG(LOG_DEBUG) "dda%d: ddaoutput: dst = %d.%d.%d.%d\n", 1266 ifp->if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 1267 imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG; 1268 } 1269 #endif DDADEBUG 1270 1271 if ((ds->dda_if.if_flags & IFF_UP) == 0) 1272 return (ENETDOWN); 1273 1274 switch (dst->sin_family) { 1275 1276 #ifdef INET 1277 case AF_INET: 1278 break; 1279 #endif INET 1280 1281 default: 1282 DMESG(ifp->if_unit, 2, 1283 (DDALOG(LOG_ERR) "dda%d: can't handle af%d\n", ifp->if_unit, 1284 dst->sin_family DDAELOG)); 1285 m_freem(m0); 1286 return (EAFNOSUPPORT); 1287 } 1288 1289 #ifdef DDADEBUG 1290 if (DDADBCH(2, ifp->if_unit)) { 1291 imp_addr.ip = dst->sin_addr; 1292 DDALOG(LOG_DEBUG) "dda%d: ddaoutput: dst = %d.%d.%d.%d\n", 1293 ifp->if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 1294 imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG; 1295 } 1296 #endif DDADEBUG 1297 1298 /* Mod to V1.5b ==> V1.5b1 */ 1299 /* In 4.3, the IP code may pass mbuf chains with 0-length mbufs */ 1300 /* This causes "transfer count = 0" messages and might even */ 1301 /* cause actual garbage data transmission if the mbuf is at the */ 1302 /* end of the chain (we don't think it ever will be, but one */ 1303 /* can't be too sure...so we scan the chain first). */ 1304 /* WE DO ASSUME that there is at least one nonempty mbuf! */ 1305 /* (ULTRIX: we don't know, but the code is at worst harmless) */ 1306 1307 while (m0->m_len == 0) { 1308 m = m0; 1309 m0 = m0->m_next; 1310 m->m_next = 0; 1311 m_freem(m); 1312 } 1313 /* Now we know the first mbuf (at m0) is not zero length */ 1314 prev = m0; 1315 m = m0->m_next; 1316 while (m) { 1317 if (m->m_len == 0) { 1318 prev->m_next = m->m_next; 1319 m->m_next = 0; 1320 m_freem(m); 1321 m = prev->m_next; 1322 } else { 1323 prev = m; 1324 m = m->m_next; 1325 } 1326 } 1327 m = m0; /* reset m to beginning of modified chain */ 1328 1329 s = splimp(); /* disable interrrupts */ 1330 1331 /* try to find an LCN */ 1332 1333 if (dc = locate_x25_lcn(ds, dst->sin_addr)) { /* if found */ 1334 #ifdef DDADEBUG 1335 if (DDADBCH(2, ifp->if_unit)) { 1336 DDALOG(LOG_DEBUG) "dda%d: ddaoutput: lcn found = %d\n", ifp->if_unit, 1337 dc->dc_lcn DDAELOG; 1338 } 1339 #endif DDADEBUG 1340 oq = &(dc->dc_oq); /* point to output queue */ 1341 if (IF_QFULL(oq)) { /* if q full */ 1342 IF_DROP(oq); /* drop the data */ 1343 m_freem(m); 1344 ds->dda_if.if_collisions++; /* for netstat display */ 1345 splx(s); 1346 return (ENOBUFS); 1347 } 1348 IF_ENQUEUE(oq, m); /* otherwise queue it */ 1349 dda_start(ds, dc); /* and try to output */ 1350 splx(s); 1351 return (0); 1352 } else { /* if no circuit available */ 1353 IF_DROP(&ifp->if_snd); /* drop the data */ 1354 m_freem(m); 1355 splx(s); 1356 return (EHOSTUNREACH); 1357 } 1358 1359 } 1360 1361 1362 1363 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1364 /*%% DDATIMER() %%*/ 1365 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1366 /* */ 1367 /* Purpose: */ 1368 /* */ 1369 /* This routine is entered to perform timer management. The */ 1370 /* LCN table is scanned for active timers (nonzero) which are */ 1371 /* decremented. If a timer expires (becomes zero), the proper */ 1372 /* action is taken. */ 1373 /* */ 1374 /* */ 1375 /* Call: ddatimer(unit) */ 1376 /* Arguments: unit: ACP device unit number */ 1377 /* Returns: nothing */ 1378 /* Called by: ddainit() */ 1379 /* Calls to: splimp() */ 1380 /* send_restart() */ 1381 /* clear_lcn() */ 1382 /* splx() */ 1383 /* */ 1384 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1385 1386 int 1387 ddatimer(unit) 1388 int unit; 1389 { 1390 register struct dda_softc *ds = &dda_softc[unit]; 1391 register struct dda_cb *dc; 1392 register int s, lcn; 1393 1394 #ifdef DDADEBUG 1395 if (DDADBCH(3, unit)) { 1396 DDALOG(LOG_DEBUG) "dda%d: ddatimer()\n", unit DDAELOG; 1397 } 1398 #endif DDADEBUG 1399 1400 ds->dda_if.if_timer = DDA_TIMEOUT; /* restart timer */ 1401 1402 dc = ds->dda_cb; 1403 1404 s = splimp(); 1405 1406 /* LCNLINK */ 1407 for (lcn = 0; lcn <= nddach[unit]; lcn++) { /* scan all LCN's */ 1408 #ifdef DDADEBUG 1409 if (dc->dc_out_t && lcn > 0 && (--(dc->dc_out_t) == 0)) { 1410 DDALOG(LOG_DEBUG) "dda%d: write completion timeout lcn %d\n", 1411 unit, lcn DDAELOG; 1412 } 1413 #endif 1414 if (dc->dc_timer && (--(dc->dc_timer) == 0)) { /* if a timer expired */ 1415 if (dc->dc_state == LC_RESTART) { /* if a restart was out */ 1416 send_restart(ds); /* send another one */ 1417 break; 1418 } else { /* otherwise */ 1419 #ifdef DDA_PAD_OR_RAW 1420 /* if it is not an X.29 connection */ 1421 if ((dc->dc_flags & (DC_X29W | DC_X29 | DC_RAW)) == 0) 1422 #endif 1423 clear_lcn(ds, dc); /* clear the LCN */ 1424 } 1425 } 1426 dc++; 1427 } 1428 splx(s); 1429 } 1430 1431 1432 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1433 /*%% DIAGS_COMPLETED() %%*/ 1434 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1435 /* */ 1436 /* Purpose: */ 1437 /* */ 1438 /* This routine checks to see that power up diagnostics have completed*/ 1439 /* It waits for a while if necessary. */ 1440 /* Call: diags_completed(ds) */ 1441 /* Argument: ds - pointer to softc structure; */ 1442 /* Returns: 0 if board is up, EINTR if it never came on line. */ 1443 /* Called by: ddaioctl() */ 1444 /* Calls to: */ 1445 /* */ 1446 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1447 1448 diags_completed(ds) 1449 struct dda_softc *ds; 1450 { 1451 int nretries = 10; 1452 1453 /* 1454 * It's overkill to check this on EVERY ioctl, because it only matters if 1455 * we are going to touch the board. But the driver has had repeated 1456 * problems with not checking it when it should have - overkill is 1457 * preferred. The delays are here rather then in the acpconfig program 1458 * due to a bug in acpconfig. They will only be executed during 1459 * /etc/rc.local when the board has not had a chance to do the "B" 1460 * interrupt yet. At that time the machine will be running essentially 1461 * single thread so it won't really matter where the delays are. (ie, if 1462 * we put the delay into acpconfig and kept calling here 10 times, the 1463 * machine would not do anything else useful in the meantime - might as 1464 * well loop here). 1465 */ 1466 while (((ds->dda_flags & DDAF_OK) == 0) && nretries-- > 0) 1467 DELAY(3000000); 1468 if ((ds->dda_flags & DDAF_OK) == 0) /* never came on line... */ 1469 return (EINTR); 1470 else 1471 return (0); 1472 } 1473 1474 1475 1476 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1477 /*%% %%*/ 1478 /*%% LOCAL FUNCTIONS %%*/ 1479 /*%% %%*/ 1480 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1481 1482 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1483 /*%% SEND_CONFIG() %%*/ 1484 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1485 /* */ 1486 /* Purpose: */ 1487 /* */ 1488 /* Send a Set System Parameters Message to the front end in */ 1489 /* response to an ACPCONFIG command from the user. */ 1490 /* */ 1491 /* Call: send_config(ds, p) */ 1492 /* Argument: ds: pointer to ACP device control structure */ 1493 /* p: pointer to the message */ 1494 /* Returns: nothing */ 1495 /* Called by: ddaioctl() */ 1496 /* Calls to: MGET() */ 1497 /* DDALOG() */ 1498 /* mtod() */ 1499 /* bcopy() */ 1500 /* sizeof() */ 1501 /* start_supr() */ 1502 /* */ 1503 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1504 1505 PRIVATE void 1506 send_config(ds, p) 1507 struct dda_softc *ds; 1508 u_char *p; 1509 { 1510 struct mbuf *m; 1511 register u_char *bp; 1512 int length; 1513 1514 #ifdef DDADEBUG 1515 if (DDADBCH(7, ds->dda_if.if_unit)) { 1516 DDALOG(LOG_DEBUG) "dda%d: send_config()\n", ds->dda_if.if_unit DDAELOG; 1517 } 1518 #endif DDADEBUG 1519 1520 MGET(m, M_DONTWAIT, MT_DATA); 1521 if (m == 0) { 1522 DMESG(ds->dda_if.if_unit, 18, 1523 (DDALOG(LOG_ERR) "dda%d: can't get bfr for acpconfig msg\n", 1524 ds->dda_if.if_unit DDAELOG)); 1525 return; 1526 } 1527 bp = mtod(m, u_char *); /* point to data section of mbuf */ 1528 1529 length = p[MSG_LENGTH] + MSG_OFFSET; /* msg length */ 1530 if (length > MLEN - 1) { 1531 1532 /* 1533 * Supervisory messages have to fit in a small mbuf. The driver 1534 * itself is careful never to get in trouble this way, but now that 1535 * we have "-m" the user could. Dropping such a message is not 1536 * likely to cause any big problems, and the user can rephrase the 1537 * request. 1538 */ 1539 DMESG(ds->dda_if.if_unit, 19, 1540 (DDALOG(LOG_ERR) "dda%d: supervisor message too long\n", 1541 ds->dda_if.if_unit DDAELOG)); 1542 m->m_next = 0; 1543 m_freem(m); 1544 return; 1545 } 1546 bcopy(p, bp, length); 1547 m->m_len = length; /* set msg length */ 1548 1549 #ifdef DDADEBUG 1550 if (DDADBCH(8, ds->dda_if.if_unit)) { 1551 prt_bytes(ds->dda_if.if_unit, "send_config", bp, length); 1552 } 1553 #endif DDADEBUG 1554 1555 start_supr(ds, m); 1556 } 1557 1558 1559 1560 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1561 /*%% LOCATE_X25_LCN() %%*/ 1562 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1563 /* */ 1564 /* Purpose: */ 1565 /* */ 1566 /* This routine tries to locate an X25 LCN associated with a */ 1567 /* remote internet address. A linear search of the LCN table */ 1568 /* is made for a matching address. If the search succeeds, the */ 1569 /* LCN is returned. If the search fails, the LCN table is */ 1570 /* searched for an unused table entry. If an unused table */ 1571 /* entry is found, an X25 call is generated to the host */ 1572 /* specified in the destination internet address. If no LCN is */ 1573 /* available, zero is returned. */ 1574 /* */ 1575 /* Call: locate_x25_lcn(ds, ip_addr) */ 1576 /* Argument: ds: pointer to dev control block struct */ 1577 /* ip_addr: IP address */ 1578 /* Returns: pointer to the dda control block which */ 1579 /* contains LCN, else zero for failure */ 1580 /* Called by: ddaoutput() */ 1581 /* Calls to: convert_ip_addr() */ 1582 /* make_x25_call() */ 1583 /* */ 1584 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1585 1586 PRIVATE struct dda_cb * 1587 locate_x25_lcn(ds, ip_addr) 1588 struct dda_softc *ds; 1589 struct in_addr ip_addr; 1590 { 1591 register int lcn, maxlcn; 1592 register struct dda_cb *dc; 1593 union imp_addr imp_addr; 1594 1595 #ifdef DDADEBUG 1596 if (DDADBCH(9, ds->dda_if.if_unit)) { 1597 DDALOG(LOG_DEBUG) "dda%d: locate_x25_lcn()\n", 1598 ds->dda_if.if_unit DDAELOG; 1599 } 1600 #endif DDADEBUG 1601 1602 imp_addr.ip = ip_addr; /* DDN X.25 doesn't know net number */ 1603 1604 if (!(ds->dda_init & DDA_PDN)) { 1605 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 1606 imp_addr.imp.s_net = 0; 1607 imp_addr.imp.s_lh = 0; 1608 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 1609 imp_addr.imp.s_net = 0; 1610 imp_addr.imp.s_host = 0; 1611 } else { /* class C, should check for class C */ 1612 imp_addr.imp.s_net = 0; 1613 imp_addr.imp.s_host = 0; 1614 imp_addr.imp.s_lh = 0; 1615 } 1616 } 1617 /* LCNLINK */ 1618 maxlcn = nddach[ds->dda_if.if_unit]; 1619 dc = &(ds->dda_cb[1]); /* scan LCN table for addr match */ 1620 for (lcn = 1; lcn <= maxlcn; lcn++) { 1621 if ((dc->dc_key.key_addr.s_addr == imp_addr.ip.s_addr) 1622 && (dc->dc_state == LC_CALL_PENDING || dc->dc_state == LC_DATA_IDLE)) 1623 return (dc); /* return LCN */ 1624 dc++; 1625 } 1626 1627 if ((dc = find_free_lcn(ds)) == 0) 1628 return (0); 1629 1630 ddacb_user_data[0] = (u_char) 0; /* we have no user data */ 1631 1632 if (convert_ip_addr(ip_addr, ddacb_called_addr, ds) 1633 && make_x25_call(ds, dc, ip_addr, X25_PROTO_IP)) { 1634 /* addr can be converted */ 1635 dc->dc_inaddr = ip_addr; /* store dest ip addr */ 1636 dc->dc_key.key_addr.s_addr = imp_addr.ip.s_addr; 1637 /* store match key */ 1638 #ifdef DDADEBUG 1639 if (DDADBCH(9, ds->dda_if.if_unit)) { 1640 imp_addr.ip = ip_addr; 1641 DDALOG(LOG_DEBUG) 1642 "dda%d: locate_x25_lcn: made call to %d.%d.%d.%d\n", 1643 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 1644 imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG; 1645 1646 } 1647 #endif DDADEBUG 1648 return (dc); /* and return the LCN */ 1649 } else { 1650 return (0); /* give up */ 1651 } 1652 } 1653 1654 1655 1656 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1657 /*%% FIND_FREE_LCN() %%*/ 1658 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1659 /* */ 1660 /* Purpose: */ 1661 /* */ 1662 /* This routine tries to locate a free X25 LCN. */ 1663 /* The LCN table is searched for an unused entry. */ 1664 /* If no LCN is available, zero is returned. */ 1665 /* */ 1666 /* Call: find_free_lcn(ds) */ 1667 /* Argument: ds: pointer to dev control block struct */ 1668 /* Returns: pointer to the dda control block which */ 1669 /* contains LCN, else zero for failure */ 1670 /* Called by: locate_x25_lcn() */ 1671 /* supr_msg() */ 1672 /* xxcntl() */ 1673 /* Calls to: DDALOG() */ 1674 /* */ 1675 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1676 1677 PRIVATE struct dda_cb * 1678 find_free_lcn(ds) 1679 struct dda_softc *ds; 1680 { 1681 struct dda_cb *dc; 1682 register int lcn, maxlcn, dwnflg = 0; 1683 1684 /* LCNLINK */ 1685 dc = &(ds->dda_cb[1]); /* scan LCN table for free entry */ 1686 maxlcn = nddach[ds->dda_if.if_unit]; 1687 for (lcn = 1; lcn <= maxlcn; lcn++) { 1688 #ifdef DDA_PAD_OR_RAW 1689 if (dc->dc_state == LC_IDLE && (dc->dc_flags & (DC_X29W | DC_X29 | DC_RAW)) == 0) 1690 #else 1691 if (dc->dc_state == LC_IDLE) 1692 #endif DDA_PAD_OR_RAW 1693 break; 1694 else if (dc->dc_state == LC_RESTART || dc->dc_state == LC_DOWN) 1695 dwnflg = 1; 1696 dc++; 1697 } 1698 1699 /* LCNLINK */ 1700 if (lcn > maxlcn) { /* if we didn't find a free entry */ 1701 if (LOG_BUSY) { 1702 if (dwnflg) 1703 DDALOG(LOG_ERR) "dda%d: no circuits available (link not up)\n", 1704 ds->dda_if.if_unit DDAELOG; 1705 else 1706 DDALOG(LOG_ERR) "dda%d: all circuits in use\n", 1707 ds->dda_if.if_unit DDAELOG; 1708 } 1709 return (0); /* return empty handed */ 1710 } 1711 return (dc); 1712 } 1713 1714 1715 1716 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1717 /*%% CONVERT_IP_ADDR() %%*/ 1718 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1719 /* */ 1720 /* Purpose: */ 1721 /* */ 1722 /* Based on the type of X.25 service, this routine performs */ 1723 /* one of two functions. For PDN X.25 service, the address */ 1724 /* translation table is searched for presence of local X.25 */ 1725 /* address (which was entered by the user via acpconfig). */ 1726 /* */ 1727 /* For DDN X.25 service, this routine accepts an internet */ 1728 /* address and attempts to translate to an equivalent X25 */ 1729 /* address. This follows the guidelines in the DDN X25 */ 1730 /* interface spec. The resultant X25 address is stored in the */ 1731 /* X25 called addr buffer. */ 1732 /* */ 1733 /* NOTE: Although front end was designed to accept ASCII coded */ 1734 /* digits for the address fields, we only supply the binary */ 1735 /* values. The front end only uses low four bits to extract */ 1736 /* the binary value from the ASCII digits, so this works out. */ 1737 /* */ 1738 /* */ 1739 /* */ 1740 /* */ 1741 /* */ 1742 /* */ 1743 /* Call: convert_ip_addr(ip_addr, x25addr, ds) */ 1744 /* Argument: ip_addr: IP address */ 1745 /* x25addr: X.25 address */ 1746 /* ds: &dda_softc[unit] */ 1747 /* Returns: 1 for success */ 1748 /* Called by: locate_x25_lcn() */ 1749 /* make_x25_call() */ 1750 /* ddaioctl() */ 1751 /* Calls to: bcopy() */ 1752 /* */ 1753 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1754 1755 PRIVATE boolean 1756 convert_ip_addr(ip_addr, x25addr, ds) 1757 struct in_addr ip_addr; 1758 u_char x25addr[]; 1759 struct dda_softc *ds; 1760 1761 { 1762 register struct dda_addr_tr *atp, *hip, *lop; 1763 register int temp; 1764 union imp_addr imp_addr; 1765 1766 /****************************************************************/ 1767 /* processing for Public Data Network (PDN) X.25 service */ 1768 /* search address translation table for local address */ 1769 /****************************************************************/ 1770 1771 if (ds->dda_init & DDA_PDN) { 1772 x25addr[0] = 0; /* clear result X.25 address length */ 1773 lop = &dda_addr_tr[ds->dda_if.if_unit][0]; /* set up for binary 1774 * search */ 1775 hip = &dda_addr_tr[ds->dda_if.if_unit][dda_num_addr_tr[ds->dda_if.if_unit]]; 1776 while (lop < hip - 1) { /* binary search loop */ 1777 atp = lop + (hip - lop) / 2; 1778 if (atp->ip_addr > ip_addr.s_addr) 1779 hip = atp; 1780 else 1781 lop = atp; 1782 } 1783 if (lop->ip_addr == ip_addr.s_addr) 1784 bcopy(lop->x25_addr, x25addr, MAXADDRLEN); 1785 } 1786 /****************************************************************/ 1787 /* processing for DDN Standard or Basic X.25 service */ 1788 /* convert IP address to X.25 address */ 1789 /****************************************************************/ 1790 1791 else { 1792 int imp_no, imp_port; 1793 1794 1795 imp_addr.ip = ip_addr; 1796 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 1797 imp_no = imp_addr.imp.s_impno; 1798 imp_port = imp_addr.imp.s_host; 1799 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 1800 imp_no = imp_addr.imp.s_impno; 1801 imp_port = imp_addr.imp.s_lh; 1802 } else { /* class C */ 1803 imp_no = imp_addr.imp.s_impno / 32; 1804 imp_port = imp_addr.imp.s_impno % 32; 1805 } 1806 1807 x25addr[0] = 12; /* set addr length */ 1808 x25addr[1] = 0; /* clear DNIC */ 1809 x25addr[2] = 0; 1810 x25addr[3] = 0; 1811 x25addr[4] = 0; 1812 1813 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 1814 * -> III, s_host -> HH */ 1815 x25addr[5] = 0; /* set flag bit */ 1816 x25addr[6] = imp_no / 100; 1817 x25addr[7] = (imp_no % 100) / 10; 1818 x25addr[8] = imp_no % 10; 1819 x25addr[9] = imp_port / 10; 1820 x25addr[10] = imp_port % 10; 1821 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 1822 * _host * 256 + s_impno -> RRRRR */ 1823 temp = (imp_port << 8) + imp_no; 1824 x25addr[5] = 1; 1825 x25addr[6] = temp / 10000; 1826 x25addr[7] = (temp % 10000) / 1000; 1827 x25addr[8] = (temp % 1000) / 100; 1828 x25addr[9] = (temp % 100) / 10; 1829 x25addr[10] = temp % 10; 1830 } 1831 1832 x25addr[11] = 0; /* clear rest of addr */ 1833 x25addr[12] = 0; 1834 } 1835 1836 #ifdef DDADEBUG 1837 if (DDADBCH(11, ds->dda_if.if_unit)) { 1838 imp_addr.ip = ip_addr; 1839 DDALOG(LOG_DEBUG) "dda%d: convert_ip_addr: %d.%d.%d.%d ==> %s\n", 1840 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 1841 imp_addr.imp.s_lh, imp_addr.imp.s_impno, 1842 fmt_x25(&x25addr[1], (int) x25addr[0]) DDAELOG; 1843 } 1844 #endif DDADEBUG 1845 1846 return (x25addr[0] ? 1 : 0); 1847 } 1848 1849 1850 1851 1852 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1853 /*%% CONVERT_X25_ADDR() %%*/ 1854 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1855 /* */ 1856 /* Purpose: */ 1857 /* */ 1858 /* This routine accepts an X25 address and attempts to */ 1859 /* translate to an equivalent internet address. For DDA this */ 1860 /* follows the guidelines in the DDA X25 interface spec. The */ 1861 /* resultant internet address is returned to the caller. */ 1862 /* */ 1863 /* Call: convert_x25_addr(x25addr, ds) */ 1864 /* Argument: x25addr: X.25 address */ 1865 /* ds: &dda_softc[unit] */ 1866 /* dc: pointer to allocated dda_cb structure */ 1867 /* Returns: IP address for success, else zero for fail */ 1868 /* Called by: supr_msg() */ 1869 /* Calls to: DDALOG() */ 1870 /* */ 1871 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1872 1873 PRIVATE u_long 1874 convert_x25_addr(x25addr, ds, dc) 1875 u_char x25addr[]; 1876 struct dda_softc *ds; 1877 struct dda_cb *dc; 1878 1879 { 1880 register int cnt, temp; 1881 union imp_addr imp_addr; 1882 register struct dda_addr_tr *atp; 1883 1884 dc->dc_inaddr.s_addr = imp_addr.ip.s_addr = 0L; 1885 if (ds->dda_init & DDA_PDN) { 1886 for (atp = &dda_addr_tr[ds->dda_if.if_unit][0]; 1887 atp < &dda_addr_tr[ds->dda_if.if_unit][dda_num_addr_tr[ds->dda_if.if_unit]]; atp++) { 1888 if (bcmp((char *) atp->x25_addr, (char *) x25addr, x25addr[0] + 1) == 0) { 1889 /* set key address and print address up */ 1890 dc->dc_inaddr.s_addr = imp_addr.ip.s_addr = atp->ip_addr; 1891 break; 1892 } 1893 } 1894 } else { 1895 int imp_no, imp_port; 1896 struct in_addr my_addr; 1897 1898 my_addr = ds->dda_ipaddr; 1899 if (((cnt = x25addr[0]) < MINADDRLEN - 1) || (cnt > MAXADDRLEN - 1)) { 1900 DMESG(ds->dda_if.if_unit, 20, 1901 (DDALOG(LOG_ERR) "dda%d: illegal X25 address length!\n", 1902 ds->dda_if.if_unit DDAELOG)); 1903 return (0L); 1904 } 1905 switch (x25addr[5] & 0x0f) { 1906 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 1907 imp_no = 1908 ((int) (x25addr[6] & 0x0f) * 100) + 1909 ((int) (x25addr[7] & 0x0f) * 10) + 1910 ((int) (x25addr[8] & 0x0f)); 1911 1912 1913 imp_port = 1914 ((int) (x25addr[9] & 0x0f) * 10) + 1915 ((int) (x25addr[10] & 0x0f)); 1916 break; 1917 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 1918 temp = ((int) (x25addr[6] & 0x0f) * 10000) 1919 + ((int) (x25addr[7] & 0x0f) * 1000) 1920 + ((int) (x25addr[8] & 0x0f) * 100) 1921 + ((int) (x25addr[9] & 0x0f) * 10) 1922 + ((int) (x25addr[10] & 0x0f)); 1923 1924 imp_port = temp >> 8; 1925 imp_no = temp & 0xff; 1926 break; 1927 default: 1928 DMESG(ds->dda_if.if_unit, 21, 1929 (DDALOG(LOG_ERR) "dda%d: illegal X25 address format!\n", 1930 ds->dda_if.if_unit DDAELOG)); 1931 return (0L); 1932 } 1933 1934 dc->dc_inaddr = imp_addr.ip = my_addr; /* use local net number */ 1935 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 1936 imp_addr.imp.s_net = 0; /* mask net number */ 1937 imp_addr.imp.s_lh = 0; /* mask logical host */ 1938 imp_addr.imp.s_host = imp_port; 1939 ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_host = imp_port; 1940 imp_addr.imp.s_impno = imp_no; 1941 ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_no; 1942 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 1943 imp_addr.imp.s_net = 0; 1944 imp_addr.imp.s_lh = imp_port; 1945 ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_lh = imp_port; 1946 imp_addr.imp.s_host = 0; 1947 imp_addr.imp.s_impno = imp_no; 1948 ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_no; 1949 } else { /* class C */ 1950 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 1951 ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_addr.imp.s_impno; 1952 imp_addr.imp.s_lh = 0; 1953 imp_addr.imp.s_host = 0; 1954 imp_addr.imp.s_net = 0; 1955 } 1956 } 1957 1958 #ifdef DDADEBUG 1959 if (DDADBCH(12, ds->dda_if.if_unit)) { 1960 DDALOG(LOG_DEBUG) "dda%d: convert_x25_addr: %s ==> %d.%d.%d.%d\n", 1961 ds->dda_if.if_unit, fmt_x25(&x25addr[1], (int) x25addr[0]), 1962 imp_addr.imp.s_net, imp_addr.imp.s_host, imp_addr.imp.s_lh, 1963 imp_addr.imp.s_impno DDAELOG; 1964 } 1965 #endif DDADEBUG 1966 1967 return (imp_addr.ip.s_addr); 1968 } 1969 1970 1971 1972 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1973 /*%% MAKE_X25_CALL() %%*/ 1974 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 1975 /* */ 1976 /* Purpose: */ 1977 /* */ 1978 /* This routine places an X25 call using the X25 Call Msg */ 1979 /* buffer. The calling LCN is placed in the appropriate state */ 1980 /* and a timer is started. Based on dda_init flag, implement */ 1981 /* DDN standard or basic service. (If PDN mode is set, then */ 1982 /* the logic for basic service is followed.) */ 1983 /* */ 1984 /* Call: make_x25_call(ds, dc, ip_addr, proto */ 1985 /* udlen, ud) */ 1986 /* Arguments: ds: pointer to device control structure */ 1987 /* dc: pointer to the Logical Channel control */ 1988 /* block structure */ 1989 /* ip_addr: callee's ip address */ 1990 /* proto: protocol identifier byte */ 1991 /* udlen: user data length */ 1992 /* ud: user data */ 1993 /* Returns: one for success, zero for failure */ 1994 /* Called by: locate_x25_lcn() */ 1995 /* Calls to: MGET() */ 1996 /* mtod() */ 1997 /* convert_ip_addr() */ 1998 /* bcopy() */ 1999 /* IF_ENQUEUE() */ 2000 /* start_supr() */ 2001 /* */ 2002 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2003 2004 PRIVATE boolean 2005 make_x25_call(ds, dc, ip_addr, proto, udlen, ud) 2006 register struct dda_softc *ds; 2007 register struct dda_cb *dc; 2008 struct in_addr ip_addr; 2009 u_char proto; 2010 u_char udlen; 2011 u_char *ud; 2012 { 2013 register struct mbuf *m_callbfr; 2014 register u_char *cb; 2015 union imp_addr imp_addr; 2016 2017 #if ACC_BSD == 42 || ACC_ULTRIX == 12 2018 struct sockaddr_in *our_addr; 2019 #endif 2020 2021 #ifdef DDADEBUG 2022 if (DDADBCH(13, ds->dda_if.if_unit)) { 2023 DDALOG(LOG_DEBUG) "dda%d: make_x25_call: lcn used = %d\n", 2024 ds->dda_if.if_unit, dc->dc_lcn DDAELOG; 2025 } 2026 #endif DDADEBUG 2027 2028 MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd 2029 * buffer */ 2030 if (m_callbfr == 0) { 2031 DMESG(ds->dda_if.if_unit, 22, 2032 (DDALOG(LOG_ERR) "dda%d: couldn't get mbuf for call command\n", 2033 ds->dda_if.if_unit DDAELOG)); 2034 return (0); 2035 } 2036 cb = mtod(m_callbfr, u_char *); 2037 2038 if (ds->dda_net_id == TRANSPAC) { 2039 ddacb_calling_addr[0] = 0; /* send a 0 length calling address */ 2040 } else { 2041 #if ACC_BSD == 42 || ACC_ULTRIX == 12 2042 our_addr = (struct sockaddr_in *) & (ds->dda_if.if_addr); 2043 (void) convert_ip_addr(our_addr->sin_addr, ddacb_calling_addr, ds); 2044 #else 2045 (void) convert_ip_addr(ds->dda_ipaddr, ddacb_calling_addr, ds); 2046 #endif 2047 } 2048 2049 ddacb_protocol[0] = 4; 2050 ddacb_protocol[1] = proto; /* protocol type */ 2051 ddacb_protocol[2] = 0; 2052 ddacb_protocol[3] = 0; 2053 ddacb_protocol[4] = 0; 2054 2055 /* 2056 * CCITT standard facilities must precede DDN specific facilities See BBN 2057 * report 5476 section 2.1.2. Firmware preceding rev 0x20 does not 2058 * support packet size / window negotiation. 2059 */ 2060 ddacb_facilities[0] = 0; /* initialize facilities length */ 2061 if (ds->dda_firmrev >= 0x21) { 2062 ddacb_facilities[0] = 0; 2063 if (ds->dda_init & DDA_PKTNEG) { 2064 int n = ddacb_facilities[0]; /* length so far */ 2065 2066 ddacb_facilities[n + 1] = X25_FACIL_PKTSIZE; 2067 ddacb_facilities[n + 2] = PKTSIZE_LARGE; 2068 ddacb_facilities[n + 3] = PKTSIZE_LARGE; 2069 ddacb_facilities[0] += 3; 2070 } 2071 if (ds->dda_init & DDA_WNDNEG) { 2072 int n = ddacb_facilities[0]; /* length so far */ 2073 2074 ddacb_facilities[n + 1] = X25_FACIL_WINSIZE; 2075 ddacb_facilities[n + 2] = WINSIZE_LARGE; 2076 ddacb_facilities[n + 3] = WINSIZE_LARGE; 2077 ddacb_facilities[0] += 3; 2078 } 2079 } 2080 if ((ds->dda_init & (DDA_BASIC | DDA_PDN)) == 0) { /* DDN standard mode, 2081 * tell callee */ 2082 int n = ddacb_facilities[0]; /* length so far */ 2083 2084 ddacb_facilities[0] += 4; /* additional facility bytes */ 2085 ddacb_facilities[n + 1] = DDN_FACIL_MARKER; /* end of CCITT stuff, */ 2086 ddacb_facilities[n + 2] = DDN_FACIL_MARKER; /* and start DDN local */ 2087 ddacb_facilities[n + 3] = X25_FACIL_DDA; /* DDA standard mode */ 2088 ddacb_facilities[n + 4] = FAC_DDASTD; 2089 } 2090 2091 ddacb_cmnd[0] = CALL; /* set command code */ 2092 ddacb_cmnd[1] = dc->dc_lcn << 1; /* set channel id */ 2093 ddacb_cmnd[2] = 0; 2094 ddacb_cmnd[3] = (ddacb_called_addr[0] + 1) + /* tally cmnd ext len */ 2095 (ddacb_calling_addr[0] + 1) + 2096 (ddacb_protocol[0] + 1) + 2097 (ddacb_facilities[0] + 1) + 2098 (ddacb_user_data[0] + 1); 2099 2100 if ((unsigned) ddacb_cmnd[3] + 4 > MLEN) { 2101 DMESG(ds->dda_if.if_unit, 38, (DDALOG(LOG_ERR) 2102 "dda%d: make_x25_call message too large for mbuf (%d bytes)\n", 2103 ds->dda_if.if_unit, (unsigned) ddacb_cmnd[3] + 4 DDAELOG)); 2104 return 0; /* failure */ 2105 } 2106 2107 m_callbfr->m_len = ddacb_cmnd[3] + 4; 2108 2109 /* copy command header */ 2110 bcopy(ddacb_cmnd, cb, 4); 2111 cb += 4; 2112 2113 /* copy called address */ 2114 bcopy(ddacb_called_addr, cb, ddacb_called_addr[0] + 1); 2115 cb += (ddacb_called_addr[0] + 1); 2116 2117 /* copy calling address */ 2118 bcopy(ddacb_calling_addr, cb, ddacb_calling_addr[0] + 1); 2119 cb += (ddacb_calling_addr[0] + 1); 2120 2121 /* copy protocol */ 2122 bcopy(ddacb_protocol, cb, ddacb_protocol[0] + 1); 2123 cb += (ddacb_protocol[0] + 1); 2124 2125 /* copy facilities */ 2126 bcopy(ddacb_facilities, cb, ddacb_facilities[0] + 1); 2127 cb += (ddacb_facilities[0] + 1); 2128 2129 /* copy user data */ 2130 bcopy(ddacb_user_data, cb, ddacb_user_data[0] + 1); 2131 cb += (ddacb_user_data[0] + 1); 2132 2133 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_CALL_PENDING); 2134 dc->dc_state = LC_CALL_PENDING; /* set state */ 2135 dc->dc_timer = TMO_CALL_PENDING; /* start call timeout */ 2136 2137 #ifdef DDADEBUG 2138 if (DDADBCH(13, ds->dda_if.if_unit)) { 2139 prt_bytes(ds->dda_if.if_unit, "make_x25_call: call_bfr", 2140 mtod(m_callbfr, u_char *), m_callbfr->m_len); 2141 } 2142 #endif DDADEBUG 2143 if (LOG_CALLS) { 2144 imp_addr.ip = ip_addr; 2145 DDALOG(LOG_ERR) "dda%d: Calling %d.%d.%d.%d (%s) on lcn %d\n", 2146 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 2147 imp_addr.imp.s_lh, imp_addr.imp.s_impno, 2148 fmt_x25(&ddacb_called_addr[1], (int) ddacb_called_addr[0]), 2149 dc->dc_lcn 2150 DDAELOG; 2151 } 2152 start_supr(ds, m_callbfr); 2153 return (1); 2154 } 2155 2156 2157 2158 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2159 /*%% DDA_START() %%*/ 2160 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2161 /* */ 2162 /* Purpose: */ 2163 /* */ 2164 /* This routine attempts to start output of data queued on a */ 2165 /* specific LCN. If the LCN was not already busy and data is */ 2166 /* available for output, the data is copied into the LCN's I/O */ 2167 /* buffer and a write request queued to the ACP device. Data */ 2168 /* is passed in mbuf(s) from IP to ddaoutput(), ddaoutput() */ 2169 /* queues the data, and the data is dequeued here. */ 2170 /* */ 2171 /* Call: dda_start(ds, dc) */ 2172 /* Arguments: ds: pointer to device control structure */ 2173 /* dc: pointer to the Logical Channel control */ 2174 /* block structure */ 2175 /* Returns: nothing */ 2176 /* Called by: ddaoutput() */ 2177 /* x25_init() */ 2178 /* make_x25_call() */ 2179 /* supr_msg() */ 2180 /* send_supr() */ 2181 /* dda_data() */ 2182 /* dda_supr() */ 2183 /* Calls to: IF_DEQUEUE() */ 2184 /* dda_wrq() */ 2185 /* */ 2186 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2187 2188 PRIVATE void 2189 dda_start(ds, dc) 2190 register struct dda_softc *ds; 2191 register struct dda_cb *dc; 2192 { 2193 register struct mbuf *m; 2194 register struct hdx_chan *hc = &dc->dc_wchan; 2195 register int s; 2196 2197 #ifdef DDADEBUG 2198 if (DDADBCH(14, ds->dda_if.if_unit)) { 2199 DDALOG(LOG_DEBUG) "dda%d: dda_start()\n", ds->dda_if.if_unit DDAELOG; 2200 } 2201 #endif DDADEBUG 2202 2203 /* 2204 * If output isn't active, attempt to start sending a new packet. 2205 */ 2206 2207 if ((dc->dc_flags & DC_OBUSY) || (dc->dc_oq.ifq_len == 0) || 2208 ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE))) { 2209 return; 2210 } 2211 if (dc->dc_lcn != 0) 2212 dc->dc_timer = tmo_data_idle; 2213 /* 2214 * Raise priority whenever touching dc_oq because 2215 * the mbufs on this queue may be asynchronously 2216 * freed upon receipt of a line status msg, restart, 2217 * clear, or reset. 2218 */ 2219 s = splimp(); 2220 IF_DEQUEUE(&dc->dc_oq, m); 2221 splx(s); 2222 if (m == 0) { /* XXX this is a bug catcher XXX */ 2223 2224 DMESG(ds->dda_if.if_unit, 24, 2225 (DDALOG(LOG_ERR) "dda%d: dequeued NULL mbuf in IP output chain!\n", 2226 ds->dda_if.if_unit DDAELOG)); 2227 DMESG(ds->dda_if.if_unit, 24, 2228 (DDALOG(LOG_ERR) "RESET dda%d MANUALLY: use /etc/acpconfig dda%d -z\n", 2229 ds->dda_if.if_unit, ds->dda_if.if_unit DDAELOG)); 2230 2231 ds->dda_if.if_flags &= ~(IFF_RUNNING | IFF_UP); 2232 hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_DISABLED); 2233 ds->dda_state = S_DISABLED; 2234 dda_disable(ds->dda_if.if_unit); 2235 return; 2236 } 2237 s = splimp(); 2238 hc->hc_mbuf = m; 2239 hc->hc_curr = m; 2240 #ifdef DDA_PAD_OR_RAW /* crufty kludge to get the Qbit */ 2241 if (dc->dc_flags & (DC_X29 | DC_X29W | DC_RAW)) { /* raw or x29? */ 2242 if (m->m_len < (MLEN - 1)) /* small mbuf? */ 2243 hc->hc_sbfc = m->m_dat[MLEN - 1]; /* ok, get the subfunc byte */ 2244 else 2245 hc->hc_sbfc = 0; /* subfunc must be zero for large buffers */ 2246 } else 2247 hc->hc_sbfc = 0; /* subfunc must be zero for ip buffers */ 2248 #else 2249 hc->hc_sbfc = 0; 2250 #endif 2251 splx(s); 2252 dc->dc_flags |= DC_OBUSY; 2253 dda_wrq(ds, hc, 0); /* write request to ACP */ 2254 } 2255 2256 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2257 /*%% DDA_DATA() %%*/ 2258 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2259 /* */ 2260 /* Purpose: */ 2261 /* */ 2262 /* This routine is called when a data channel I/O completes. */ 2263 /* If the completion was for a write, an attempt is made to */ 2264 /* start output on the next packet waiting for output on that */ 2265 /* LCN. If the completion was for a read, the received packet */ 2266 /* is sent to the IP input queue (if no error) and another read */ 2267 /* is started on the LCN. */ 2268 /* */ 2269 /* Call: dda_data(ds, hc, cc, cnt) */ 2270 /* Argument: ds: device control block */ 2271 /* hc: half duplex channel control block */ 2272 /* cc: Mailbox I/O completion status */ 2273 /* cnt: byte count */ 2274 /* Returns: nothing */ 2275 /* Called by: ddainta() */ 2276 /* Calls to: m_freem() */ 2277 /* dda_start() */ 2278 /* IF_QFULL() */ 2279 /* IF_DROP() */ 2280 /* IF_ENQUEUE() */ 2281 /* schednetisr() */ 2282 /* dda_rrq() */ 2283 /* dda_wrq() */ 2284 /* */ 2285 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2286 2287 PRIVATE void 2288 dda_data(ds, hc, cc, cnt) 2289 register struct dda_softc *ds; 2290 register struct hdx_chan *hc; 2291 int cc, cnt; 2292 { 2293 register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]); 2294 struct ifqueue *inq = &ipintrq; /* IP input queue */ 2295 2296 /* note that this routine is a weird case in which Ultrix 2.0 behaves like 2297 * a 4.2 system rather than a 4.3 system. This is reflected in the structure 2298 * of conditional compilation segments. 2299 */ 2300 #if ACC_BSD > 42 /* 4.3bsd or newer */ 2301 register struct mbuf *m, *mb; 2302 struct ifnet *ifp; 2303 #else /* 4.2, or all flavors of Ultrix */ 2304 register struct mbuf *m; 2305 #endif 2306 2307 #ifdef DDADEBUG 2308 if (DDADBCH(18, ds->dda_if.if_unit)) { 2309 DDALOG(LOG_DEBUG) "dda%d: dda_data: chan=%d cc=%x cnt=%x\n", 2310 ds->dda_if.if_unit, hc->hc_chan, cc, cnt DDAELOG; 2311 } 2312 #endif DDADEBUG 2313 2314 #if ACC_BSD > 42 2315 ifp = &ds->dda_if; 2316 #endif 2317 2318 if (hc->hc_chan & 0x01) { /* was it read or write? *//* write, fire up 2319 * next output */ 2320 #ifdef DDADEBUG 2321 dc->dc_out_t = TMO_OFF; /* turn off output completion timer */ 2322 #endif 2323 hc = &dc->dc_wchan; 2324 if ((hc->hc_func != DDAABT) && (hc->hc_curr = hc->hc_curr->m_next)) 2325 dda_wrq(ds, hc, 0); 2326 else { 2327 m_freem(hc->hc_mbuf); 2328 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2329 if (hc->hc_func == DDAABT) { 2330 hc->hc_func &= ~DDAABT; 2331 hc->hc_inv &= ~INVALID_MBUF; 2332 } else 2333 ds->dda_if.if_opackets++; 2334 dc->dc_flags &= ~DC_OBUSY; 2335 dda_start(ds, dc); 2336 } 2337 } else { /* read, process rcvd packet */ 2338 hc = &dc->dc_rchan; 2339 2340 #ifdef DDADEBUG 2341 if (DDADBCH(19, ds->dda_if.if_unit)) { 2342 u_char *p; 2343 2344 p = mtod(hc->hc_curr, u_char *); 2345 prt_bytes(ds->dda_if.if_unit, "received data", p, (cnt < 64 ? cnt : 64)); 2346 } 2347 #endif DDADEBUG 2348 2349 if (cc == DDAIOCOK) { /* Queue good packet for input */ 2350 #ifdef DDADEBUG 2351 if (DDADBCH(19, ds->dda_if.if_unit)) { 2352 DDALOG(LOG_DEBUG) "dda%d: dda_data: chan=%d DDAIOCOK\n", 2353 ds->dda_if.if_unit, hc->hc_chan DDAELOG; 2354 } 2355 #endif DDADEBUG 2356 ds->dda_if.if_ipackets++; 2357 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE); 2358 if (dc->dc_state == LC_DATA_IDLE) 2359 dc->dc_timer = tmo_data_idle; 2360 hc->hc_curr->m_len += cnt; /* update byte count */ 2361 m = hc->hc_mbuf; /* que mbuf chain */ 2362 2363 #if ACC_BSD > 42 2364 /* Prepend ifp pointer for 4.3 */ 2365 MGET(mb, M_DONTWAIT, MT_DATA); 2366 if (mb == 0) { 2367 DMESG(ds->dda_if.if_unit, 26, 2368 (DDALOG(LOG_ERR) "dda%d: couldn't get mbuf for ifp header\n", 2369 ds->dda_if.if_unit DDAELOG)); 2370 m_freem(m); 2371 return; 2372 } 2373 *(mtod(mb, struct ifnet **)) = ifp; 2374 mb->m_len = sizeof(ifp); 2375 mb->m_next = m; 2376 2377 if (IF_QFULL(inq)) { 2378 IF_DROP(inq); 2379 m_freem(mb); 2380 } else { 2381 IF_ENQUEUE(inq, mb); 2382 schednetisr(NETISR_IP); 2383 } 2384 #else 2385 if (IF_QFULL(inq)) { 2386 IF_DROP(inq); 2387 m_freem(m); 2388 } else { 2389 IF_ENQUEUE(inq, m); 2390 schednetisr(NETISR_IP); 2391 } 2392 #endif 2393 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2394 } else if (cc == DDAIOCOKP) { /* good completion, more data pending */ 2395 hc->hc_curr->m_len += cnt; 2396 } else { 2397 m_freem(hc->hc_mbuf); 2398 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2399 } 2400 /* hang a new data read */ 2401 dda_rrq(ds, hc); 2402 } 2403 } 2404 2405 2406 2407 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2408 /*%% DDA_SUPR() %%*/ 2409 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2410 /* */ 2411 /* Purpose: */ 2412 /* */ 2413 /* This routine is called when a supervisor I/O completes. */ 2414 /* If the completion was for a write, an attempt is made to */ 2415 /* start output on the next supervisor command waiting for */ 2416 /* output. If the completion was for a read, the received */ 2417 /* supervisor message is processed and another read is started. */ 2418 /* */ 2419 /* Call: dda_supr(ds, hc, cc) */ 2420 /* Argument: ds: device control block */ 2421 /* hc: half duplex channel control block */ 2422 /* cc: Mailbox I/O completion status */ 2423 /* Returns: nothing */ 2424 /* Called by: ddainta() */ 2425 /* Calls to: dda_start() */ 2426 /* mtod() */ 2427 /* supr_msg() */ 2428 /* m_free() */ 2429 /* dda_rrq() */ 2430 /* */ 2431 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2432 2433 PRIVATE void 2434 dda_supr(ds, hc, cc, cnt) 2435 register struct dda_softc *ds; 2436 struct hdx_chan *hc; 2437 int cc; 2438 int cnt; 2439 { 2440 register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]); 2441 u_char *p; 2442 2443 #ifdef DDADEBUG 2444 if (DDADBCH(20, ds->dda_if.if_unit)) { 2445 DDALOG(LOG_DEBUG) "dda%d: dda_supr: chan=%d cc=%x\n", 2446 ds->dda_if.if_unit, hc->hc_chan, cc DDAELOG; 2447 } 2448 #endif DDADEBUG 2449 2450 /* an odd-numbered channel indicates a write */ 2451 /* the supr msg is assumed to be in 1 mbuf */ 2452 2453 if (hc->hc_chan & 0x01) { 2454 m_freem(hc->hc_mbuf); 2455 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2456 dc->dc_flags &= ~DC_OBUSY; 2457 dda_start(ds, dc); 2458 } 2459 /* otherwise, process the read */ 2460 2461 else { 2462 if (cc == DDAIOCOK) { 2463 p = mtod(hc->hc_curr, u_char *); /* point to data in mbuf */ 2464 #ifdef DDA_PAD_OR_RAW 2465 switch (dda_decode_type(ds, p)) { 2466 # ifdef DDA_PADOPT 2467 case 1: 2468 # ifdef DDADEBUG 2469 if (DDADBCH(20, ds->dda_if.if_unit)) { 2470 printf("dda%d: dda_supr(): case 1: chan = %x, p = %x\n", 2471 ds->dda_if.if_unit, hc->hc_chan, *p); 2472 } 2473 # endif DDADEBUG 2474 x29_supr(ds, p); 2475 break; 2476 # endif 2477 # ifdef DDA_RAWOPT 2478 case 2: 2479 # ifdef DDADEBUG 2480 if (DDADBCH(20, ds->dda_if.if_unit)) { 2481 printf("dda%d: dda_supr(): case 2: chan = %x, p = %x\n", 2482 ds->dda_if.if_unit, hc->hc_chan, *p); 2483 } 2484 # endif DDADEBUG 2485 hc->hc_curr->m_len += cnt; 2486 pi_supr(ds, hc->hc_curr); 2487 /* don't free mbuf here */ 2488 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2489 dda_rrq(ds, hc);/* hang a new supr read */ 2490 return; 2491 # endif 2492 default: 2493 supr_msg(ds, p);/* process supervisor message */ 2494 break; 2495 } 2496 #else DDA_PAD_OR_RAW 2497 supr_msg(ds, p); /* process supervisor message */ 2498 #endif DDA_PAD_OR_RAW 2499 } else if (cc == DDAIOCOKP) { 2500 DMESG(ds->dda_if.if_unit, 28, 2501 (DDALOG(LOG_ERR) "dda%d: truncated supervisor message\n", 2502 ds->dda_if.if_unit DDAELOG)); 2503 } 2504 m_freem(hc->hc_mbuf); 2505 hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0; 2506 dda_rrq(ds, hc); /* hang a new supr read */ 2507 } 2508 } 2509 2510 2511 2512 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2513 /*%% SUPR_MSG() %%*/ 2514 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2515 /* */ 2516 /* Purpose: */ 2517 /* */ 2518 /* This routine processes received supervisor messages. */ 2519 /* Depending on the message type, the appropriate action is */ 2520 /* taken. */ 2521 /* */ 2522 /* Call: supr_msg(ds, p) */ 2523 /* Arguments: ds: pointer to dev control block struct */ 2524 /* p: pointer to a character array */ 2525 /* containing the supervisor message */ 2526 /* Returns: nothing */ 2527 /* Called by: dda_supr() */ 2528 /* Calls to: DDALOG() */ 2529 /* IF_DEQUEUE() */ 2530 /* m_freem() */ 2531 /* send_restart() */ 2532 /* send_supr() */ 2533 /* dda_start() */ 2534 /* decode_ring() */ 2535 /* decode_answer() */ 2536 /* convert_x25_addr() */ 2537 /* */ 2538 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2539 2540 PRIVATE void 2541 supr_msg(ds, p) 2542 struct dda_softc *ds; 2543 u_char p[]; 2544 2545 { 2546 register struct dda_cb *dc; 2547 register int lcn; 2548 register int maxlcn; 2549 union imp_addr imp_addr; 2550 2551 #ifdef DDADEBUG 2552 if (DDADBCH(21, ds->dda_if.if_unit)) { 2553 prt_bytes(ds->dda_if.if_unit, "supr_msg", p, (int) (4 + p[3])); 2554 } 2555 #endif DDADEBUG 2556 2557 maxlcn = nddach[ds->dda_if.if_unit]; /* obtain SVC limit */ 2558 switch (p[0]) { 2559 case LINE_STATUS: /* link status msg */ 2560 if (p[2] == LINK_UP) { /* if link came up */ 2561 #ifdef DDADEBUG 2562 if (DDADBCH(21, ds->dda_if.if_unit)) { 2563 DDALOG(LOG_DEBUG) "dda%d: supr_msg: HDLC link up\n", 2564 ds->dda_if.if_unit DDAELOG; 2565 } 2566 #endif DDADEBUG 2567 send_restart(ds); /* send restart msg */ 2568 ds->dda_state = S_COMING_UP; 2569 } else { /* if link went down */ 2570 ds->dda_if.if_flags &= ~IFF_UP; /* ? should call if_down() ? */ 2571 hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_DISABLED); 2572 ds->dda_state = S_DISABLED; 2573 dc = ds->dda_cb; 2574 /* LCNLINK */ 2575 for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */ 2576 dc->dc_inaddr.s_addr = 0; /* forget dest address */ 2577 dc->dc_key.key_addr.s_addr = 0; 2578 dc->dc_wsizein = dc->dc_wsizeout = 0; 2579 dc->dc_pktsizein = dc->dc_pktsizeout = 0; 2580 dc->dc_state = LC_DOWN; /* set state */ 2581 dc->dc_timer = TMO_OFF; /* stop timer */ 2582 dc++; 2583 } 2584 hist_all_lcns(ds->dda_if.if_unit, LC_DOWN); 2585 abort_io(ds->dda_if.if_unit, ALL_CHANS); 2586 #ifdef DDA_PADOPT 2587 x29_init(ds->dda_if.if_unit, 1); 2588 #endif 2589 if (p[2] == LINK_DISABLED) /* link disabled */ 2590 DMESG(ds->dda_if.if_unit, 29, 2591 (DDALOG(LOG_ERR) "dda%d: link disabled\n", 2592 ds->dda_if.if_unit DDAELOG)); 2593 else 2594 DMESG(ds->dda_if.if_unit, 30, 2595 (DDALOG(LOG_ERR) "dda%d: link down\n", ds->dda_if.if_unit DDAELOG)); 2596 } 2597 break; 2598 2599 case RESTART: /* restart received */ 2600 if (ds->dda_cb[0].dc_state != LC_RESTART) { /* if not restarting */ 2601 2602 #ifdef DDADEBUG 2603 if (DDADBCH(21, ds->dda_if.if_unit)) { 2604 DDALOG(LOG_DEBUG) 2605 "dda%d: supr_msg: RESTART rcvd, no RESTART pending\n", 2606 ds->dda_if.if_unit DDAELOG; 2607 } 2608 #endif DDADEBUG 2609 send_supr(ds, RSTRT_ACK, 0, 0); /* send restart ack */ 2610 } 2611 /* fall thru */ 2612 case RSTRT_ACK: /* restart ack */ 2613 if ((ds->dda_state == S_COMING_UP) || (ds->dda_state == S_LINK_UP)) { 2614 if (p[0] == RSTRT_ACK) { 2615 DMESG(ds->dda_if.if_unit, 31, 2616 (DDALOG(LOG_ERR) "dda%d: Restart Ack received\n", 2617 ds->dda_if.if_unit DDAELOG)); 2618 } else { /* restart. print cause and diagnostic. */ 2619 DMESG(ds->dda_if.if_unit, 31, 2620 (DDALOG(LOG_ERR) "dda%d: Restart (%x %x) received\n", 2621 ds->dda_if.if_unit, p[2], p[3] ? p[4] : 0 DDAELOG)); 2622 } 2623 2624 ds->dda_if.if_flags |= IFF_UP; 2625 hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_LINK_UP); 2626 ds->dda_state = S_LINK_UP; 2627 dc = ds->dda_cb; 2628 /* LCNLINK */ 2629 for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */ 2630 dc->dc_state = LC_IDLE; /* set state */ 2631 dc->dc_timer = TMO_OFF; /* stop timer */ 2632 dc->dc_inaddr.s_addr = 0; /* forget address */ 2633 dc->dc_key.key_addr.s_addr = 0; 2634 dc->dc_wsizein = dc->dc_wsizeout = 0; 2635 dc->dc_pktsizein = dc->dc_pktsizeout = 0; 2636 dc++; 2637 } 2638 hist_all_lcns(ds->dda_if.if_unit, LC_IDLE); 2639 abort_io(ds->dda_if.if_unit, ALL_CHANS); 2640 DMESG(ds->dda_if.if_unit, 32, 2641 (DDALOG(LOG_ERR) "dda%d: (%s rev %d.%d) link up\n", 2642 ds->dda_if.if_unit, dda_product, 2643 (ds->dda_firmrev >> 4) & 0xF, ds->dda_firmrev & 0xF DDAELOG)); 2644 #ifdef DDA_PAD_OR_RAW 2645 x29_init(ds->dda_if.if_unit, 1); 2646 2647 /* 2648 * wake up all processes that tried to open a x29 device but 2649 * slept because the board was not up 2650 */ 2651 wakeup(&ds->dda_state); 2652 #endif DDA_PAD_OR_RAW 2653 } else 2654 #ifdef DDADEBUG 2655 if (DDADBCH(21, ds->dda_if.if_unit)) { 2656 DDALOG(LOG_ERR) "dda%d: Unexpected RESTART in state %x\n", 2657 ds->dda_if.if_unit, ds->dda_state DDAELOG; 2658 } 2659 #endif DDADEBUG 2660 break; 2661 2662 case ANSWER: /* call answered */ 2663 lcn = p[1] / 2; 2664 dc = &(ds->dda_cb[lcn]); 2665 if (dc->dc_state == LC_CALL_PENDING) { /* if a call pending */ 2666 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE); 2667 decode_answer(p, dc); 2668 dc->dc_state = LC_DATA_IDLE; /* set state */ 2669 dc->dc_timer = tmo_data_idle; /* start timer */ 2670 dda_start(ds, dc); /* try to send data */ 2671 } 2672 if (LOG_CALLS) { 2673 DDALOG(LOG_ERR) "dda%d: lcn %d connected\n", 2674 ds->dda_if.if_unit, lcn DDAELOG; 2675 } 2676 break; 2677 2678 case RING: /* incoming call */ 2679 /* if ring looks ok, and we find a free LCN to assign */ 2680 if (decode_ring(p) && (dc = find_free_lcn(ds))) { 2681 dc->dc_key.key_addr.s_addr = 2682 convert_x25_addr(ddacb_calling_addr, ds, dc); 2683 #ifdef DDADEBUG 2684 if (DDADBCH(21, ds->dda_if.if_unit)) { 2685 imp_addr.ip = dc->dc_inaddr; 2686 DDALOG(LOG_DEBUG) 2687 "dda%d: supr_msg: got call from %d.%d.%d.%d\n", 2688 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 2689 imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG; 2690 } 2691 #endif DDADEBUG 2692 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE); 2693 dc->dc_state = LC_DATA_IDLE; /* set state */ 2694 dc->dc_timer = tmo_data_idle; /* start timer */ 2695 dc->dc_pktsizein = 0; 2696 dc->dc_pktsizeout = 0; 2697 dc->dc_wsizein = 0; 2698 dc->dc_wsizeout = 0; 2699 send_supr(ds, ANSWER, (int) dc->dc_lcn * 2, 2700 (int) p[2]); /* send answer */ 2701 if (LOG_CALLS) { 2702 imp_addr.ip = dc->dc_inaddr; 2703 DDALOG(LOG_ERR) 2704 "dda%d: Accepting call from %d.%d.%d.%d (%s) on lcn %d\n", 2705 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 2706 imp_addr.imp.s_lh, imp_addr.imp.s_impno, 2707 fmt_x25(&ddacb_calling_addr[1], 2708 (int) ddacb_calling_addr[0]), dc->dc_lcn DDAELOG; 2709 } 2710 } else { /* if no free LCN's */ 2711 send_supr(ds, CLEARVC, p[2], 0); /* clear call */ 2712 if (LOG_CALLS) { 2713 DDALOG(LOG_ERR) "dda%d: Rejecting call from %s on VC 0x%x\n", 2714 ds->dda_if.if_unit, 2715 fmt_x25(&ddacb_calling_addr[1], ddacb_calling_addr[0]), 2716 p[1] DDAELOG; 2717 } 2718 } 2719 break; 2720 2721 case CLEARLC: /* clear by LCN */ 2722 2723 /* 2724 * This could mean one of three things: If we have a call request 2725 * outstanding, this message means the call has failed. If we have a 2726 * clear request outstanding, this message completes the cleanup; the 2727 * channel is now available for reuse. If we have a call active, this 2728 * message means the other side is closing the circuit. 2729 */ 2730 lcn = p[1] / 2; /* get LCN */ 2731 dc = &(ds->dda_cb[lcn]); 2732 if (dc->dc_state != LC_CLR_PENDING) { /* if no clear pending */ 2733 send_supr(ds, CLEARLC, p[1], 0); /* ack the clear */ 2734 } 2735 if (dc->dc_state == LC_CALL_PENDING /* if call is cleared */ 2736 && (LOG_CALLS || DMESGVAL(ds->dda_if.if_unit, 33) == 0)) { 2737 imp_addr.ip = dc->dc_inaddr; 2738 DDALOG(LOG_ERR) 2739 "dda%d: Call to %d.%d.%d.%d on lcn %d failed (%x %x)\n", 2740 ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host, 2741 imp_addr.imp.s_lh, imp_addr.imp.s_impno, dc->dc_lcn, p[2], p[4] 2742 DDAELOG; 2743 2744 } else if (LOG_CALLS) { 2745 if (dc->dc_state == LC_CLR_PENDING) { /* did we clear it? *//* y 2746 * es, IP address is 2747 * already gone. Say 2748 * channel is free. */ 2749 DDALOG(LOG_ERR) "dda%d: Cleared lcn %d\n", 2750 ds->dda_if.if_unit, dc->dc_lcn DDAELOG; 2751 } else { /* cleared by net, print more info */ 2752 imp_addr.ip = dc->dc_inaddr; 2753 DDALOG(LOG_ERR) 2754 "dda%d: Cleared lcn %d to %d.%d.%d.%d (%x %x)\n", 2755 ds->dda_if.if_unit, dc->dc_lcn, imp_addr.imp.s_net, 2756 imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno, 2757 p[2], p[4] DDAELOG; 2758 } 2759 } 2760 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_IDLE); 2761 /* LCNLINK delete */ 2762 dc->dc_state = LC_IDLE; /* set state */ 2763 dc->dc_timer = TMO_OFF; /* stop timer */ 2764 dc->dc_inaddr.s_addr = 0; /* forget address */ 2765 dc->dc_key.key_addr.s_addr = 0; 2766 dc->dc_wsizein = dc->dc_wsizeout = 0; 2767 dc->dc_pktsizein = dc->dc_pktsizeout = 0; 2768 abort_io(ds->dda_if.if_unit, lcn); 2769 if (LOG_CALLS) { 2770 printf("dda%d: Cleared LCN %d cause code %x diag code %x\n", 2771 ds->dda_if.if_unit, dc->dc_lcn, p[2], p[4]); 2772 } 2773 break; 2774 2775 case CLEARVC: /* clear by VCN */ 2776 2777 send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */ 2778 if (LOG_CALLS) { 2779 DDALOG(LOG_ERR) "dda%d: Network cleared VC %x (%x %x)\n", 2780 ds->dda_if.if_unit, p[1], p[2], p[4] DDAELOG; 2781 } 2782 #ifdef DDADEBUG 2783 else if (DDADBCH(21, ds->dda_if.if_unit)) { 2784 DDALOG(LOG_DEBUG) "dda%d: supr_msg: CLEARVC VCN=%x\n", 2785 ds->dda_if.if_unit, p[1] DDAELOG; 2786 } 2787 #endif DDADEBUG 2788 break; 2789 2790 case RESET: /* X25 reset */ 2791 lcn = p[1] / 2; /* get LCN */ 2792 dc = &(ds->dda_cb[lcn]); 2793 send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */ 2794 abort_io(ds->dda_if.if_unit, lcn); 2795 imp_addr.ip = dc->dc_inaddr; 2796 DMESG(ds->dda_if.if_unit, 34, 2797 (DDALOG(LOG_ERR) 2798 "dda%d: X25 RESET (%x %x) on lcn %d: %d.%d.%d.%d\n", 2799 ds->dda_if.if_unit, p[2], p[4], lcn, imp_addr.imp.s_net, 2800 imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno 2801 DDAELOG)); 2802 break; 2803 2804 case INTERRUPT: /* X25 interrupt */ 2805 lcn = p[1] / 2; /* get LCN */ 2806 dc = &(ds->dda_cb[lcn]); 2807 imp_addr.ip = dc->dc_inaddr; 2808 DMESG(ds->dda_if.if_unit, 35, 2809 (DDALOG(LOG_ERR) 2810 "dda%d: X25 INTERRUPT (%x) on lcn %d: %d.%d.%d.%d\n", 2811 ds->dda_if.if_unit, p[2], lcn, imp_addr.imp.s_net, 2812 imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno 2813 DDAELOG)); 2814 break; 2815 2816 case STATRESP: /* Statistics Response from FEP */ 2817 2818 /* 2819 * Copy the whole message into a static buffer, dda_iobuf. The buffer 2820 * is viewed as a (struct ddactl). Wake up the ioctl thread which 2821 * will copy the message out for acpconfig. 2822 */ 2823 { 2824 struct ddactl *da = (struct ddactl *) dda_iobuf; 2825 2826 bcopy(p, da->msg, max(4 + p[3], sizeof(da->msg))); 2827 #ifdef MULTINET 2828 StatQuery_Completed = 1; 2829 #else 2830 wakeup(dda_iobuf); 2831 #endif 2832 break; 2833 } 2834 2835 default: 2836 DMESG(ds->dda_if.if_unit, 36, 2837 (DDALOG(LOG_ERR) "dda%d: supervisor error (%x %x %x %x)\n", 2838 ds->dda_if.if_unit, p[0], p[1], p[2], p[3] DDAELOG)); 2839 } 2840 } 2841 2842 2843 2844 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2845 /*%% DECODE_ANSWER() %%*/ 2846 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2847 /* */ 2848 /* Purpose: */ 2849 /* This routine looks at the answer message from the FE */ 2850 /* and decodes it to find the negtiated packet and window sizes */ 2851 /* if they are present. */ 2852 /* */ 2853 /* Call: decode_answer(p, dc) */ 2854 /* Argument: p: pointer to mbuf data for ANSWER message */ 2855 /* dc: pointer to relavant lcn structure */ 2856 /* Returns: nothing */ 2857 /* Called by: supr_msg() */ 2858 /* Calls to: */ 2859 /* DDALOG() */ 2860 /* */ 2861 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2862 2863 PRIVATE void 2864 decode_answer(p, dc) 2865 u_char *p; 2866 struct dda_cb *dc; 2867 { 2868 register u_char *cp; 2869 int i, faclen; 2870 2871 dc->dc_pktsizein = 0; 2872 dc->dc_pktsizeout = 0; 2873 dc->dc_wsizein = 0; 2874 dc->dc_wsizeout = 0; 2875 cp = p + 4; /* skip over code, lcn, vcn and count in 2876 * answer message */ 2877 /* cp now points to length of called address */ 2878 cp += *cp + 1; /* skip over called address and length byte */ 2879 /* cp now points to length of calling address */ 2880 cp += *cp + 1; /* skip over calling address and length byte */ 2881 /* cp now points to length of protocol */ 2882 cp += *cp + 1; /* skip over protocol and protocol length 2883 * byte */ 2884 /* cp now points to the facilities length */ 2885 2886 faclen = *cp++; 2887 /* cp now points to start of facilities */ 2888 for (i = 0; i < faclen;) { 2889 switch (*cp & 0xc0) { 2890 case 0x00: /* single octet parameter field */ 2891 i += 2; 2892 cp += 2; 2893 break; 2894 case 0x40: /* double octet parameter field */ 2895 switch (*cp) { 2896 case X25_FACIL_PKTSIZE: /* 0x42, packet size */ 2897 dc->dc_pktsizein = *(cp + 1); 2898 dc->dc_pktsizeout = *(cp + 2); 2899 break; 2900 case X25_FACIL_WINSIZE: /* 0x43, window size */ 2901 dc->dc_wsizein = *(cp + 1); 2902 dc->dc_wsizeout = *(cp + 2); 2903 break; 2904 } 2905 i += 3; 2906 cp += 3; 2907 break; 2908 case 0x80: /* triple octet parameter field */ 2909 i += 4; 2910 cp += 4; 2911 break; 2912 case 0xc0: /* variable-length parameter field */ 2913 cp++; 2914 i += 2 + *cp; 2915 cp += 1 + *cp; 2916 break; 2917 /* Note: No other cases (i.e., default) possible */ 2918 } 2919 } 2920 } 2921 2922 2923 2924 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2925 /*%% DECODE_RING() %%*/ 2926 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2927 /* */ 2928 /* Purpose: */ 2929 /* */ 2930 /* This routine parses and validates the incoming call message. */ 2931 /* */ 2932 /* Call: decode_ring(p) */ 2933 /* Argument: p: pointer to the message */ 2934 /* Returns: 1 for success, else 0 for failure */ 2935 /* Called by: supr_msg() */ 2936 /* Calls to: bcopy() */ 2937 /* */ 2938 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 2939 2940 PRIVATE boolean 2941 decode_ring(p) 2942 register u_char *p; 2943 { 2944 register int cnt; 2945 2946 #ifdef DDADEBUG 2947 if (DDADBCH(22, 0)) { /* no easy access to unit, assume unit 0 */ 2948 DDALOG(LOG_DEBUG) "dda: decode_ring()\n" DDAELOG; 2949 } 2950 #endif DDADEBUG 2951 2952 p += 3; /* skip to cmnd ext length */ 2953 if (*p++ < 5) /* is count appropriate */ 2954 return (0); /* return false if not */ 2955 2956 /* called address */ 2957 if ((cnt = *p + 1) > 16) /* is called addr len legal? */ 2958 return (0); /* return false if not */ 2959 bcopy(p, ddacb_called_addr, cnt); /* copy field */ 2960 p += cnt; 2961 2962 /* calling address */ 2963 if ((cnt = *p + 1) > 16) /* is calling addr len legal? */ 2964 return (0); /* return false if not */ 2965 bcopy(p, ddacb_calling_addr, cnt); /* copy field */ 2966 p += cnt; 2967 2968 /* protocol part of user data */ 2969 if ((cnt = *p + 1) > 5) /* is protocol len legal? */ 2970 return (0); /* return false if not */ 2971 bcopy(p, ddacb_protocol, cnt); /* copy field */ 2972 p += cnt; 2973 2974 /* facilities */ 2975 if ((cnt = *p + 1) > 64) /* is facilities len legal? */ 2976 return (0); /* return false if not */ 2977 bcopy(p, ddacb_facilities, cnt); /* copy field */ 2978 p += cnt; 2979 2980 /* ignore rest of user data for now */ 2981 2982 #ifdef DDA_PAD_OR_RAW 2983 if (ddacb_protocol[0] == 0) 2984 return (0); 2985 #else DDA_PAD_OR_RAW 2986 if ((ddacb_protocol[0] == 0) || (ddacb_protocol[1] != X25_PROTO_IP)) 2987 return (0); /* bad if not IP */ 2988 #endif DDA_PAD_OR_RAW 2989 2990 #ifndef DDA_PAD_OR_RAW 2991 return (1); /* looks ok */ 2992 #else 2993 # ifdef DDA_RAWOPT 2994 return (1); /* anything is ok if we're PI interface */ 2995 # else 2996 if (ddacb_protocol[1] == X25_PROTO_IP || ddacb_protocol[1] == X25_PROTO_X29) 2997 return (1); /* looks ok */ 2998 else 2999 return (0); /* bad if not IP or X29 */ 3000 # endif 3001 #endif DDA_PAD_OR_RAW 3002 } 3003 3004 3005 3006 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3007 /*%% CLEAR_LCN() %%*/ 3008 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3009 /* */ 3010 /* Purpose: */ 3011 /* */ 3012 /* This routine clears an X25 circuit and releases any buffers */ 3013 /* queued for transmission. */ 3014 /* */ 3015 /* Call: clear_lcn(ds, dc) */ 3016 /* Argument: ds: pointer to dev control block struct */ 3017 /* dc: pointer to the Logical Channel control */ 3018 /* block structure */ 3019 /* Returns: nothing */ 3020 /* Called by: ddatimer() */ 3021 /* Calls to: IF_DEQUEUE() */ 3022 /* m_freem() */ 3023 /* send_supr() */ 3024 /* */ 3025 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3026 3027 PRIVATE void 3028 clear_lcn(ds, dc) 3029 struct dda_softc *ds; 3030 struct dda_cb *dc; 3031 { 3032 register struct mbuf *m; 3033 register int s; 3034 3035 #ifdef DDADEBUG 3036 if (DDADBCH(23, ds->dda_if.if_unit)) { 3037 DDALOG(LOG_DEBUG) "dda%d: clear_lcn(%d)\n", ds->dda_if.if_unit, 3038 dc->dc_lcn DDAELOG; 3039 } 3040 #endif DDADEBUG 3041 3042 if (dc->dc_state == LC_CLR_PENDING) { /* Unfortunately, we can't 3043 * display the destination's 3044 * IP address, as we cleared 3045 * it when we entered 3046 * clear-pending state (to 3047 * prevent new data from 3048 * being queued to this 3049 * channel). */ 3050 DMESG(ds->dda_if.if_unit, 37, 3051 (DDALOG(LOG_ERR) "dda%d: Clear request lost -- lcn %d\n", 3052 ds->dda_if.if_unit, dc->dc_lcn DDAELOG)); 3053 return; 3054 } 3055 hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_CLR_PENDING); 3056 dc->dc_state = LC_CLR_PENDING; /* set state */ 3057 dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */ 3058 dc->dc_inaddr.s_addr = 0; /* clear associated address */ 3059 dc->dc_key.key_addr.s_addr = 0; 3060 dc->dc_wsizein = dc->dc_wsizeout = 0; 3061 dc->dc_pktsizein = dc->dc_pktsizeout = 0; 3062 /* 3063 * Raise priority whenever dc_oq is touched. 3064 */ 3065 s = splimp(); 3066 while (dc->dc_oq.ifq_len) { /* drop any pending data */ 3067 IF_DEQUEUE(&dc->dc_oq, m); 3068 m_freem(m); 3069 } 3070 splx(s); 3071 send_supr(ds, CLEARLC, (int) dc->dc_lcn * 2, 0); /* send clear msg */ 3072 } 3073 3074 3075 3076 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3077 /*%% SEND_RESTART() %%*/ 3078 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3079 /* */ 3080 /* Purpose: */ 3081 /* */ 3082 /* This routine marks all LCNs as being in a restarting state */ 3083 /* and sends a restart command to X25. */ 3084 /* */ 3085 /* Call: send_restart(ds) */ 3086 /* Argument: ds: pointer to dev control block struct */ 3087 /* Returns: nothing */ 3088 /* Called by: ddatimer() */ 3089 /* supr_msg() */ 3090 /* Calls to: IF_DEQUEUE() */ 3091 /* m_freem() */ 3092 /* send_supr() */ 3093 /* */ 3094 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3095 3096 PRIVATE void 3097 send_restart(ds) 3098 struct dda_softc *ds; 3099 { 3100 register struct dda_cb *dc; 3101 register int lcn; 3102 register int maxlcn; 3103 3104 #ifdef DDADEBUG 3105 if (DDADBCH(24, ds->dda_if.if_unit)) { 3106 DDALOG(LOG_DEBUG) "dda%d: send_restart()\n", ds->dda_if.if_unit DDAELOG; 3107 } 3108 #endif DDADEBUG 3109 3110 dc = ds->dda_cb; 3111 /* LCNLINK */ 3112 maxlcn = nddach[ds->dda_if.if_unit]; 3113 for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */ 3114 dc->dc_state = LC_RESTART; /* set state */ 3115 dc->dc_timer = TMO_RESTART; /* start restart timeout */ 3116 dc->dc_inaddr.s_addr = 0; /* forget address */ 3117 dc->dc_key.key_addr.s_addr = 0; 3118 dc->dc_wsizein = dc->dc_wsizeout = 0; 3119 dc->dc_pktsizein = dc->dc_pktsizeout = 0; 3120 dc++; 3121 } 3122 hist_all_lcns(ds->dda_if.if_unit, LC_RESTART); 3123 abort_io(ds->dda_if.if_unit, ALL_CHANS); 3124 send_supr(ds, RESTART, 0, 0); /* send restart msg */ 3125 } 3126 3127 3128 3129 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3130 /*%% SEND_SUPR() %%*/ 3131 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3132 /* */ 3133 /* Purpose: */ 3134 /* */ 3135 /* This routine is used to send short (4 bytes only) supervisor */ 3136 /* commands, except that longer ANSWER messages may be sent. */ 3137 /* */ 3138 /* Call: send_supr(ds, cmd, p1, p2) */ 3139 /* Argument: ds: pointer to dev control block struct */ 3140 /* cmd: type of command */ 3141 /* p1: 2nd byte of supervisor message */ 3142 /* p2: 3rd byte of supervisor message */ 3143 /* Returns: nothing */ 3144 /* Called by: supr_msg() */ 3145 /* clear_lcn() */ 3146 /* send_restart() */ 3147 /* Calls to: MGET() */ 3148 /* DDALOG() */ 3149 /* mtod() */ 3150 /* IF_ENQUEUE() */ 3151 /* dda_start() */ 3152 /* */ 3153 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3154 3155 PRIVATE void 3156 send_supr(ds, cmd, p1, p2) 3157 struct dda_softc *ds; 3158 int cmd, p1, p2; 3159 { 3160 struct mbuf *m; 3161 register u_char *cp; 3162 u_char *savcp, *fp, *svcp; 3163 int i, faclen; 3164 3165 MGET(m, M_DONTWAIT, MT_DATA); 3166 3167 if (m == 0) { 3168 DMESG(ds->dda_if.if_unit, 23, 3169 (DDALOG(LOG_ERR) "dda%d: failed to get supr msg bfr!\n", 3170 ds->dda_if.if_unit DDAELOG)); 3171 return; 3172 } 3173 cp = savcp = mtod(m, u_char *); 3174 3175 /* build supervisor message */ 3176 3177 *cp++ = (u_char) cmd; 3178 *cp++ = (u_char) p1; 3179 *cp++ = (u_char) p2; 3180 *cp++ = 0; 3181 3182 m->m_len = 4; 3183 3184 if (cmd == ANSWER) { 3185 register struct dda_cb *dc; 3186 3187 /* for answer messages p1 is (lcn * 2) */ 3188 dc = &(ds->dda_cb[p1 / 2]); 3189 *cp++ = 0; /* zero length called address */ 3190 *cp++ = 0; /* zero length calling address */ 3191 *cp++ = 0; /* zero length protocol */ 3192 3193 /* check and copy facilities */ 3194 faclen = 0; 3195 svcp = cp++; 3196 for (i = 0, fp = &ddacb_facilities[1]; i < ddacb_facilities[0];) { 3197 switch (*fp & 0xc0) { 3198 case 0x00: /* single octet parameter field */ 3199 i += 2; 3200 fp += 2; 3201 break; 3202 case 0x40: /* double octet parameter field */ 3203 3204 /* 3205 * Note that this code can in some cases attempt to negotiate 3206 * the packet size or window away from the default, which 3207 * appears to violate the X.25 spec. In fact, the FEP 3208 * examines these values and bounds them between the 3209 * requested value and the default value thus satisfying X.25 3210 */ 3211 switch (*fp) { 3212 case X25_FACIL_PKTSIZE: /* 0x42, packet size */ 3213 *cp++ = X25_FACIL_PKTSIZE; 3214 if (ds->dda_firmrev < 0x21) { 3215 *cp++ = PKTSIZE_DEF; /* Set incoming and outgoing */ 3216 *cp++ = PKTSIZE_DEF; /* packet size to default */ 3217 dc->dc_pktsizein = dc->dc_pktsizeout = PKTSIZE_DEF; 3218 } else { 3219 *cp++ = *(fp + 1); /* Answer with requested */ 3220 *cp++ = *(fp + 2); /* facilities */ 3221 dc->dc_pktsizeout = *(fp + 1); 3222 dc->dc_pktsizein = *(fp + 2); 3223 } 3224 faclen += 3; 3225 break; 3226 case X25_FACIL_WINSIZE: /* 0x43, window size */ 3227 *cp++ = X25_FACIL_WINSIZE; 3228 if (ds->dda_firmrev < 0x21) { 3229 *cp++ = WINSIZE_DEF; /* Set incoming and outgoing */ 3230 *cp++ = WINSIZE_DEF; /* window size to default */ 3231 dc->dc_wsizein = dc->dc_wsizeout = WINSIZE_DEF; 3232 } else { 3233 *cp++ = *(fp + 1); /* Answer with requested */ 3234 *cp++ = *(fp + 2); /* facilities */ 3235 dc->dc_wsizeout = *(fp + 1); 3236 dc->dc_wsizein = *(fp + 2); 3237 } 3238 faclen += 3; 3239 break; 3240 } 3241 i += 3; 3242 fp += 3; 3243 break; 3244 case 0x80: /* triple octet parameter field */ 3245 i += 4; 3246 fp += 4; 3247 break; 3248 case 0xc0: /* variable-length parameter field */ 3249 fp++; 3250 i += 2 + *fp; 3251 fp += 1 + *fp; 3252 break; 3253 /* Note: No other cases (i.e., default) possible */ 3254 } 3255 } 3256 3257 if (faclen) { /* Found facilities to negotiate! */ 3258 *svcp = faclen; /* facility length <- faclen */ 3259 *cp++ = 0; /* user data length <- 0 */ 3260 *(savcp + 3) = cp - savcp - 4; /* set supv message length */ 3261 m->m_len = cp - savcp; /* set mbuf message length */ 3262 } 3263 } /* (end of answer message case) */ 3264 # ifdef DDADEBUG 3265 if (DDADBCH(25, ds->dda_if.if_unit)) { 3266 prt_bytes(ds->dda_if.if_unit, "send_supr", savcp, m->m_len); 3267 } 3268 #endif DDADEBUG 3269 start_supr(ds, m); 3270 } 3271 3272 3273 3274 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3275 /*%% START_SUPR() %%*/ 3276 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3277 /* */ 3278 /* Purpose: */ 3279 /* */ 3280 /* Start i/o on the supervisor channel, checking for queue full. */ 3281 /* Added to revision 2.0 so that "queue full" checking would be */ 3282 /* applied uniformly to all supervisory channel output. */ 3283 /* */ 3284 /* Call: start_supr(ds, m) */ 3285 /* Argument: ds: softc structure for board */ 3286 /* m: mbuf holding message */ 3287 /* Returns: nothing */ 3288 /* Called by: send_supr(), send_config(), make_x25_call() */ 3289 /* Calls to: DDALOG(), dda_start(), IF_ENQUEUE() */ 3290 /* */ 3291 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3292 3293 PRIVATE void 3294 start_supr(ds, m) 3295 struct dda_softc *ds; 3296 struct mbuf *m; 3297 { 3298 register int s; 3299 3300 3301 #ifdef DDADEBUG 3302 if (DDADBCH(27, ds->dda_if.if_unit)) 3303 DDALOG(LOG_DEBUG) "dda%d: start_supr\n", ds->dda_if.if_unit DDAELOG; 3304 #endif DDADEBUG 3305 3306 if (IF_QFULL(&(ds->dda_cb[0].dc_oq))) { 3307 DMESG(ds->dda_if.if_unit, 27, 3308 (DDALOG(LOG_ERR) "dda%d: supervisory channel overflow (maxlen=%d)\n", 3309 ds->dda_if.if_unit, ds->dda_cb[0].dc_oq.ifq_maxlen DDAELOG)); 3310 ds->dda_cb[0].dc_oq.ifq_maxlen += ds->dda_cb[0].dc_oq.ifq_maxlen; 3311 } 3312 /* 3313 * Raise priority whenever you touch dc_oq. 3314 * We do not want to be interrupted in the middle of adding 3315 * an mbuf to the output queue because the interrupt may indicate 3316 * a condition that will cause the mbuf to be freed. 3317 * (The mbufs are freed on receipt of a line status msg, restart, 3318 * clear, or reset.) 3319 */ 3320 s = splimp(); 3321 #ifdef DDA_PAD_OR_RAW 3322 m->m_dat[MLEN - 1] = 0; 3323 #endif 3324 IF_ENQUEUE(&(ds->dda_cb[0].dc_oq), m); 3325 splx(s); 3326 dda_start(ds, &(ds->dda_cb[0])); 3327 } 3328 3329 3330 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3331 /*%% ABORT_IO() %%*/ 3332 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3333 /* */ 3334 /* Purpose: */ 3335 /* */ 3336 /* Abort outstanding I/O upon receipt of a line status message, */ 3337 /* restart, clear, or reset. */ 3338 /* The contents of the output queue (dc_oq) is cleared for each */ 3339 /* lcn; all I/O queued on either the read or write queue */ 3340 /* (dc_rchan and dc_wchan) is marked invalid; all I/O queued on */ 3341 /* the sioq is marked invalid; */ 3342 /* */ 3343 /* Call: abort_io() */ 3344 /* Argument: none */ 3345 /* Returns: nothing */ 3346 /* Called by: */ 3347 /* Calls to: IF_DEQUEUE() */ 3348 /* */ 3349 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3350 PRIVATE void 3351 abort_io(unit, lcn) 3352 int unit, lcn; 3353 { 3354 register struct dda_cb *dc; 3355 register struct dda_softc *ds = &dda_softc[unit]; 3356 register struct hdx_chan *hc; 3357 register struct mbuf *m; 3358 register int lchan; 3359 register int s; 3360 register struct hdx_chan *ptr; 3361 int start, end; 3362 3363 /* set up range of lcns affected */ 3364 if (lcn == ALL_CHANS) { 3365 start = 1; 3366 end = nddach[unit]; 3367 } else 3368 start = end = lcn; 3369 #ifdef DDADEBUG 3370 if (DDADBCH(28, unit)) 3371 DDALOG(LOG_DEBUG) "dda%d: abort_io on lcn's %d - %d\n", 3372 unit, start, end DDAELOG; 3373 #endif DDADEBUG 3374 s = splimp(); 3375 /* 3376 * Invalidate writes on the sioq for specified channel(s) 3377 */ 3378 if (ptr = ds->dda_sioq.sq_head) 3379 for (; ptr; ptr = ptr->hc_next) /* scan sioq */ 3380 if ((ptr->hc_chan & 0x01) && 3381 ((lcn == ALL_CHANS) || (lcn == ptr->hc_chan >> 1)) 3382 && (ptr->hc_chan != 1)) { 3383 #ifdef DDADEBUG 3384 if (DDADBCH(28, unit)) 3385 DDALOG(LOG_DEBUG) 3386 "dda%d: abort_io--invalidating sioq lcn %d\n", 3387 unit, ptr->hc_chan >> 1 DDAELOG; 3388 #endif DDADEBUG 3389 ptr->hc_inv |= INVALID_MBUF; 3390 } 3391 /* 3392 * For each selected lcn, clear the output queue and 3393 * add an hdx struct to the sioq that will generate an 3394 * abort. 3395 */ 3396 for (lchan = start; lchan <= end; lchan++) { /* for selected LCNs */ 3397 dc = &dda_softc[unit].dda_cb[lchan]; 3398 hc = &dc->dc_wchan; 3399 while (dc->dc_oq.ifq_len) { 3400 IF_DEQUEUE(&dc->dc_oq, m); 3401 m_freem(m); 3402 } 3403 3404 if (hc->hc_mbuf && !(hc->hc_inv & INVALID_MBUF)) { 3405 if (dc->dc_flags & DC_OBUSY) { /* output pending */ 3406 #ifdef DDADEBUG 3407 if (DDADBCH(28, unit)) 3408 DDALOG(LOG_DEBUG) 3409 "dda%d: abort_io--queueing abort: lcn %d\n", 3410 unit, lchan DDAELOG; 3411 #endif DDADEBUG 3412 3413 hc->hc_inv |= INVALID_MBUF; 3414 hc->hc_func = DDAABT; 3415 /* 3416 * Add to the sioq 3417 */ 3418 dda_wrq(ds, hc, DDAABT); 3419 } 3420 } 3421 } 3422 splx(s); 3423 } 3424 3425 #ifdef DDADEBUG 3426 3427 3428 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3429 /*%% PRT_BYTES() %%*/ 3430 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3431 /* */ 3432 /* Purpose: */ 3433 /* */ 3434 /* This routine is used to print a label, followed by the contents of */ 3435 /* a buffer in hex, 16 bytes per line. Each line is preceded by */ 3436 /* the device name and unit number. */ 3437 /* */ 3438 /* Call: prt_bytes(unit, label, bp, cnt) */ 3439 /* Argument: unit: dda unit number to be displayed */ 3440 /* label: pointer to string to be displayed */ 3441 /* bp: pointer to the buffer to be dumped */ 3442 /* cnt: number of bytes in buffer */ 3443 /* Returns: nothing */ 3444 /* Called by: dda_data() */ 3445 /* dda_supr() */ 3446 /* supr_msg() */ 3447 /* Calls to: DDALOG() */ 3448 /* */ 3449 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3450 PRIVATE void 3451 prt_bytes(unit, label, bp, cnt) 3452 int unit; 3453 char *label; 3454 u_char *bp; 3455 int cnt; 3456 { 3457 char hexbuf[50]; /* (worst case: 3 * 16 + 1 = 49 bytes) */ 3458 char *p; 3459 int i; 3460 static char hex[] = "0123456789abcdef"; 3461 3462 DDALOG(LOG_DEBUG) "dda%d: %s\n", unit, label DDAELOG; 3463 while (cnt > 0) { 3464 i = (cnt > 16) ? 16 : cnt; 3465 cnt -= i; 3466 p = hexbuf; 3467 while (--i >= 0) { 3468 *p++ = ' '; 3469 *p++ = hex[*bp >> 4]; 3470 *p++ = hex[*bp++ & 0x0f]; 3471 } 3472 *p++ = '\0'; 3473 DDALOG(LOG_DEBUG) "dda%d: %s\n", unit, hexbuf DDAELOG; 3474 } 3475 } 3476 3477 #endif 3478 3479 3480 3481 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3482 /*%% FMT_X25() %%*/ 3483 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3484 /* */ 3485 /* Purpose: */ 3486 /* */ 3487 /* This routine is used to format an X.25 address for inclusion in */ 3488 /* an error message. The previous return value is invalidated each */ 3489 /* time the function is called, as it is stored in a static buffer */ 3490 /* Note: The X.25 address is apparently sometimes stored in */ 3491 /* BCD, and other times (PDN mode) in ASCII. So we mask */ 3492 /* off the high order bits to make ourselves immune. */ 3493 /* Call: fmt_x25(bp, cnt) */ 3494 /* Argument: bp: pointer to the string */ 3495 /* cnt: number of bytes (usually from address[0]) */ 3496 /* Returns: pointer to an internal buffer containing the string; */ 3497 /* string is 1 to 15 digits, null-terminated. */ 3498 /* Called by: make_x25_call() */ 3499 /* supr_msg() */ 3500 /* convert_x25_addr() */ 3501 /* Calls to: none */ 3502 /* */ 3503 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3504 PRIVATE char * 3505 fmt_x25(bp, cnt) 3506 register u_char *bp; 3507 register int cnt; 3508 { 3509 char *p; 3510 static char x25buf[20]; /* worst case is 15 digits plus trailing null */ 3511 3512 /* (Don't put this on the stack!) */ 3513 p = x25buf; 3514 if (cnt >= sizeof(x25buf)) 3515 cnt = sizeof(x25buf) - 1; /* (oops!) */ 3516 while (cnt--) 3517 *p++ = (*bp++ & 0x0f) + '0'; 3518 *p++ = '\0'; 3519 return (x25buf); 3520 } 3521 3522 #ifdef DDA_HISTOGRAM 3523 /*----------------------- HISTOGRAM SUPPORT ---------------------------------*/ 3524 3525 3526 /* the histogram array */ 3527 struct timeval histogram[NDDA][HISTSIZE]; 3528 3529 /* these two structures save the time of the last change in the state of the 3530 * lcn table or the board status. 3531 */ 3532 3533 struct timeval last_lcn_time[NDDA] = {0L, 0L}; 3534 struct timeval last_brd_time[NDDA] = {0L, 0L}; 3535 3536 /* h_lcn_level: the current number of active lcns */ 3537 int h_lcn_level[NDDA] = {0}; 3538 3539 /*#define DDA_HIST_DEBUG 1 /* set this to debug history features */ 3540 3541 3542 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3543 /*%% HIST_INIT() %%*/ 3544 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3545 /* */ 3546 /* Purpose: */ 3547 /* */ 3548 /* This routine initializes the histogram facility when coming up or */ 3549 /* after a reset. */ 3550 /* Call: hist_init(unit,reset) */ 3551 /* Argument: unit - board number to initialize. */ 3552 /* reset - set to 1 to force an init. */ 3553 /* Returns: nothing. */ 3554 /* Called by: ddaioctl() */ 3555 /* Calls to: microtime() */ 3556 /* */ 3557 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3558 3559 PRIVATE void 3560 hist_init(unit, reset) 3561 int unit; 3562 int reset; 3563 { 3564 int s; 3565 register int i; 3566 struct dda_cb *dc; 3567 3568 if (last_lcn_time[unit].tv_sec != 0L && !reset) 3569 return; /* histogram for this unit already enabled */ 3570 bzero(histogram[unit], sizeof(struct timeval) * HISTSIZE); 3571 h_lcn_level[unit] = 0; 3572 dc = dda_softc[unit].dda_cb; 3573 s = splimp(); 3574 for (i = 0; i < NDDACH + 1; i++) { 3575 if (dc++->dc_state == LC_DATA_IDLE) 3576 h_lcn_level[unit]++; 3577 } 3578 splx(s); 3579 microtime(&histogram[unit][H_START]); 3580 #ifdef DDA_HIST_DEBUG 3581 DDALOG(LOG_DEBUG) "hist_init: starting at level %d\n", 3582 h_lcn_level[unit] DDAELOG; 3583 #endif 3584 } 3585 3586 3587 3588 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3589 /*%% HIST_LCN_STATE() %%*/ 3590 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3591 /* */ 3592 /* Purpose: */ 3593 /* */ 3594 /* This routine changes the histogram depending on how the state of */ 3595 /* a channel has changed. */ 3596 /* Call: hist_lcn_state(unit, old_state, new_state) */ 3597 /* Argument: old_state: the old state of the lcn. */ 3598 /* new_state: the state the lcn is changing to. */ 3599 /* unit: unit this applies to */ 3600 /* Returns: nothing. */ 3601 /* Called by: */ 3602 /* Calls to: timevalsub(), timevaladd(), microtime() */ 3603 /* */ 3604 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3605 3606 PRIVATE void 3607 hist_lcn_state(unit, old_state, new_state) 3608 int unit; 3609 u_char old_state; 3610 u_char new_state; 3611 { 3612 struct timeval tv, tmpv; 3613 3614 /* 3615 * this structure for determining state transitions is much more general 3616 * than is necessary right now. However it allows easy changes to the 3617 * state transition table for the histogram so I will leave it in until 3618 * it settles down 3619 */ 3620 switch (old_state) { 3621 case LC_DATA_IDLE: 3622 switch (new_state) { 3623 case LC_DATA_IDLE: 3624 break; 3625 default: /* all other states */ 3626 microtime(&tv); 3627 tmpv = tv; 3628 timevalsub(&tv, &last_lcn_time[unit]); 3629 #ifdef DDA_HIST_DEBUG 3630 DDALOG(LOG_DEBUG) "hist_lcn_state: adding %ld.%ld to level %d--\n", 3631 tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG; 3632 #endif 3633 timevaladd(&histogram[unit][h_lcn_level[unit]], &tv); 3634 last_lcn_time[unit] = tmpv; 3635 if (--h_lcn_level[unit] < 0) /* safety net for driver 3636 * errors */ 3637 h_lcn_level[unit] = 0; 3638 break; 3639 } 3640 break; 3641 default: 3642 switch (new_state) { 3643 case LC_DATA_IDLE: 3644 microtime(&tv); 3645 tmpv = tv; 3646 timevalsub(&tv, &last_lcn_time[unit]); 3647 #ifdef DDA_HIST_DEBUG 3648 DDALOG(LOG_DEBUG) "hist_lcn_state: adding %ld.%ld to level %d++\n", 3649 tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG; 3650 #endif 3651 timevaladd(&histogram[unit][h_lcn_level[unit]], &tv); 3652 last_lcn_time[unit] = tmpv; 3653 if (++h_lcn_level[unit] > NDDACH) /* safety net for driver 3654 * errors */ 3655 h_lcn_level[unit] = NDDACH; 3656 break; 3657 default: /* all other states */ 3658 break; 3659 } 3660 break; 3661 } 3662 } 3663 3664 3665 3666 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3667 /*%% HIST_ALL_LCNS() %%*/ 3668 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3669 /* */ 3670 /* Purpose: */ 3671 /* */ 3672 /* This routine changes the histogram when the state of all the lcns */ 3673 /* are changed as a group. */ 3674 /* Call: hist_lcn_state(unit, state) */ 3675 /* Argument: state: state that all lcn are going to. Currently not*/ 3676 /* used. */ 3677 /* unit: unit this applies to */ 3678 /* Returns: nothing. */ 3679 /* Called by: */ 3680 /* Calls to: timevalsub(), timevaladd(), microtime() */ 3681 /* */ 3682 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3683 3684 PRIVATE void 3685 hist_all_lcns(unit, state) 3686 int unit, state; 3687 { 3688 struct timeval tmpv, tv; 3689 3690 #ifdef lint 3691 state = state; 3692 #endif 3693 if (last_brd_time[unit].tv_sec == 0L 3694 || last_lcn_time[unit].tv_sec == 0L) 3695 return; /* see if we have initialized yet */ 3696 microtime(&tv); 3697 tmpv = tv; 3698 timevalsub(&tv, &last_lcn_time[unit]); 3699 #ifdef DDA_HIST_DEBUG 3700 DDALOG(LOG_DEBUG) "hist_all_lcns: adding %ld.%ld to level %d\n", 3701 tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG; 3702 #endif 3703 timevaladd(&histogram[unit][h_lcn_level[unit]], &tv); 3704 last_lcn_time[unit] = tmpv; 3705 h_lcn_level[unit] = 0; 3706 } 3707 3708 3709 3710 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3711 /*%% HIST_LINK_STATE() %%*/ 3712 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3713 /* */ 3714 /* Purpose: */ 3715 /* */ 3716 /* This routine changes the histogram depending on how the state of */ 3717 /* the link has changed. */ 3718 /* Call: hist_link_state(old_state, new_state) */ 3719 /* Argument: old_state: the old state of the link. */ 3720 /* new_state: the state the link is changing to. */ 3721 /* unit: unit this applies to */ 3722 /* Returns: nothing. */ 3723 /* Called by: */ 3724 /* Calls to: timevalsub(), timevaladd(), microtime() */ 3725 /* */ 3726 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3727 3728 PRIVATE void 3729 hist_link_state(unit, old_state, new_state) 3730 int unit; 3731 u_char old_state; 3732 u_char new_state; 3733 { 3734 struct timeval tv, tmpv; 3735 3736 /* 3737 * this structure for determining state transitions is much more general 3738 * than is necessary right now. However it allows easy changes to the 3739 * state transition table for the histogram so I will leave it in until 3740 * it settles down 3741 */ 3742 switch (old_state) { 3743 case S_LINK_UP: 3744 switch (new_state) { 3745 case S_LINK_UP: 3746 break; 3747 default: /* all other states */ 3748 #ifdef DDA_HIST_DEBUG 3749 DDALOG(LOG_DEBUG) "hist_link_state: link down\n" DDAELOG; 3750 #endif 3751 microtime(&tv); 3752 tmpv = tv; 3753 timevalsub(&tv, &last_lcn_time[unit]); 3754 timevaladd(&histogram[unit][h_lcn_level[unit]], &tv); 3755 tv = tmpv; 3756 timevalsub(&tv, &last_brd_time[unit]); 3757 timevaladd(&histogram[unit][H_LINK_UP], &tv); 3758 last_brd_time[unit].tv_sec = 0L; 3759 break; 3760 } 3761 break; 3762 default: /* all other states */ 3763 switch (new_state) { 3764 case S_LINK_UP: 3765 #ifdef DDA_HIST_DEBUG 3766 DDALOG(LOG_DEBUG) "hist_link_state: link up\n" DDAELOG; 3767 #endif 3768 microtime(&last_brd_time[unit]); 3769 3770 /* 3771 * reset last_lcn_time so 0 entry will not accumulate the time 3772 * that we were down 3773 */ 3774 last_lcn_time[unit] = last_brd_time[unit]; 3775 break; 3776 default: 3777 break; 3778 } 3779 break; 3780 } 3781 } 3782 3783 3784 3785 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3786 /*%% HIST_READ() %%*/ 3787 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3788 /* */ 3789 /* Purpose: */ 3790 /* */ 3791 /* This routine prepares the histogram table for reading by making */ 3792 /* all entries current. */ 3793 /* Call: hist_read(unit) */ 3794 /* Argument: unit : board to use. */ 3795 /* Returns: nothing */ 3796 /* Called by: ddaioctl() */ 3797 /* Calls to: timevalsub(), timevaladd(), microtime() */ 3798 /* */ 3799 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3800 3801 PRIVATE void 3802 hist_read(unit) 3803 int unit; 3804 { 3805 struct timeval tmpv, tv; 3806 3807 microtime(&tv); 3808 tmpv = tv; 3809 histogram[unit][H_END] = tmpv; 3810 histogram[unit][H_TMO].tv_sec = tmo_data_idle * DDA_TIMEOUT; 3811 histogram[unit][H_TMO].tv_usec = 0L; 3812 if (last_brd_time[unit].tv_sec) { 3813 timevalsub(&tv, &last_lcn_time[unit]); 3814 #ifdef DDA_HIST_DEBUG 3815 DDALOG(LOG_DEBUG) "hist_read: adding %ld.%ld to level %d\n", 3816 tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG; 3817 #endif 3818 timevaladd(&histogram[unit][h_lcn_level[unit]], &tv); 3819 last_lcn_time[unit] = tmpv; 3820 tv = tmpv; 3821 timevalsub(&tv, &last_brd_time[unit]); 3822 timevaladd(&histogram[unit][H_LINK_UP], &tv); 3823 last_brd_time[unit] = tmpv; 3824 } 3825 } 3826 3827 3828 3829 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3830 /*%% HIST_COPYOUT() %%*/ 3831 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3832 /* */ 3833 /* Purpose: */ 3834 /* */ 3835 /* This routine prepares the histogram table for reading by making */ 3836 /* all entries current. */ 3837 /* Call: hist_copyout(unit, to) */ 3838 /* Argument: unit : board to use. */ 3839 /* to : address in user space to copy to. */ 3840 /* Returns: return value from copyout */ 3841 /* Called by: ddaioctl() */ 3842 /* Calls to: copyout() */ 3843 /* */ 3844 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 3845 3846 PRIVATE int 3847 hist_copyout(unit, to) 3848 int unit; 3849 caddr_t to; 3850 { 3851 return ((copyout(histogram[unit], to, sizeof(struct timeval) * HISTSIZE))); 3852 } 3853 3854 #endif DDA_HISTOGRAM 3855 3856 #ifdef DDA_PAD_OR_RAW 3857 3858 #if ACC_BSD > 42 3859 # include "uba.h" 3860 # include "bk.h" 3861 # include "conf.h" 3862 # include "proc.h" 3863 # include "tty.h" 3864 # include "map.h" 3865 # include "vm.h" 3866 # include "bkmac.h" 3867 # include "clist.h" 3868 # include "file.h" 3869 # include "uio.h" 3870 #endif 3871 3872 #if ACC_BSD == 42 || ACC_ULTRIX > 00 3873 # include "bk.h" 3874 # include "../h/conf.h" 3875 # include "../h/proc.h" 3876 # include "../h/tty.h" 3877 # include "../h/map.h" 3878 # include "../h/vm.h" 3879 # if ACC_ULTRIX > 12 3880 # include "uba.h" 3881 # endif 3882 # include "../h/bk.h" 3883 # ifdef SIMULATION 3884 # include "Clist.h" 3885 # else 3886 # include "../h/clist.h" 3887 # endif 3888 # include "../h/file.h" 3889 # include "../h/uio.h" 3890 #endif 3891 3892 PRIVATE int 3893 dda_decode_type(ds, p) 3894 struct dda_softc *ds; 3895 u_char *p; 3896 { 3897 register u_char *cp; 3898 int i, usrlen; 3899 3900 #ifdef DDADEBUG 3901 if (DDADBCH(20, ds->dda_if.if_unit)) { 3902 printf(" dda_decode_type(): p[0]= %x ", *p); 3903 } 3904 #endif DDADEBUG 3905 3906 switch (p[0]) { 3907 case LINE_STATUS: /* link status msg */ 3908 case RESTART: /* restart received */ 3909 case RSTRT_ACK: /* restart ack */ 3910 case STATRESP: /* Statistics Response from FEP */ 3911 case CLEARVC: /* clear by VCN */ 3912 return (0); 3913 case RESET: /* X25 reset */ 3914 return (1); 3915 case ANSWER: 3916 case CLEARLC: 3917 case INTERRUPT: 3918 case INTR_ACK: 3919 i = p[1] / 2; /* get lcn */ 3920 if (ds->dda_cb[i].dc_flags & (DC_X29 | DC_X29W)) 3921 return (1); 3922 else if (ds->dda_cb[i].dc_flags & (DC_RAW)) 3923 return (2); 3924 else 3925 return (0); 3926 } 3927 if (p[0] != RING) { /* let standard dda handle it */ 3928 return (0); 3929 } 3930 cp = p + 4; /* skip over code, lcn, vcn and count in 3931 * (ring?) answer message */ 3932 /* cp now points to length of called address */ 3933 cp += *cp + 1; /* skip over called address and length byte */ 3934 /* cp now points to length of calling address */ 3935 cp += *cp + 1; /* skip over calling address and length byte */ 3936 /* cp now points to length of protocol */ 3937 if (*cp == 0) 3938 return (0); 3939 3940 usrlen = *cp++; 3941 if (usrlen) { 3942 #ifdef DDA_RAWOPT 3943 if (pi_circuit_to_handle_protocol(*cp)) 3944 return (2); 3945 #endif 3946 #ifdef DDADEBUG 3947 if (DDADBCH(20, ds->dda_if.if_unit)) { 3948 printf(" dda_decode_type(): return value = %x ", *cp); 3949 } 3950 #endif DDADEBUG 3951 switch (*cp) { 3952 case X25_PROTO_IP: 3953 return (0); 3954 case X25_PROTO_X29: 3955 return (1); 3956 default: 3957 return (2); 3958 } 3959 } else 3960 return (0); 3961 } 3962 #endif DDA_PAD_OR_RAW 3963 3964 #ifdef SIMULATION 3965 # ifdef DDA_PADOPT 3966 # include "if_x29.c" 3967 # endif 3968 # ifdef DDA_RAWOPT 3969 # include "if_pi.c" 3970 # endif 3971 #else 3972 # ifdef DDA_PADOPT 3973 # if ACC_VMS > 00 3974 # include "../vaxif/if_vmsx29.c" 3975 # else 3976 # include "../vaxif/if_x29.c" 3977 # endif 3978 # endif 3979 # ifdef DDA_RAWOPT 3980 # include "../vaxif/if_pi.c" 3981 # endif 3982 #endif 3983 3984 #ifdef DDA_MSGQ 3985 u_char ddamsgq[MSGQSIZE]; 3986 PRIVATE u_char *mqptr = 0; 3987 3988 #define MSGQEND (ddamsgq+MSGQSIZE) 3989 3990 dda_mqstr(s) 3991 char *s; 3992 { 3993 if (mqptr == 0) 3994 mqptr = ddamsgq; 3995 while (*s) { 3996 *mqptr++ = *s++; 3997 if (mqptr >= MSGQEND) 3998 mqptr = ddamsgq; 3999 } 4000 *mqptr = '\0'; 4001 } 4002 4003 dda_mqnum(num, type) 4004 int num, type; 4005 { 4006 if (mqptr == 0) 4007 mqptr = ddamsgq; 4008 if ((mqptr + sizeof(int) + 2) >= MSGQEND) 4009 mqptr = ddamsgq; 4010 *mqptr++ = type; 4011 *((int *) mqptr) = num; 4012 mqptr += sizeof(int); 4013 *mqptr = '\0'; 4014 } 4015 4016 #endif DDA_MSGQ 4017 4018 /* link in support for steve's test-jig */ 4019 #ifdef SIMULATION 4020 #include "if_dda_sim.c" 4021 #endif 4022 4023 /* 4024 Revision History: 4025 4026 18-Dec-87: V3.0 - Brad Engstrom 4027 Added the -t flag to acpconfig and the 't' case in ddaioctl to allow 4028 setting of the idle circuit timeout. 4029 The constant TMO_DATA_IDLE was changed to a variable called 4030 tmo_data_idle. 4031 11-Mar-88: V3.0 - Brad Engstrom 4032 Modified the history routine to return the current value of the 4033 timeout. Also fixed bug so that level 0 records amount of time 0 4034 circuits were in use only when link is up. 4035 11-Mar-88: V3.0 - Brad Engstrom 4036 Changed handling of supervisor channel overflows to double the max q 4037 length each time it overflows. This Will prevent a flood of console 4038 messages while still notifying the user that there has been an 4039 overflow. 4040 21-Mar-88: V3.0 - Brad Engstrom 4041 Fixed bug in writing the facilities field for packet and window size 4042 negotiation. This was in the routine make X.25 call. Previously 4043 constants were used to index into the facilities buffer now offsets 4044 from the current facilities length are used. 4045 12-Apr-88: V3.0 - Brad Engstrom 4046 Added ability to handle class b and class c addressing. The changes 4047 affect locate_x25_lcn, convert_x25_addr, and convert_ip_addr. The 4048 modifications came from fixes sent to Wollongong by Lars Poulson. 4049 12-Apr-88: V3.0 - Brad Engstrom 4050 Made modifications so the driver will work under Ultrix or BSD. In 4051 cases where there are differences between 4.3 and 4.2 bsd (shown by 4052 #ifdef BSD4_3) Ultrix 1.2 is exactly like a 4.2 system. Ultrix 2.0 is 4053 like 4.3 in most cases. New macros were added to distinquish between 4054 systems. These are BSD4_2 and BSD43_OR_ULTRIX20. 4055 13-Apr-88: V3.0 - Brad Engstrom 4056 ddareset() was called from ddaintb without arguments. This could 4057 cause ddareset to return without doing anything. Proper arguments were 4058 inserted. In ddaioctl the priority level s may be used without being 4059 set. This was fixed. 4060 18-Apr-88: V3.0 - Brad Engstrom 4061 Added the use of a key field in the dda_cb structure. Previously the 4062 dc_inaddr field was used both for printing the ip address (-l command) 4063 and for searching for circuits that were open to a destination. Using 4064 this for a cicuit matching address means that the network and local 4065 host fields needed to be masked off, thus making this field less 4066 usefull for printing. Now two fields are used dc_inaddr is used for 4067 printing. dc_key is used for circuit matching. In PDN mode the 4068 full ip address is used as the key. In DDN mode just the imp number 4069 and host(port) number are used. 4070 18-Apr-88: V3.0 - Brad Engstrom 4071 Made histogram facilities a compile time option. The histogram is 4072 enabled if DDA_HISTOGRAM is defined. The facilities are always 4073 disabled when using 4.2 or ULTRIX 1.2 as the kernel does not have the 4074 proper support routines available. 4075 22-Apr-88: V3.0 - Brad Engstrom 4076 Added new option to -v command to set the dda_db_unit variable. 4077 22-Apr-88: V3.0 - Brad Engstrom 4078 Added the DMESG macro and the msgbits array to allow selective 4079 disabling of driver error messages. To enable or disable an error 4080 message the -c command of acpconfig is used. The msgbits array holds 4081 info about whether each message is enabled or disabled. Setting a bit 4082 to 1 disables a message. Clearing a bit to 0 enables a message. 4083 All messages start as enabled. 4084 22-Apr-88: V3.0 - Brad Engstrom 4085 Added check for DDAMAINT_BRD in probe routine. If DDAMAINT_BRD is 4086 defined then assume we are using a maintenence board so don't try to 4087 find the firmware id because it won't be there. Fake info that was 4088 supposed to be contained in the firmware id. 4089 25-Apr-88: V3.0 - Brad Engstrom 4090 Added check in locate_x25_lcn to see if state of lc is LC_CALL_PENDING 4091 or LC_DATA_IDLE in the loop that looks for an already open lc. This 4092 will prevent an address of 0.0.0.0 from matching a circuit that is not 4093 in use. If the address is invalid then the imp will kick it out. 4094 26-Apr-88: V3.0 - Brad Engstrom 4095 Changed the -n command case so that a command of the form "-n 0" will 4096 return the number of channels currently available. This will be used 4097 by the -l command and possible by the -h command to determine the 4098 number of available circuits. 4099 10-May-88: V3.0 - Brad Engstrom 4100 Made all occurences of the length of and X.25 address refer to the 4101 constants MAXADDRLEN and MINADDRLEN defined in if_ddavar.h. These 4102 constants include the 1 byte for encoding the length. 4103 02-Jun-88: V3.0 - Brad Engstrom 4104 Change the check for the firmware revision level to 2.2 for the -e 4105 command. This command will crash [56]250s that don't have at least 4106 v2.2 firmware. 4107 12-Jul-88: V3.0 - Brad Engstrom 4108 Deleted case for class_b_c addressing. 4109 20-Jul-88: V3.0 - Brad Engstrom 4110 Fixed bug in parsing facilities that would cause the kernel to hang. 4111 The bug was not incrmenting pointers when an urecognized 2 octet 4112 facility was seen. Fixes were applied to send_supr() and 4113 decode_answer() 4114 30-Aug-88: V4.0 - Brad Engstrom 4115 Modified driver to support X.29 and a programmers interface. Includes 4116 files if_x29.c, if_pi.c, and if_pivar.h 4117 30-Aug-88: V4.0 - Brad Engstrom 4118 Added support for debug logging under the control of the DDA_MSGQ 4119 define. Information is extracted using the new -p command of 4120 acpconfig. 4121 30-Aug-88: V4.0 - Brad Engstrom 4122 Modified start_chan to check the ready bit before touching the 4123 comregs. Also modified dda_rrq and dda_wrq to raise ipl before 4124 touching the sioq. These changes fixed a bug where the FE was losing 4125 I/O requests. 4126 20-Oct-88: V4.0 - Steve Johnson 4127 Added SIMULATION #ifdef for simulation support 4128 08-Jan-89: V4.1 - Steve Johnson 4129 MERGE 4.0 and 3.1 4130 10-Oct-88: V3.1 - Charles Carvalho 4131 Replace prt_x25 with fmt_x25, which returns a pointer to a formatted 4132 message instead of printing its data; this allows error messages to be 4133 output with a single call to DDALOG (or syslog). Move prt_addr 4134 inline, for same reason. Add IP address to some error messages; 4135 trim excess text from some error messages. Allocate channels 4136 for incoming calls from lowest channel up; we do linear searches of 4137 the lcn table, so it's to our advantage to use the lowest numbers for 4138 all active circuits. (The lcn is not related to the virtual circuit 4139 number, so there is no need to allocate incoming channels from the 4140 top down.) Modify prt_bytes to take unit number and descriptive 4141 string to be printed along with the buffer and byte count; it now 4142 formats up to 16 bytes at a time and prints a full line with each call 4143 to DDALOG rather than calling DDALOG for each byte. 4144 17-Oct-88: V3.1 - Charles Carvalho 4145 Add definitions for DDALOG and DDAELOG, which translate into a call to 4146 DDALOG() or log(). 4147 26-Oct-88: V3.1 - Charles Carvalho 4148 Change index for 'v' ioctl to preserve compatibility with previous 4149 versions. Restrict maximum window size to 127, not 128. 4150 7-Nov-88: V3.2 - Charles Carvalho 4151 Fix check for no free circuits when processing RING 4152 17-Feb-89: V4.3.0 - Paul Traina 4153 Added TGV changes for Multinet. 4154 8-Mar-89: V4.3.1 - Steve Johnson 4155 Installed 'Q' ioctl to support obtaining an internal trace log used 4156 for debugging only -- not documented for general user. acpconfig 4157 dda0 -q 2 dumps 256 bytes from the dda_debug_silo[] array 4158 13-Mar-89: V4.3.2 - Paul Traina 4159 Updated Multinet support. 4160 17-Apr-89: V4.3.3 - Steve Johnson 4161 Split bus and simulation related code out to included files for first 4162 shot at 7000 and tahoe design. Don't reset timeout counter in 4163 dda_data() unless link really is in idle state. 4164 28-Apr-89: V4.3.4 - Paul Traina 4165 Modified changes of 17-Apr-89, added minimal tahoe support until 4166 driver modified to use 4.3uba transfers. 4167 Fixed timeout fix of 17-Apr-89 to do what was intended. 4168 Fixed code dealing with maintenance board, reformatted with indent 4169 to repair readablility. 4170 09-May-89: V4.3.5 - Paul Traina 4171 Minimal tahoe support completed, based on BSD4_3TAHOE define which 4172 must be uncommented manually. Finalizing for ECO. 4173 24-May-89: V4.3.6 - Paul Traina 4174 Ultrix 3.0 support added. Revised 4.3 tahoe support for automatic 4175 invocation. 4176 *** NOTE: one of the three OS defines (ACC_BSD, ACC_ULTRIX, ACC_VMS) 4177 in if_dda.c must be set to a non-zero value for the driver to 4178 compile. 4179 Attempting multiple-os support based upon weird variables from include 4180 files is not acceptable with the latest proliferation of OS versions. 4181 20-Jun-89: V4.3.7 - Paul Traina 4182 Removed crufty old debug stuff and integrated it with the log-message 4183 code. Now X29 and PI modules can be debuged properly (no #if 0's!). 4184 22-Jun-89: - Paul Traina 4185 Diddled ring-decode logic to check for proper ring packet decoding 4186 before attempting to find a free lcn. This will make it easier to deal 4187 with the race condition with find_free_lcn(). 4188 Modified ACC os specific equates to be set as options in the config 4189 file. This way, most users won't ever edit if_dda.c. 4190 18-Jul-89: - Paul Traina 4191 Driver will no longer return errors if duplicate address-translation 4192 entries are made. Errors will only happen if a redefiniton is 4193 attempted. 4194 Moved dc_key.ttyline out of union, creating dc_line. 4195 26-Jul-89: - Paul Traina f/Brad Engstrom 4196 Added support for called user-data field (two new params to 4197 make_x25_call) to support extended pad mode in the X.29 module. 4198 01-Aug-89: - Paul Traina 4199 Made ddamsgs uninitialized -- it gets inited in ddaattach now. 4200 03-Aug-89: - Paul Traina 4201 Changed hist_copyout definition to PRIVATE. 4202 15-Aug-89: - Paul Traina 4203 Made dda_softc and dda_iobuf non-private. 4204 18-Aug-89: - Paul Traina 4205 Somehow, ddareset was removed from the 'z' ioctl. 4206 28-Aug-89: - Paul Traina 4207 Changed make_x25_call so that it checks length of data to be stuffed 4208 into the mbuf before actually copying data in. Removed udlen and 4209 ud parameters to the routine, as the public areas will be plugged 4210 with data before being called. (May need to splimp()). 4211 22-Sep-89: - Paul Traina 4212 The order of the 'v' ioctl parameters was screwed up. This caused 4213 window and packet size setting to fail. 4214 23-Oct-89: - Paul Traina 4215 Added further support for Steve's yetchy simulation. Updated main 4216 module to work with BI version of dda board. 4217 29-Oct-89: - Paul Traina 4218 Acpconfig inconsistancy (again): removed the 'p', and 'Q' ioctls. 4219 Since all of these are queries, I placed them under the 'q' ioctl 4220 with a new switch. Some day we should just scrap the whole mess 4221 and design a proper ioctl interface. 4222 11-Nov-89: - Paul Traina 4223 Moved rrq/wrq routines into bus modules because we can do several 4224 queue reads and writes when working with the BI. 4225 */ 4226 #endif NDDA > 0 4227