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
ddaioctl(ifp,cmd,data)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
ddatimer(unit)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
send_config(ds,p)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 *
locate_x25_lcn(ds,ip_addr)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 *
find_free_lcn(ds)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
convert_ip_addr(ip_addr,x25addr,ds)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
convert_x25_addr(x25addr,ds,dc)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
make_x25_call(ds,dc,ip_addr,proto,udlen,ud)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
dda_start(ds,dc)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
dda_data(ds,hc,cc,cnt)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
dda_supr(ds,hc,cc,cnt)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
supr_msg(ds,p)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
decode_answer(p,dc)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
decode_ring(p)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
clear_lcn(ds,dc)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
send_restart(ds)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
send_supr(ds,cmd,p1,p2)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
start_supr(ds,m)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
abort_io(unit,lcn)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
prt_bytes(unit,label,bp,cnt)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 *
fmt_x25(bp,cnt)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
hist_init(unit,reset)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
hist_lcn_state(unit,old_state,new_state)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
hist_all_lcns(unit,state)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
hist_link_state(unit,old_state,new_state)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
hist_read(unit)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
hist_copyout(unit,to)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
dda_decode_type(ds,p)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
dda_mqstr(s)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
dda_mqnum(num,type)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