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