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