xref: /csrg-svn/sys/vax/if/if_ddn.c (revision 24801)
1*24801Skarels /*	@(#)if_ddn.c	6.2 (Berkeley) 09/16/85 */
224434Skarels 
324434Skarels 
424434Skarels /************************************************************************\
524434Skarels 
624434Skarels      ________________________________________________________
724434Skarels     /                                                        \
824434Skarels    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
924434Skarels    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
1024434Skarels    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
1124434Skarels    |       AAAA AAAA      CCCC              CCCC              |
1224434Skarels    |      AAAA   AAAA     CCCC              CCCC              |
1324434Skarels    |     AAAA     AAAA    CCCC              CCCC              |
1424434Skarels    |    AAAA       AAAA   CCCC              CCCC              |
1524434Skarels    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
1624434Skarels    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
1724434Skarels    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
1824434Skarels     \________________________________________________________/
1924434Skarels 
2024434Skarels 	Copyright (c) 1985 by Advanced Computer Communications
2124434Skarels 	720 Santa Barbara Street, Santa Barbara, California  93101
2224434Skarels 	(805) 963-9431
2324434Skarels 
2424434Skarels 	This software may be duplicated and used on systems
2524434Skarels 	which are licensed to run U.C. Berkeley versions of
2624434Skarels 	the UNIX operating system.  Any duplication of any
2724434Skarels 	part of this software must include a copy of ACC's
2824434Skarels 	copyright notice.
2924434Skarels 
3024434Skarels 
3124434Skarels File:
3224434Skarels 		if_ddn.c
3324434Skarels 
3424434Skarels Author:
3524434Skarels 		Art Berggreen
3624434Skarels 
3724434Skarels Project:
3824434Skarels 		4.2 DDN X.25 network driver
3924434Skarels 
4024434Skarels Function:
4124434Skarels 		This is a network device driver for BSD 4.2 UNIX which
4224434Skarels 		provides an interface between IP and ACC's ACP625
4324434Skarels 		(IF-11/X25) for connecting to the Defense Data Network.
4424434Skarels 
4524434Skarels Components:
4624434Skarels 
4724434Skarels Revision History:
4824434Skarels 		16-May-1985:	V1.0 - First release.
4924434Skarels 				Art Berggreen.
5024434Skarels 
5124434Skarels \************************************************************************/
5224434Skarels 
5324434Skarels 
5424434Skarels /*	if_ddn.c	 V1.0	5/16/85	*/
5524434Skarels 
5624434Skarels /*
5724434Skarels  * ACC ACP625 DDN/X.25 Network device driver
5824434Skarels  */
5924434Skarels 
6024434Skarels /* #define DDNDEBUG 1		/* Enable definition for Debug code */
6124434Skarels 
6224434Skarels #include "ddn.h"
6324434Skarels #if NDDN > 0
6424434Skarels #include "../machine/pte.h"
6524434Skarels 
66*24801Skarels #include "param.h"
67*24801Skarels #include "systm.h"
68*24801Skarels #include "mbuf.h"
69*24801Skarels #include "buf.h"
70*24801Skarels #include "protosw.h"
71*24801Skarels #include "socket.h"
72*24801Skarels #include "vmmac.h"
73*24801Skarels #include "errno.h"
74*24801Skarels #include "time.h"
75*24801Skarels #include "kernel.h"
76*24801Skarels #include "ioctl.h"
7724434Skarels 
7824434Skarels #include "../net/if.h"
7924434Skarels #include "../net/netisr.h"
8024434Skarels #include "../net/route.h"
81*24801Skarels 
82*24801Skarels #ifdef	BBNNET
83*24801Skarels #define	INET
84*24801Skarels #endif
85*24801Skarels #ifdef	INET
8624434Skarels #include "../netinet/in.h"
8724434Skarels #include "../netinet/in_systm.h"
88*24801Skarels #include "../netinet/in_var.h"
8924434Skarels #include "../netinet/ip.h"
90*24801Skarels #endif
9124434Skarels 
9224434Skarels #include "../vax/cpu.h"
9324434Skarels #include "../vax/mtpr.h"
94*24801Skarels #include "if_ddnreg.h"
95*24801Skarels #include "if_ddnvar.h"
96*24801Skarels #include "if_uba.h"
9724434Skarels #include "../vaxuba/ubareg.h"
9824434Skarels #include "../vaxuba/ubavar.h"
9924434Skarels 
10024434Skarels 
10124434Skarels 
10224434Skarels /* declare global functions */
10324434Skarels 
10424434Skarels int ddnprobe();
10524434Skarels int ddnattach();
10624434Skarels int ddnreset();
10724434Skarels int ddninit();
10824434Skarels int ddnoutput();
10924434Skarels int ddntimer();
11024434Skarels int ddnioctl();
11124434Skarels int ddnintr();
11224434Skarels 
11324434Skarels /* declare local functions */
11424434Skarels 
11524434Skarels static void x25_init();
11624434Skarels static struct ddn_cb *locate_x25_lcn();
11724434Skarels static boolean convert_ip_addr();
11824434Skarels static int convert_x25_addr();
11924434Skarels static boolean make_x25_call();
12024434Skarels static void ddn_start();
12124434Skarels static void ddn_iorq();
12224434Skarels static void start_chn();
12324434Skarels static void ddn_data();
12424434Skarels static void ddn_supr();
12524434Skarels static void supr_msg();
12624434Skarels static boolean decode_ring();
12724434Skarels static void clear_lcn();
12824434Skarels static void send_restart();
12924434Skarels static void send_supr();
13024434Skarels #ifdef DDNDEBUG
13124434Skarels static void prt_addr();
13224434Skarels static void prt_bytes();
13324434Skarels #endif DDNDEBUG
13424434Skarels 
13524434Skarels 
13624434Skarels struct	uba_device *ddninfo[NDDN];	/* ptrs to device info */
13724434Skarels u_short	ddnstd[] = { 0766740, 0 };	/* standard addresses */
13824434Skarels struct	uba_driver ddndriver =		/* device driver info */
13924434Skarels   {
14024434Skarels     ddnprobe,				/* device probe routine */
14124434Skarels     0,					/* slave probe routine */
14224434Skarels     ddnattach,				/* device attach routine */
14324434Skarels     0,					/* "dmago" routine */
14424434Skarels     ddnstd,				/* device address */
14524434Skarels     "ddn",				/* device name */
14624434Skarels     ddninfo				/* ptr to device info ptrs */
14724434Skarels   };
14824434Skarels 
14924434Skarels static u_char init_msg[] =
15024434Skarels   {
15124434Skarels     LINE_CNTL,				/* set command code */
15224434Skarels     0x00,				/* not used */
15324434Skarels     0x00,				/* not used */
15424434Skarels     0x00,				/* extension length (set at runtime) */
15524434Skarels     LINK_DISABLE,			/* link disable */
15624434Skarels /*    LINK_LOOPBACK,			/* loopback mode */
15724434Skarels /*    LOOP_INTERNAL,			/*   = internal loopback */
15824434Skarels     PKT_SIZE,				/* packet size */
15924434Skarels     0x80,				/*   128 - LSB */
16024434Skarels     0x00,				/*   128 - MSB */
16124434Skarels     PKT_WINDOW,				/* packet window */
16224434Skarels     0x02,				/*   = 2 */
16324434Skarels     LINK_ENABLE				/* link enable */
16424434Skarels   };
16524434Skarels 
16624434Skarels u_char cb_cmnd[4] =
16724434Skarels   {
16824434Skarels     CALL,
16924434Skarels     0,
17024434Skarels     0,
17124434Skarels     0
17224434Skarels   };
17324434Skarels 
17424434Skarels u_char cb_called_addr[16] = {0};
17524434Skarels 
17624434Skarels u_char cb_calling_addr[16] = {0};
17724434Skarels 
17824434Skarels u_char cb_facilities[64] = {0};
17924434Skarels 
18024434Skarels u_char cb_protocol[5] = {0};
18124434Skarels 
18224434Skarels u_char cb_user_data[1] = {0};
18324434Skarels 
18424434Skarels #ifdef DDNDEBUG
18524434Skarels int ddn_debug = 1;		/* values 0-8 cause increasing verbosity */
18624434Skarels #endif DDNDEBUG
18724434Skarels 
18824434Skarels 
18924434Skarels /***********************************************************************\
19024434Skarels *									*
19124434Skarels *	Information for each device unit is maintained in an array	*
19224434Skarels *	of structures named ddn_softc[].  The array is indexed by	*
19324434Skarels *	unit number.  Each entry includes the network interface		*
19424434Skarels *	structure (ddn_if) used by the routing code to locate the	*
19524434Skarels *	interface,  an array of Logical	Channel control blocks which	*
19624434Skarels *	maintain information about each of the Logical Channels (LCNs)	*
19724434Skarels *	through which X.25 virtual calls are established, a queue of	*
19824434Skarels *	I/O requests pending for the UMC, the UNIBUS interrupt vector	*
19924434Skarels *	for the unit and misc flags.  The Logical Channel Control	*
20024434Skarels *	blocks maintain information about the state of each LCN,	*
20124434Skarels *	a queue of outbound data, Half Duplex Channel (HDX) blocks	*
20224434Skarels *	used for queuing I/O requests to the UMC and an ifuba		*
20324434Skarels *	structure which records the UNIBUS resources being held by	*
20424434Skarels *	the LCN.							*
20524434Skarels *									*
20624434Skarels \***********************************************************************/
20724434Skarels 
20824434Skarels struct sioq		/* Start I/O queue head */
20924434Skarels   {
21024434Skarels     struct hdx_chan	*sq_head;	/* queue head */
21124434Skarels     struct hdx_chan	*sq_tail;	/* queue tail */
21224434Skarels   };
21324434Skarels 
21424434Skarels struct hdx_chan		/* HDX channel block */
21524434Skarels   {
21624434Skarels     struct hdx_chan	*hc_next;	/* link to next HDX channel */
21724434Skarels     u_char		hc_chan;	/* HDX channel number */
21824434Skarels     u_char		hc_adx;		/* address bits 17-16 */
21924434Skarels     u_short		hc_addr;	/* address bits 15-00 */
22024434Skarels     u_short		hc_cnt;		/* byte count */
22124434Skarels     u_char		hc_func;	/* I/O function */
22224434Skarels     u_char		hc_sbfc;	/* I/O subfunction */
22324434Skarels   };
22424434Skarels 
22524434Skarels struct ddn_cb		/* Logical Channel control block */
22624434Skarels   {
22724434Skarels     struct in_addr	dc_inaddr;	/* remote Internet address */
22824434Skarels     u_char		dc_lcn;		/* LCN number */
22924434Skarels     u_char		dc_state;	/* LCN state */
23024434Skarels     u_short		dc_timer;	/* LCN timer */
23124434Skarels     struct ifqueue	dc_oq;		/* LCN output queue */
23224434Skarels     struct hdx_chan	dc_rchan;	/* LCN read HDX channel */
23324434Skarels     struct hdx_chan	dc_wchan;	/* LCN write HDX channel */
23424434Skarels     struct ifuba	dc_ifuba;	/* UNIBUS resources */
23524434Skarels     u_short		dc_flags;	/* misc flags */
23624434Skarels   };
23724434Skarels 
23824434Skarels struct ddn_softc	/* device control structure */
23924434Skarels   {
24024434Skarels     struct ifnet	ddn_if;		/* network-visible interface */
24124434Skarels     struct ddn_cb	ddn_cb[NDDNCH+1]; /* Logical Channel cntl blks */
24224434Skarels     struct sioq		ddn_sioq;	/* start I/O queue */
24324434Skarels     int			ddn_vector;	/* UNIBUS interrupt vector */
24424434Skarels     u_short		ddn_flags;	/* misc flags */
245*24801Skarels     struct in_addr	ddn_ipaddr;	/* local IP address */
24624434Skarels   } ddn_softc[NDDN];
24724434Skarels 
24824434Skarels 
24924434Skarels /***********************************************************************\
25024434Skarels *				ddnprobe()				*
25124434Skarels *************************************************************************
25224434Skarels *									*
25324434Skarels *	This routine probes the device to obtain the UNIBUS interrupt	*
25424434Skarels *	vector.  Since the UMC is a soft vector device, we obtain	*
25524434Skarels *	an unused vector from the uba structure and return that.	*
25624434Skarels *	The UMC is given the vector and the board is reset.		*
25724434Skarels *	In order to save the vector in the device info structure, we	*
25824434Skarels *	place it in a static temporary where the attach routine can	*
25924434Skarels *	find it and save it in the device info structure.  This is	*
26024434Skarels *	necessary because probe only provides a pointer to the device	*
26124434Skarels *	and we have no idea which unit is being referenced.  This	*
26224434Skarels *	works in 4.2 because the attach routine is called immediately	*
26324434Skarels *	after a successful probe.					*
26424434Skarels *									*
26524434Skarels \***********************************************************************/
26624434Skarels 
26724434Skarels #define INIT_DELAY	(100 * 2)	/* time for board initialization */
26824434Skarels 					/*   ( in 10 millisecond ticks) */
26924434Skarels 
27024434Skarels static int savevec;			/* static variable for vector */
27124434Skarels 
27224434Skarels ddnprobe(reg)
27324434Skarels caddr_t reg;
27424434Skarels   {
27524434Skarels     register int br, cvec;		/* r11, r10 value-result */
27624434Skarels     register struct ddnregs *addr = (struct ddnregs *)reg;
27724434Skarels     register int delay_time;
27824434Skarels 
27924434Skarels #ifdef lint
28024434Skarels     br = 0; cvec = br; br = cvec;
28124434Skarels #endif
28224434Skarels 
28324434Skarels     cvec = savevec = (uba_hd[numuba].uh_lastiv -= 4);	/* return vector */
28424434Skarels     br = 0x15;				/* return bus level */
28524434Skarels 
28624434Skarels     addr->ioini = 0;			/* clear handshake flags */
28724434Skarels     addr->ionmi = 0;
28824434Skarels     addr->staack = 0;
28924434Skarels     addr->xfrgnt = 0;
29024434Skarels     addr->iovect = cvec >> 2;		/* pass vector to UMC */
29124434Skarels     addr->csr = DDN_RST;		/* reset the board */
29224434Skarels     delay_time = mfpr(TODR) + INIT_DELAY;
29324434Skarels     while(delay_time > mfpr(TODR)) /* wait */ ;
29424434Skarels 
29524434Skarels     return (sizeof(struct ddnregs));
29624434Skarels   }
29724434Skarels 
29824434Skarels 
29924434Skarels /***********************************************************************\
30024434Skarels *				ddnattach				*
30124434Skarels *************************************************************************
30224434Skarels *									*
30324434Skarels *	This routine attaches the device to the network software.	*
30424434Skarels *	The network interface structure is filled in.  The device	*
30524434Skarels *	will be initialized when the system is ready to accept packets.	*
30624434Skarels *									*
30724434Skarels \***********************************************************************/
30824434Skarels 
30924434Skarels ddnattach(ui)
31024434Skarels struct uba_device *ui;
31124434Skarels   {
31224434Skarels     register struct ddn_softc *ds = &ddn_softc[ui->ui_unit];
31324434Skarels 
31424434Skarels     ds->ddn_vector = savevec;		/* save vector from probe() */
31524434Skarels     ds->ddn_if.if_unit = ui->ui_unit;	/* set unit number */
31624434Skarels     ds->ddn_if.if_name = "ddn";		/* set device name */
31724434Skarels     ds->ddn_if.if_mtu = DDNMTU;		/* set max msg size */
31824434Skarels     ds->ddn_if.if_init = ddninit;	/* set init routine addr */
31924434Skarels     ds->ddn_if.if_ioctl = ddnioctl;	/* set ioctl routine addr */
32024434Skarels     ds->ddn_if.if_output = ddnoutput;	/* set output routine addr */
32124434Skarels     ds->ddn_if.if_reset = ddnreset;	/* set reset routine addr */
32224434Skarels     ds->ddn_if.if_watchdog = ddntimer;	/* set timer routine addr */
323*24801Skarels     if_attach(&ds->ddn_if);
32424434Skarels   }
32524434Skarels 
32624434Skarels 
32724434Skarels /***********************************************************************\
32824434Skarels *				ddnreset()				*
32924434Skarels *************************************************************************
33024434Skarels *									*
33124434Skarels *	Reset of interface after UNIBUS reset.				*
33224434Skarels *	If interface is on specified uba, reset its state.		*
33324434Skarels *									*
33424434Skarels \***********************************************************************/
33524434Skarels 
33624434Skarels ddnreset(unit, uban)
33724434Skarels int unit, uban;
33824434Skarels   {
33924434Skarels     register struct uba_device *ui;
34024434Skarels     register struct ddnregs *addr;
34124434Skarels     register int delay_time;
34224434Skarels 
34324434Skarels     if (unit >= NDDN || (ui = ddninfo[unit]) == 0 || ui->ui_alive == 0 ||
34424434Skarels       ui->ui_ubanum != uban)
34524434Skarels 	return;
34624434Skarels 
34724434Skarels     printf(" ddn%d", unit);
34824434Skarels 
34924434Skarels     addr = (struct ddnregs *)ui->ui_addr;
35024434Skarels     addr->ioini = 0;			/* clear handshake flags */
35124434Skarels     addr->ionmi = 0;
35224434Skarels     addr->staack = 0;
35324434Skarels     addr->xfrgnt = 0;
35424434Skarels     addr->iovect = ddn_softc[unit].ddn_vector >> 2;  /* pass vector to UMC */
35524434Skarels     addr->csr = DDN_RST;		/* reset the board */
35624434Skarels     delay_time = mfpr(TODR) + INIT_DELAY;
35724434Skarels     while(delay_time > mfpr(TODR)) /* wait */ ;
35824434Skarels 
35924434Skarels     ddninit(unit);
36024434Skarels   }
36124434Skarels 
36224434Skarels 
36324434Skarels /***********************************************************************\
36424434Skarels *				ddninit()				*
36524434Skarels *************************************************************************
36624434Skarels *									*
36724434Skarels *	This routine initializes the interface for operation.  The	*
36824434Skarels *	device control blocks are initialized, UNIBUS resources are	*
36924434Skarels *	allocated and an X.25 initialization message is sent to the	*
37024434Skarels *	UMC.								*
37124434Skarels *									*
37224434Skarels \***********************************************************************/
37324434Skarels 
37424434Skarels ddninit(unit)
37524434Skarels int unit;
37624434Skarels   {
37724434Skarels     register struct ddn_softc *ds = &ddn_softc[unit];
37824434Skarels     register struct ddn_cb *dc;
37924434Skarels     register struct uba_device *ui = ddninfo[unit];
38024434Skarels     int lcn, s;
38124434Skarels 
38224434Skarels #ifdef DDNDEBUG
38324434Skarels if (ddn_debug > 0)
38424434Skarels   {
38524434Skarels printf("ddn%d: ddninit()\n", unit);
38624434Skarels   }
38724434Skarels #endif DDNDEBUG
38824434Skarels 
389*24801Skarels     if (ds->ddn_if.if_addrlist == 0)	/* if we have no internet addr */
39024434Skarels 	return;				/*   don't init yet */
39124434Skarels 
39224434Skarels     dc = ds->ddn_cb;			/* setup ptr to first LCN cntl block */
39324434Skarels 
39424434Skarels     for(lcn = 0; lcn <= NDDNCH; lcn++)	/* for all LCN's ... */
39524434Skarels       {
39624434Skarels     	dc->dc_lcn = lcn;		/* record LCN */
39724434Skarels     	dc->dc_inaddr.s_addr = 0;	/* clear remote internet addr */
39824434Skarels     	dc->dc_state = LC_DOWN;		/* init LCN state */
39924434Skarels     	dc->dc_timer = TMO_OFF;		/* turn LCN timer off */
40024434Skarels 
40124434Skarels 		/* init LCN output queue */
40224434Skarels 
40324434Skarels     	dc->dc_oq.ifq_head = (struct mbuf *)0;
40424434Skarels     	dc->dc_oq.ifq_tail = (struct mbuf *)0;
40524434Skarels     	dc->dc_oq.ifq_len = 0;
40624434Skarels     	dc->dc_oq.ifq_maxlen = DDN_OQMAX;
40724434Skarels     	dc->dc_oq.ifq_drops = 0;
40824434Skarels 
40924434Skarels     		/* init HDX channels */
41024434Skarels 
41124434Skarels     	dc->dc_rchan.hc_next = (struct hdx_chan *)0;
41224434Skarels     	dc->dc_rchan.hc_chan = lcn * 2;
41324434Skarels     	dc->dc_wchan.hc_next = (struct hdx_chan *)0;
41424434Skarels     	dc->dc_wchan.hc_chan = (lcn * 2) + 1;
41524434Skarels 
41624434Skarels     		/* init UNIBUS resources */
41724434Skarels 
41824434Skarels     	if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
41924434Skarels     	    0, (int)btoc(DDNMTU)) == 0)
42024434Skarels     	  {
42124434Skarels     	    printf("ddn%d: failed getting UBA resources for lcn %d\n",
42224434Skarels     		unit, lcn);
42324434Skarels     	    ds->ddn_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
42424434Skarels     	    return;
42524434Skarels     	  }
42624434Skarels 
42724434Skarels     	dc->dc_flags = 0;		/* initialize flags */
42824434Skarels 
42924434Skarels 	dc++;				/* point at next cntl blk */
43024434Skarels       }
43124434Skarels 
43224434Skarels     ds->ddn_sioq.sq_head = (struct hdx_chan *)0;
43324434Skarels     ds->ddn_sioq.sq_tail = (struct hdx_chan *)0;
43424434Skarels     ds->ddn_if.if_flags |= IFF_RUNNING;
43524434Skarels 
43624434Skarels     s = splimp();
43724434Skarels 
43824434Skarels     dc = ds->ddn_cb;			/* setup ptr to first LCN cntl block */
43924434Skarels 
44024434Skarels     for(lcn = 0; lcn <= NDDNCH; lcn++)	/* issue reads on all LCNs */
44124434Skarels       {
44224434Skarels     	ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
44324434Skarels 	dc++;
44424434Skarels       }
44524434Skarels 
44624434Skarels     x25_init(ds);			/* init the X.25 board */
44724434Skarels 
44824434Skarels     splx(s);
44924434Skarels 
45024434Skarels     ddntimer(unit);			/* start timers */
45124434Skarels   }
45224434Skarels 
45324434Skarels 
45424434Skarels /***********************************************************************\
45524434Skarels *				ddnoutput()				*
45624434Skarels *************************************************************************
45724434Skarels *									*
45824434Skarels *	This routine is called by the network software when it has	*
45924434Skarels *	an IP datagram to send out this interface.  An attempt is	*
46024434Skarels *	made to find a LCN which has a virtual circuit open to the	*
46124434Skarels *	indicated host.  If an LCN is found the packet is queued for	*
46224434Skarels *	output on that LCN.						*
46324434Skarels *									*
46424434Skarels \***********************************************************************/
46524434Skarels 
46624434Skarels ddnoutput(ifp, m0, dst)
46724434Skarels struct ifnet *ifp;
46824434Skarels struct mbuf *m0;
46924434Skarels struct sockaddr_in *dst;
47024434Skarels   {
47124434Skarels     register struct mbuf *m = m0;
47224434Skarels     register struct ddn_softc *ds = &ddn_softc[ifp->if_unit];
47324434Skarels     register struct ddn_cb *dc;
47424434Skarels     register struct ifqueue *oq;
47524434Skarels     int s;
47624434Skarels 
47724434Skarels     if ((ds->ddn_if.if_flags & IFF_UP) == 0)
47824434Skarels 	return (ENETDOWN);
47924434Skarels 
48024434Skarels     switch (dst->sin_family)
48124434Skarels       {
48224434Skarels 
48324434Skarels #ifdef INET
48424434Skarels     case AF_INET:
48524434Skarels 	break;
48624434Skarels #endif INET
48724434Skarels 
48824434Skarels     default:
48924434Skarels 	printf("ddn%d: can't handle af%d\n", ifp->if_unit,
49024434Skarels 	    dst->sin_family);
49124434Skarels 	m_freem(m0);
49224434Skarels 	return (EAFNOSUPPORT);
49324434Skarels       }
49424434Skarels 
49524434Skarels 
49624434Skarels #ifdef DDNDEBUG
49724434Skarels if (ddn_debug > 6)
49824434Skarels   {
49924434Skarels printf("ddnoutput(): dst = ");
50024434Skarels prt_addr(dst->sin_addr.s_addr);
50124434Skarels printf("\n");
50224434Skarels   }
50324434Skarels #endif DDNDEBUG
50424434Skarels 
50524434Skarels     s = splimp();
50624434Skarels 
50724434Skarels     /* try to find an LCN */
50824434Skarels 
50924434Skarels     if (dc = locate_x25_lcn(ds, dst->sin_addr))
51024434Skarels       {						/* if found */
51124434Skarels 	oq = &(dc->dc_oq);			/*   point to output queue */
51224434Skarels 	dc->dc_state = LC_DATA_IDLE;
51324434Skarels 	dc->dc_timer = TMO_DATA_IDLE;
51424434Skarels 	if (IF_QFULL(oq))			/*   if q full */
51524434Skarels     	  {
51624434Skarels 	    IF_DROP(oq);			/*     drop the data */
51724434Skarels 	    m_freem(m);
51824434Skarels 	    splx(s);
51924434Skarels 	    return (ENOBUFS);
52024434Skarels 	  }
52124434Skarels 	IF_ENQUEUE(oq, m);			/*   otherwise queue it */
52224434Skarels 	ddn_start(ds, dc);			/*   and try to output */
52324434Skarels 	splx(s);
52424434Skarels 	return (0);
52524434Skarels       }
52624434Skarels     else					/* if no circuit available */
52724434Skarels       {
52824434Skarels     	IF_DROP(&ifp->if_snd);			/*   drop the data */
52924434Skarels     	m_freem(m);
53024434Skarels 	splx(s);
53124434Skarels 	return (EHOSTUNREACH);
53224434Skarels       }
53324434Skarels 
53424434Skarels   }
53524434Skarels 
53624434Skarels 
53724434Skarels /***********************************************************************\
53824434Skarels *				ddntimer()				*
53924434Skarels *************************************************************************
54024434Skarels *									*
54124434Skarels *	This routine is entered once a second to perform timer		*
54224434Skarels *	managment.  The LCN table is scanned for active timers,		*
54324434Skarels *	(nonzero) which are decremented.  If a timer expires		*
54424434Skarels *	(becomes zero), the proper action is taken.			*
54524434Skarels *									*
54624434Skarels \***********************************************************************/
54724434Skarels 
54824434Skarels int ddntimer(unit)
54924434Skarels int unit;
55024434Skarels   {
55124434Skarels     register struct ddn_softc *ds = &ddn_softc[unit];
55224434Skarels     register struct ddn_cb *dc;
55324434Skarels     register int s, lcn;
55424434Skarels 
55524434Skarels #ifdef DDNDEBUG
55624434Skarels if (ddn_debug > 7)
55724434Skarels   {
55824434Skarels printf("ddntimer()\n");
55924434Skarels   }
56024434Skarels #endif DDNDEBUG
56124434Skarels 
56224434Skarels     ds->ddn_if.if_timer = DDN_TIMEOUT;		/* restart timer */
56324434Skarels 
56424434Skarels     dc = ds->ddn_cb;
56524434Skarels 
56624434Skarels     s = splimp();
56724434Skarels 
56824434Skarels     for(lcn = 0; lcn <= NDDNCH; lcn++)		/* scan all LCN's */
56924434Skarels       {
57024434Skarels     	if (dc->dc_timer && (--(dc->dc_timer) == 0))
57124434Skarels     	  {					/* if a timer expired */
57224434Skarels     	    if (dc->dc_state == LC_RESTART)
57324434Skarels     	      {					/*   if a restart was out */
57424434Skarels     		send_restart(ds);		/*     send another one */
57524434Skarels     		break;
57624434Skarels     	      }
57724434Skarels     	    else				/*   otherwise */
57824434Skarels     	      {
57924434Skarels     		clear_lcn(ds, dc);		/*     clear the LCN */
58024434Skarels     	      }
58124434Skarels     	  }
58224434Skarels 	dc++;
58324434Skarels       }
58424434Skarels     splx(s);
58524434Skarels   }
58624434Skarels 
58724434Skarels 
58824434Skarels /***********************************************************************\
58924434Skarels *				ddnioctl()				*
59024434Skarels *************************************************************************
59124434Skarels *									*
59224434Skarels *	This routine processes device dependent ioctl's.  Currently,	*
59324434Skarels *	the only ioctl supported is used to set the host's internet	*
59424434Skarels *	address for this network interface.				*
59524434Skarels *									*
59624434Skarels \***********************************************************************/
59724434Skarels 
59824434Skarels ddnioctl(ifp, cmd, data)
599*24801Skarels 	register struct ifnet *ifp;
600*24801Skarels 	int cmd;
601*24801Skarels 	caddr_t data;
602*24801Skarels {
603*24801Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
604*24801Skarels 	int s = splimp(), error = 0;
605*24801Skarels 	struct endevice *enaddr;
60624434Skarels 
607*24801Skarels 	switch (cmd) {
60824434Skarels 
609*24801Skarels 	case SIOCSIFADDR:
610*24801Skarels 		if (ifa->ifa_addr.sa_family != AF_INET)
611*24801Skarels 			return(EINVAL);
612*24801Skarels 		ifp->if_flags |= IFF_UP;
613*24801Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
614*24801Skarels 			ddninit(ifp->if_unit);
615*24801Skarels 		ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
616*24801Skarels 		break;
61724434Skarels 
618*24801Skarels 	default:
619*24801Skarels 		error = EINVAL;
620*24801Skarels 		break;
621*24801Skarels 	}
622*24801Skarels 	splx(s);
623*24801Skarels 	return (error);
624*24801Skarels }
62524434Skarels 
62624434Skarels 
62724434Skarels /***********************************************************************\
62824434Skarels *				ddnintr()				*
62924434Skarels *************************************************************************
63024434Skarels *									*
63124434Skarels *	This is the interrupt handler for UNIBUS interrupts from the	*
63224434Skarels *	UMC.  The interrupting HDX channel and interrupt type are	*
63324434Skarels *	obtained from the completion comm regs.  If the interrupt is	*
63424434Skarels *	an I/O request acknowledge, the next I/O request is passed	*
63524434Skarels *	to the UMC.  If the interrupt is an I/O completion, the		*
63624434Skarels *	completion is processed depending on whether it is for the	*
63724434Skarels *	supervisor or a data channel.					*
63824434Skarels *									*
63924434Skarels \***********************************************************************/
64024434Skarels 
64124434Skarels ddnintr(unit)
64224434Skarels int unit;
64324434Skarels   {
64424434Skarels     register struct ddn_softc *ds = &ddn_softc[unit];
64524434Skarels     register struct hdx_chan *hc;
64624434Skarels     register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
64724434Skarels     int chan, type, cc, cnt;
64824434Skarels 
64924434Skarels     /*
65024434Skarels      * Check for hardware errors.
65124434Skarels      */
65224434Skarels     if (addr->csr & DDN_UER)
65324434Skarels       {
65424434Skarels 	printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
65524434Skarels 	addr->csr = 0;		/* disable i/f */
65624434Skarels     	return;
65724434Skarels       }
65824434Skarels 
65924434Skarels     /*
66024434Skarels      * Get logical channel info.
66124434Skarels      */
66224434Skarels     if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
66324434Skarels       {
66424434Skarels     	printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
66524434Skarels     	return;
66624434Skarels       }
66724434Skarels 
66824434Skarels     if (chan & 0x01)
66924434Skarels     	hc = &(ds->ddn_cb[chan/2].dc_wchan);
67024434Skarels     else
67124434Skarels     	hc = &(ds->ddn_cb[chan/2].dc_rchan);
67224434Skarels 
67324434Skarels     type = addr->statyp;
67424434Skarels     cc = addr->stacc;
67524434Skarels     cnt = hc->hc_cnt - addr->stacnt;
67624434Skarels 
67724434Skarels     /* Figure out what kind of interrupt it was */
67824434Skarels 
67924434Skarels     switch(type)
68024434Skarels       {
68124434Skarels     case DDNSACK:		/* start i/o accepted */
68224434Skarels     	if (hc != ds->ddn_sioq.sq_head)  /* does ack match waiting req? */
68324434Skarels     	  {
68424434Skarels     	    printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
68524434Skarels     		unit, chan, hc, ds->ddn_sioq.sq_head);
68624434Skarels     	    addr->csr = 0;		/* disable UMC */
68724434Skarels     	    return;
68824434Skarels     	  }
68924434Skarels 
69024434Skarels 	/* dequeue old request by copying link to queue head */
69124434Skarels 	/*   and start next I/O request if queue has not gone empty */
69224434Skarels 
69324434Skarels     	if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
69424434Skarels     	  {
69524434Skarels     	    start_chn(ds);
69624434Skarels     	  }
69724434Skarels     	break;
69824434Skarels 
69924434Skarels     case DDNDONE:		/* i/o completion */
70024434Skarels     	switch (cc)
70124434Skarels     	  {
70224434Skarels     	case DDNIOCABT:		/* probably VCN flush */
70324434Skarels 	    break;
70424434Skarels 
70524434Skarels     	case DDNIOCERR:
70624434Skarels     	    printf("ddn%d: program error ", unit);
70724434Skarels     	    goto daterr;
70824434Skarels 
70924434Skarels     	case DDNIOCOVR:
71024434Skarels     	    printf("ddn%d: overrun error ", unit);
71124434Skarels     	    goto daterr;
71224434Skarels 
71324434Skarels     	case DDNIOCUBE:
71424434Skarels     	    printf("ddn%d: NXM timeout or UB parity error ", unit);
71524434Skarels 
71624434Skarels     	daterr:
71724434Skarels     	    printf("chan=%d func=%x\n", chan, hc->hc_func);
71824434Skarels     	    if (hc->hc_func & DDNRDB)
71924434Skarels     		ds->ddn_if.if_ierrors++;
72024434Skarels     	    else
72124434Skarels     		ds->ddn_if.if_oerrors++;
72224434Skarels     	  }
72324434Skarels 
72424434Skarels     	/* was it supervisor or data traffic? */
72524434Skarels 
72624434Skarels     	if (chan > 1)
72724434Skarels     	    ddn_data(unit, chan, cc, cnt);
72824434Skarels     	else
72924434Skarels     	    ddn_supr(unit, chan, cc, cnt);
73024434Skarels 
73124434Skarels       }
73224434Skarels 
73324434Skarels     /*
73424434Skarels      * Ack the interrupt
73524434Skarels      */
73624434Skarels     addr->staack = 1;
73724434Skarels     if (!(addr->ionmi))
73824434Skarels       {
73924434Skarels     	addr->ionmi = 1;
74024434Skarels     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
74124434Skarels       }
74224434Skarels   }
74324434Skarels 
74424434Skarels 
74524434Skarels /***********************************************************************\
74624434Skarels *				x25_init()				*
74724434Skarels *************************************************************************
74824434Skarels *									*
74924434Skarels *	This routine builds and sends an X.25 initialization msg	*
75024434Skarels *	to the UMC.							*
75124434Skarels *									*
75224434Skarels \***********************************************************************/
75324434Skarels 
75424434Skarels static void x25_init(ds)
75524434Skarels struct ddn_softc *ds;
75624434Skarels   {
75724434Skarels     struct mbuf *m;
75824434Skarels     register u_char *bp;
75924434Skarels 
76024434Skarels #ifdef DDNDEBUG
76124434Skarels if (ddn_debug > 0)
76224434Skarels   {
76324434Skarels printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
76424434Skarels   }
76524434Skarels #endif DDNDEBUG
76624434Skarels 
76724434Skarels     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get X25 init buffer */
76824434Skarels     if (m == 0)
76924434Skarels       {
77024434Skarels     	printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
77124434Skarels     	return;
77224434Skarels       }
77324434Skarels 
77424434Skarels     init_msg[3] = sizeof(init_msg) - 4;	/* set cmnd ext length */
77524434Skarels 
77624434Skarels     bcopy(init_msg, mtod(m, u_char *), sizeof(init_msg));
77724434Skarels 
77824434Skarels     m->m_len = sizeof(init_msg);	/* set msg length */
77924434Skarels 
78024434Skarels     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
78124434Skarels     ddn_start(ds, &(ds->ddn_cb[0]));
78224434Skarels   }
78324434Skarels 
78424434Skarels 
78524434Skarels /***********************************************************************\
78624434Skarels *			locate_x25_lcn()				*
78724434Skarels *************************************************************************
78824434Skarels *									*
78924434Skarels *	This routine tries to locate an X25 LCN associated with a	*
79024434Skarels *	remote internet address.  A linear search of the LCN table	*
79124434Skarels *	is made for a matching address.  If the search succeeds, the	*
79224434Skarels *	LCN is returned.  If the search fails, the LCN table is		*
79324434Skarels *	searched for an unused table entry.  If an unused table entry	*
79424434Skarels *	is found, an X25 call is generated to the host specified in	*
79524434Skarels *	the destination internet address.  If no LCN is available,	*
79624434Skarels *	zero is returned.						*
79724434Skarels *									*
79824434Skarels \***********************************************************************/
79924434Skarels 
80024434Skarels static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
80124434Skarels struct ddn_softc *ds;
80224434Skarels struct in_addr ip_addr;
80324434Skarels   {
80424434Skarels     register int lcn;
80524434Skarels     register struct ddn_cb *dc;
80624434Skarels     struct mbuf *m_callbfr;
80724434Skarels 
80824434Skarels #ifdef DDNDEBUG
80924434Skarels if (ddn_debug > 6)
81024434Skarels   {
81124434Skarels printf("locate_x25_lcn()\n");
81224434Skarels   }
81324434Skarels #endif DDNDEBUG
81424434Skarels 
81524434Skarels     dc = &(ds->ddn_cb[1]);
81624434Skarels     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for addr match */
81724434Skarels       {
81824434Skarels     	if (dc->dc_inaddr.s_addr == ip_addr.s_addr)	/* if found */
81924434Skarels     	    return(dc);		     			/*   return LCN */
82024434Skarels 	dc++;
82124434Skarels       }
82224434Skarels 
82324434Skarels     dc = &(ds->ddn_cb[1]);
82424434Skarels     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for free entry */
82524434Skarels       {
82624434Skarels     	if (dc->dc_state == LC_IDLE)
82724434Skarels     	    break;
82824434Skarels 	dc++;
82924434Skarels       }
83024434Skarels 
83124434Skarels     if (lcn > NDDNCH)			/* if we didn't find a free entry */
83224434Skarels         return(0);			/*   return empty handed */
83324434Skarels 
83424434Skarels 
83524434Skarels     if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
83624434Skarels       {					/*  addr can be converted */
83724434Skarels 	dc->dc_inaddr.s_addr = ip_addr.s_addr;
83824434Skarels     	return(dc);			/*   and return the LCN */
83924434Skarels       }
84024434Skarels     else
84124434Skarels       {
84224434Skarels 	return(0);				/* give up */
84324434Skarels       }
84424434Skarels   }
84524434Skarels 
84624434Skarels 
84724434Skarels /***********************************************************************\
84824434Skarels *			convert_ip_addr()				*
84924434Skarels *************************************************************************
85024434Skarels *									*
85124434Skarels *	This routine accepts an internet address and attempts to	*
85224434Skarels *	translate to an equivalent X25 address.  For DDN this follows	*
85324434Skarels *	the guidelines in the DDN X25 interface spec.  The resultant	*
85424434Skarels *	X25 address is stored in the X25 called addr buffer.  The	*
85524434Skarels *	routine returns TRUE if successfull, FALSE otherwise.		*
85624434Skarels *									*
85724434Skarels *	NOTE: Although IF-11/X25 was designed to accept ASCII coded	*
85824434Skarels *	digits for the address fields, we only supply the binary	*
85924434Skarels *	values.  The front-end only uses the low four bits to extract	*
86024434Skarels *	the binary value from the ASCII digits, so this works out.	*
86124434Skarels *									*
86224434Skarels \***********************************************************************/
86324434Skarels 
86424434Skarels static boolean convert_ip_addr(ip_addr, x25addr)
86524434Skarels struct in_addr ip_addr;
86624434Skarels u_char x25addr[];
86724434Skarels   {
86824434Skarels     register int temp;
869*24801Skarels     union {
870*24801Skarels 	struct in_addr ip;
871*24801Skarels 	struct {	 /*   (assumes Class A network number) */
872*24801Skarels 	    u_char s_net;
873*24801Skarels 	    u_char s_host;
874*24801Skarels 	    u_char s_lh;
875*24801Skarels 	    u_char s_impno;
876*24801Skarels 	} imp;
877*24801Skarels     } imp_addr;
87824434Skarels 
879*24801Skarels     imp_addr.ip = ip_addr;
88024434Skarels     x25addr[0] = 14;		/* set addr length */
88124434Skarels 
88224434Skarels     x25addr[1] = 0;		/* clear DNIC */
88324434Skarels     x25addr[2] = 0;
88424434Skarels     x25addr[3] = 0;
88524434Skarels     x25addr[4] = 0;
88624434Skarels 
887*24801Skarels     if (imp_addr.imp.s_host < 64)	/* Physical:  0000 0 IIIHH00 [SS] */
888*24801Skarels       {					/*   s_impno -> III, s_host -> HH */
88924434Skarels     	x25addr[5] = 0;		/* set flag bit */
890*24801Skarels     	x25addr[6] = imp_addr.imp.s_impno / 100;
891*24801Skarels     	x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
892*24801Skarels     	x25addr[8] = imp_addr.imp.s_impno % 10;
893*24801Skarels     	x25addr[9] = imp_addr.imp.s_host / 10;
894*24801Skarels     	x25addr[10] = imp_addr.imp.s_host % 10;
89524434Skarels       }
89624434Skarels     else			/* Logical:   0000 1 RRRRR00 [SS]	*/
89724434Skarels       {				/*   s_host * 256 + s_impno -> RRRRR	*/
898*24801Skarels     	temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
89924434Skarels     	x25addr[5] = 1;
90024434Skarels     	x25addr[6] = temp / 10000;
90124434Skarels     	x25addr[7] = (temp % 10000) / 1000;
90224434Skarels     	x25addr[8] = (temp % 1000) / 100;
90324434Skarels     	x25addr[9] = (temp % 100) / 10;
90424434Skarels     	x25addr[10] = temp % 10;
90524434Skarels       }
90624434Skarels 
90724434Skarels     x25addr[11] = 0;		/* clear rest of addr */
90824434Skarels     x25addr[12] = 0;
90924434Skarels     x25addr[13] = 0;
91024434Skarels     x25addr[14] = 0;
91124434Skarels 
91224434Skarels #ifdef DDNDEBUG
91324434Skarels if (ddn_debug > 4)
91424434Skarels   {
91524434Skarels printf("convert_ip_addr():  ");
91624434Skarels prt_addr(ip_addr);
91724434Skarels printf(" ==> ");
91824434Skarels prt_bytes(x25addr, 14);
91924434Skarels printf("\n");
92024434Skarels   }
92124434Skarels #endif DDNDEBUG
92224434Skarels 
92324434Skarels     return(1);
92424434Skarels   }
92524434Skarels 
92624434Skarels 
92724434Skarels /***********************************************************************\
92824434Skarels *			convert_x25_addr()				*
92924434Skarels *************************************************************************
93024434Skarels *									*
93124434Skarels *	This routine accepts an X25 address and attempts to translate	*
93224434Skarels *	to an equivalent internet address.  For DDN this follows the	*
93324434Skarels *	guidelines in the DDN X25 interface spec.  The resultant	*
93424434Skarels *	internet address is returned to the caller.			*
93524434Skarels *									*
93624434Skarels \***********************************************************************/
93724434Skarels 
93824434Skarels static int convert_x25_addr(x25addr)
93924434Skarels u_char x25addr[];
94024434Skarels   {
94124434Skarels     register int cnt, temp;
942*24801Skarels     union {
943*24801Skarels 	struct in_addr ip;
944*24801Skarels 	struct {	 /*   (assumes Class A network number) */
945*24801Skarels 	    u_char s_net;
946*24801Skarels 	    u_char s_host;
947*24801Skarels 	    u_char s_lh;
948*24801Skarels 	    u_char s_impno;
949*24801Skarels 	} imp;
950*24801Skarels     } imp_addr;
95124434Skarels 
95224434Skarels     if (((cnt = x25addr[0]) < 12) || (cnt > 14))
95324434Skarels       {
95424434Skarels     	printf("DDN: illegal X25 address length!\n");
95524434Skarels     	return(0);
95624434Skarels       }
95724434Skarels 
95824434Skarels     switch(x25addr[5] & 0x0f)
95924434Skarels       {
96024434Skarels     case 0:			/* Physical:  0000 0 IIIHH00 [SS]	*/
961*24801Skarels 	imp_addr.imp.s_impno =
96224434Skarels 		((int)(x25addr[6] & 0x0f) * 100) +
96324434Skarels 		((int)(x25addr[7] & 0x0f) * 10)  +
96424434Skarels 		((int)(x25addr[8] & 0x0f));
96524434Skarels 
96624434Skarels 
967*24801Skarels     	imp_addr.imp.s_host =
96824434Skarels     		((int)(x25addr[9] & 0x0f) * 10) +
96924434Skarels 		((int)(x25addr[10] & 0x0f));
97024434Skarels         break;
97124434Skarels     case 1:			/* Logical:   0000 1 RRRRR00 [SS]	*/
97224434Skarels     	temp =    ((int)(x25addr[6] & 0x0f) * 10000)
97324434Skarels 		+ ((int)(x25addr[7] & 0x0f) * 1000)
97424434Skarels 		+ ((int)(x25addr[8] & 0x0f) * 100)
97524434Skarels     		+ ((int)(x25addr[9] & 0x0f) * 10)
97624434Skarels 		+ ((int)(x25addr[10] & 0x0f));
97724434Skarels 
978*24801Skarels     	imp_addr.imp.s_host = temp >> 8;
979*24801Skarels     	imp_addr.imp.s_impno = temp & 0xff;
98024434Skarels     	break;
98124434Skarels     default:
98224434Skarels     	printf("DDN: illegal X25 address format!\n");
98324434Skarels     	return(0);
98424434Skarels       }
98524434Skarels 
986*24801Skarels     imp_addr.imp.s_lh = 0;
987*24801Skarels     imp_addr.imp.s_net = 0;
98824434Skarels 
98924434Skarels #ifdef DDNDEBUG
99024434Skarels if (ddn_debug > 4)
99124434Skarels   {
99224434Skarels printf("convert_x25_addr():  ");
99324434Skarels prt_bytes(&x25addr[1], cnt);
99424434Skarels printf(" ==> ");
995*24801Skarels prt_addr(imp_addr.ip);
99624434Skarels printf("\n");
99724434Skarels   }
99824434Skarels #endif DDNDEBUG
99924434Skarels 
1000*24801Skarels     return(imp_addr.ip.s_addr);
100124434Skarels   }
100224434Skarels 
100324434Skarels 
100424434Skarels /***********************************************************************\
100524434Skarels *			make_x25_call()					*
100624434Skarels *************************************************************************
100724434Skarels *									*
100824434Skarels *	This routine places an X25 call using the X25 Call Msg		*
100924434Skarels *	buffer.  The calling LCN is placed in the appropriate state	*
101024434Skarels *	and a timer is started.						*
101124434Skarels *									*
101224434Skarels \***********************************************************************/
101324434Skarels 
101424434Skarels static boolean make_x25_call(ds, dc)
101524434Skarels register struct ddn_softc *ds;
101624434Skarels register struct ddn_cb *dc;
101724434Skarels   {
101824434Skarels     register struct mbuf *m_callbfr;
101924434Skarels     register u_char *cb;
102024434Skarels 
102124434Skarels     MGET(m_callbfr, M_DONTWAIT, MT_DATA);  /* try to get call cmnd buffer */
102224434Skarels     if (m_callbfr == 0)
102324434Skarels 	return(0);
102424434Skarels 
102524434Skarels     cb = mtod(m_callbfr, u_char *);
102624434Skarels 
1027*24801Skarels     convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
102824434Skarels 
102924434Skarels     cb_protocol[0] = 4;
103024434Skarels     cb_protocol[1] = X25_PROTO_IP;	/* protocol = IP */
103124434Skarels     cb_protocol[2] = 0;
103224434Skarels     cb_protocol[3] = 0;
103324434Skarels     cb_protocol[4] = 0;
103424434Skarels 
103524434Skarels     cb_facilities[0] = 4;		/* number facility bytes */
103624434Skarels     cb_facilities[1] = 0;		/*  options marker */
103724434Skarels     cb_facilities[2] = 0;
103824434Skarels     cb_facilities[3] = X25_FACIL_DDN;	/*  DDN standard mode */
103924434Skarels     cb_facilities[4] = FAC_DDNSTD;
104024434Skarels 
104124434Skarels     cb_user_data[0] = 0;		/* no user data */
104224434Skarels 
104324434Skarels     cb_cmnd[0] = CALL;			/* set command code */
104424434Skarels     cb_cmnd[1] = dc->dc_lcn << 1;	/* set channel id */
104524434Skarels     cb_cmnd[2] = 0;
104624434Skarels     cb_cmnd[3] = (cb_called_addr[0] + 1) +	/* tally up cmnd ext length */
104724434Skarels 		 (cb_calling_addr[0] + 1) +
104824434Skarels 		 (cb_protocol[0] + 1) +
104924434Skarels 		 (cb_facilities[0] + 1) +
105024434Skarels 		 (cb_user_data[0] + 1);
105124434Skarels 
105224434Skarels     m_callbfr->m_len = cb_cmnd[3] + 4;
105324434Skarels 
105424434Skarels     /* copy command header */
105524434Skarels     bcopy(cb_cmnd, cb, 4);
105624434Skarels     cb += 4;
105724434Skarels 
105824434Skarels     /* copy called address */
105924434Skarels     bcopy(cb_called_addr, cb, cb_called_addr[0] + 1);
106024434Skarels     cb += (cb_called_addr[0] + 1);
106124434Skarels 
106224434Skarels     /* copy calling address */
106324434Skarels     bcopy(cb_calling_addr, cb, cb_calling_addr[0] + 1);
106424434Skarels     cb += (cb_calling_addr[0] + 1);
106524434Skarels 
106624434Skarels     /* copy protocol */
106724434Skarels     bcopy(cb_protocol, cb, cb_protocol[0] + 1);
106824434Skarels     cb += (cb_protocol[0] + 1);
106924434Skarels 
107024434Skarels     /* copy facilities */
107124434Skarels     bcopy(cb_facilities, cb, cb_facilities[0] + 1);
107224434Skarels     cb += (cb_facilities[0] + 1);
107324434Skarels 
107424434Skarels     /* copy user data */
107524434Skarels     bcopy(cb_user_data, cb, cb_user_data[0] + 1);
107624434Skarels     cb += (cb_user_data[0] + 1);
107724434Skarels 
107824434Skarels     dc->dc_state = LC_CALL_PENDING;		/* set state */
107924434Skarels     dc->dc_timer = TMO_CALL_PENDING;		/* start call timeout */
108024434Skarels 
108124434Skarels #ifdef DDNDEBUG
108224434Skarels if (ddn_debug > 3)
108324434Skarels   {
108424434Skarels printf("make_x25_call(): call_bfr = ");
108524434Skarels prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
108624434Skarels printf("\n");
108724434Skarels   }
108824434Skarels #endif DDNDEBUG
108924434Skarels 
109024434Skarels     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
109124434Skarels     ddn_start(ds, &(ds->ddn_cb[0]));
109224434Skarels 
109324434Skarels     return(1);
109424434Skarels   }
109524434Skarels 
109624434Skarels 
109724434Skarels /***********************************************************************\
109824434Skarels *				ddn_start()				*
109924434Skarels *************************************************************************
110024434Skarels *									*
110124434Skarels *	This routine attempts to start output of data queued on	a	*
110224434Skarels *	specific LCN.  If the LCN was not already busy and data is	*
110324434Skarels *	available for output, the data is copied into the LCN's I/O	*
110424434Skarels *	buffer and an I/O request queued to the UMC.			*
110524434Skarels *									*
110624434Skarels \***********************************************************************/
110724434Skarels 
110824434Skarels static void ddn_start(ds, dc)
110924434Skarels register struct ddn_softc *ds;
111024434Skarels register struct ddn_cb *dc;
111124434Skarels   {
111224434Skarels     register struct mbuf *m;
111324434Skarels     int len;
111424434Skarels 
111524434Skarels     /*
111624434Skarels      * If output isn't active, attempt to
111724434Skarels      * start sending a new packet.
111824434Skarels      */
111924434Skarels 
112024434Skarels     if ((dc->dc_flags & DC_OBUSY) ||
112124434Skarels     	(dc->dc_oq.ifq_len == 0) ||
112224434Skarels     	((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
112324434Skarels       {
112424434Skarels     	return;
112524434Skarels       }
112624434Skarels 
112724434Skarels     IF_DEQUEUE(&dc->dc_oq, m);
112824434Skarels 
112924434Skarels     len = if_wubaput(&dc->dc_ifuba, m);	/* copy data to mapped mem */
113024434Skarels     dc->dc_flags |= DC_OBUSY;
113124434Skarels 
113224434Skarels     ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
113324434Skarels   }
113424434Skarels 
113524434Skarels 
113624434Skarels /***********************************************************************\
113724434Skarels *				ddn_iorq()				*
113824434Skarels *************************************************************************
113924434Skarels *									*
114024434Skarels *	This routine builds UMC I/O requests and queues them for	*
114124434Skarels *	delivery to the UMC. If the UMC I/O request comm regs are	*
114224434Skarels *	not busy, the I/O request is passed to the UMC.			*
114324434Skarels *									*
114424434Skarels \***********************************************************************/
114524434Skarels 
114624434Skarels static void ddn_iorq(ds, dc, len, func)
114724434Skarels struct ddn_softc *ds;
114824434Skarels struct ddn_cb *dc;
114924434Skarels int len, func;
115024434Skarels   {
115124434Skarels     register struct hdx_chan *hc;
115224434Skarels     register int info;
115324434Skarels 
115424434Skarels 
115524434Skarels     /* get appropriate UNIBUS mapping info */
115624434Skarels 
115724434Skarels     if (func & DDNRDB)		/* read or write? */
115824434Skarels       {
115924434Skarels     	hc = &dc->dc_rchan;
116024434Skarels     	info = dc->dc_ifuba.ifu_r.ifrw_info;
116124434Skarels       }
116224434Skarels     else
116324434Skarels       {
116424434Skarels     	hc = &dc->dc_wchan;
116524434Skarels     	info = dc->dc_ifuba.ifu_w.ifrw_info;
116624434Skarels       }
116724434Skarels 
116824434Skarels     /* set channel info */
116924434Skarels 
117024434Skarels     hc->hc_adx = (u_char)((info & 0x30000) >> 12);
117124434Skarels     hc->hc_addr = (u_short)(info & 0xffff);
117224434Skarels     hc->hc_cnt = len;
117324434Skarels     hc->hc_func = (u_char)func;
117424434Skarels     hc->hc_sbfc = 0;
117524434Skarels 
117624434Skarels     /*
117724434Skarels      * If UMC comm regs busy, queue start i/o for later.
117824434Skarels      */
117924434Skarels     if (ds->ddn_sioq.sq_head)
118024434Skarels       {
118124434Skarels     	(ds->ddn_sioq.sq_tail)->hc_next = hc;
118224434Skarels     	ds->ddn_sioq.sq_tail = hc;
118324434Skarels     	hc->hc_next = 0;
118424434Skarels     	return;
118524434Skarels       }
118624434Skarels 
118724434Skarels     /* start i/o on channel now */
118824434Skarels 
118924434Skarels     ds->ddn_sioq.sq_head = hc;
119024434Skarels     ds->ddn_sioq.sq_tail = hc;
119124434Skarels     hc->hc_next = 0;
119224434Skarels     start_chn(ds);
119324434Skarels   }
119424434Skarels 
119524434Skarels 
119624434Skarels /***********************************************************************\
119724434Skarels *				start_chn()				*
119824434Skarels *************************************************************************
119924434Skarels *									*
120024434Skarels *	This routine copies UMC I/O requests into the UMC comm regs	*
120124434Skarels *	and notifies the UMC.						*
120224434Skarels *									*
120324434Skarels \***********************************************************************/
120424434Skarels 
120524434Skarels static void start_chn(ds)
120624434Skarels struct ddn_softc *ds;
120724434Skarels   {
120824434Skarels     register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
120924434Skarels     register struct ddnregs *addr =
121024434Skarels     	(struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
121124434Skarels 
121224434Skarels     /*
121324434Skarels      * Set up comm regs.
121424434Skarels      */
121524434Skarels     addr->iochn = hc->hc_chan;
121624434Skarels     addr->ioadx = hc->hc_adx;
121724434Skarels     addr->ioadl = hc->hc_addr;
121824434Skarels     addr->iocnt = hc->hc_cnt;
121924434Skarels     addr->iofcn = hc->hc_func;
122024434Skarels     addr->iosbf = hc->hc_sbfc;
122124434Skarels     addr->ioini = 1;
122224434Skarels 
122324434Skarels     /* signal UMC if necessary */
122424434Skarels 
122524434Skarels     if (!(addr->ionmi))
122624434Skarels       {
122724434Skarels     	addr->ionmi = 1;
122824434Skarels     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
122924434Skarels       }
123024434Skarels   }
123124434Skarels 
123224434Skarels 
123324434Skarels /***********************************************************************\
123424434Skarels *				ddn_data()				*
123524434Skarels *************************************************************************
123624434Skarels *									*
123724434Skarels *	This routine is called when a data channel I/O completes.	*
123824434Skarels *	If the completion was for a write, an attempt is made to	*
123924434Skarels *	start output on the next packet waiting for output on that	*
124024434Skarels *	LCN.  If the completion was for a read, the received packet	*
124124434Skarels *	is sent to the IP input queue (if no error) and another read	*
124224434Skarels *	is started on the LCN.						*
124324434Skarels *									*
124424434Skarels \***********************************************************************/
124524434Skarels 
124624434Skarels static void ddn_data(unit, chan, cc, rcnt)
124724434Skarels int unit, chan, cc, rcnt;
124824434Skarels {
124924434Skarels     register struct ddn_softc *ds = &ddn_softc[unit];
125024434Skarels     register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
125124434Skarels     register struct ifqueue *inq = &ipintrq;
125224434Skarels     register struct mbuf *m;
125324434Skarels 
125424434Skarels     if (chan & 0x01)			/* was it read or write? */
125524434Skarels       {					/*   write, fire up next output */
125624434Skarels     	ds->ddn_if.if_opackets++;
125724434Skarels     	dc->dc_flags &= ~DC_OBUSY;
125824434Skarels     	ddn_start(ds, dc);
125924434Skarels       }
126024434Skarels     else				/*   read, process rcvd packet */
126124434Skarels       {
126224434Skarels     	if (cc == DDNIOCOK)
126324434Skarels     	  {				/* Queue good packet for input */
126424434Skarels     	    ds->ddn_if.if_ipackets++;
126524434Skarels 	    dc->dc_state = LC_DATA_IDLE;
126624434Skarels 	    dc->dc_timer = TMO_DATA_IDLE;
1267*24801Skarels     	    m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
126824434Skarels     	    if (m)
126924434Skarels     	      {
127024434Skarels     		if (IF_QFULL(inq))
127124434Skarels     		  {
127224434Skarels     		    IF_DROP(inq);
127324434Skarels     		    m_freem(m);
127424434Skarels     		  }
127524434Skarels     		else
127624434Skarels     		  {
127724434Skarels     		    IF_ENQUEUE(inq, m);
127824434Skarels     		    schednetisr(NETISR_IP);
127924434Skarels     		  }
128024434Skarels     	      }
128124434Skarels     	  }
128224434Skarels 
128324434Skarels     	/* hang a new data read */
128424434Skarels 
128524434Skarels     	ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
128624434Skarels 
128724434Skarels       }
128824434Skarels   }
128924434Skarels 
129024434Skarels 
129124434Skarels /***********************************************************************\
129224434Skarels *				ddn_supr()				*
129324434Skarels *************************************************************************
129424434Skarels *									*
129524434Skarels *	This routine is called when a supervisor I/O completes.		*
129624434Skarels *	If the completion was for a write, an attempt is made to	*
129724434Skarels *	start output on the next supervisor command waiting for		*
129824434Skarels *	output.  If the completion was for a read, the received		*
129924434Skarels *	supervisor message is processed and another read is started.	*
130024434Skarels *									*
130124434Skarels \***********************************************************************/
130224434Skarels 
130324434Skarels static void ddn_supr(unit, chan, cc, rcnt)
130424434Skarels int unit, chan, cc, rcnt;
130524434Skarels {
130624434Skarels     register struct ddn_softc *ds = &ddn_softc[unit];
130724434Skarels     u_char *p;
130824434Skarels 
130924434Skarels     /* was it read or write? */
131024434Skarels 
131124434Skarels     if (chan & 0x01)
131224434Skarels       {
131324434Skarels     	ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
131424434Skarels     	ddn_start(ds, &(ds->ddn_cb[0]));
131524434Skarels       }
131624434Skarels     else
131724434Skarels       {
131824434Skarels     	if (cc == DDNIOCOK)
131924434Skarels     	  {
132024434Skarels     	    p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
132124434Skarels 
132224434Skarels     	    /* process supervisor message */
132324434Skarels 
132424434Skarels     	    supr_msg(ds, p);
132524434Skarels 
132624434Skarels     	  }
132724434Skarels 
132824434Skarels     	/* hang a new supr read */
132924434Skarels 
133024434Skarels     	ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
133124434Skarels       }
133224434Skarels   }
133324434Skarels 
133424434Skarels 
133524434Skarels /***********************************************************************\
133624434Skarels *				supr_msg()				*
133724434Skarels *************************************************************************
133824434Skarels *									*
133924434Skarels *	This routine processes received supervisor messages.		*
134024434Skarels *	Depending on the message type, the appropriate action is	*
134124434Skarels *	taken.
134224434Skarels *									*
134324434Skarels \***********************************************************************/
134424434Skarels 
134524434Skarels static void supr_msg(ds, p)
134624434Skarels struct ddn_softc *ds;
134724434Skarels u_char p[];
134824434Skarels   {
134924434Skarels     register struct ddn_cb *dc;
135024434Skarels     register int lcn;
135124434Skarels     register struct mbuf *m;
135224434Skarels 
135324434Skarels #ifdef DDNDEBUG
135424434Skarels if (ddn_debug > 5)
135524434Skarels   {
135624434Skarels printf("supr_msg():  ");
135724434Skarels prt_bytes(p, 4+p[3]);
135824434Skarels printf("\n");
135924434Skarels   }
136024434Skarels #endif DDNDEBUG
136124434Skarels 
136224434Skarels     switch (p[0])
136324434Skarels       {
136424434Skarels     case LINE_STATUS:			/*   link status msg */
136524434Skarels 	if (p[2] == LINK_UP)		/*   if link came up */
136624434Skarels 	  {
136724434Skarels     	    send_restart(ds);		/*     send restart msg */
136824434Skarels 	  }
136924434Skarels 	else				/*   if link went down */
137024434Skarels 	  {
137124434Skarels     	    ds->ddn_if.if_flags &= ~IFF_UP;
137224434Skarels     	    dc = ds->ddn_cb;
137324434Skarels     	    for(lcn = 0; lcn <= NDDNCH; lcn++) /*    for all LCN's */
137424434Skarels     	      {
137524434Skarels     		dc->dc_state = LC_DOWN;  /* set state */
137624434Skarels     		dc->dc_timer = TMO_OFF;  /* stop timer */
137724434Skarels 		dc++;
137824434Skarels     	      }
137924434Skarels 	  }
138024434Skarels     	break;
138124434Skarels 
138224434Skarels     case RESTART:			/* restart received */
138324434Skarels     	if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
138424434Skarels     	    send_supr(ds, RSTRT_ACK, 0, 0);    /*   send restart ack */
138524434Skarels 	/* fall thru */
138624434Skarels     case RSTRT_ACK:			/* restart ack */
138724434Skarels     	ds->ddn_if.if_flags |= IFF_UP;
138824434Skarels     	dc = ds->ddn_cb;
138924434Skarels     	for(lcn = 0; lcn <= NDDNCH; lcn++)	/* for all LCN's */
139024434Skarels     	  {
139124434Skarels     	    dc->dc_state = LC_IDLE;   /* set state */
139224434Skarels     	    dc->dc_timer = TMO_OFF;   /* stop timer */
139324434Skarels     	    dc->dc_inaddr.s_addr = 0; /* forget address */
139424434Skarels     	    while (dc->dc_oq.ifq_len) /* drop pending data */
139524434Skarels     	      {
139624434Skarels     		IF_DEQUEUE(&dc->dc_oq, m);
139724434Skarels     		m_freem(m);
139824434Skarels     	      }
139924434Skarels 	    dc++;
140024434Skarels     	  }
140124434Skarels     	break;
140224434Skarels 
140324434Skarels     case ANSWER:			/* call answered */
140424434Skarels     	lcn = p[1] / 2;
140524434Skarels     	dc = &(ds->ddn_cb[lcn]);
140624434Skarels     	if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
140724434Skarels     	  {
140824434Skarels     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
140924434Skarels     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
141024434Skarels     	    ddn_start(ds, dc);		  /* try to send data */
141124434Skarels     	  }
141224434Skarels     	break;
141324434Skarels 
141424434Skarels     case RING:				/* incoming call */
141524434Skarels     	for(lcn = NDDNCH; lcn > 0; lcn--)	/* search LCN's */
141624434Skarels     	  {
141724434Skarels     	    if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
141824434Skarels     	    	break;
141924434Skarels     	  }
142024434Skarels 
142124434Skarels     	if (lcn && decode_ring(p))	/* if a free LCN found */
142224434Skarels 					/*   and ring looks ok */
142324434Skarels     	  {
142424434Skarels     	    dc = &(ds->ddn_cb[lcn]);
142524434Skarels     	    dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
142624434Skarels     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
142724434Skarels     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
142824434Skarels     	    send_supr(ds, ANSWER, lcn * 2, p[2]); /* send answer */
142924434Skarels     	  }
143024434Skarels     	else				/* if no free LCN's */
143124434Skarels     	  {
143224434Skarels     	    send_supr(ds, CLEARVC, p[2], 0); /* clear call */
143324434Skarels     	  }
143424434Skarels     	break;
143524434Skarels 
143624434Skarels     case CLEARLC:			/* clear by LCN */
143724434Skarels     	lcn = p[1] / 2;			/* get LCN */
143824434Skarels     	dc = &(ds->ddn_cb[lcn]);
143924434Skarels     	if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
144024434Skarels     	  {
144124434Skarels     	    send_supr(ds, CLEARLC, p[1], 0);      /*   ack the clear */
144224434Skarels     	  }
144324434Skarels     	dc->dc_state = LC_IDLE; /* set state */
144424434Skarels     	dc->dc_timer = TMO_OFF; /* stop timer */
144524434Skarels     	dc->dc_inaddr.s_addr = 0; /* forget address */
144624434Skarels     	while (dc->dc_oq.ifq_len) /* drop pending data */
144724434Skarels     	  {
144824434Skarels     	    IF_DEQUEUE(&dc->dc_oq, m);
144924434Skarels     	    m_freem(m);
145024434Skarels     	  }
145124434Skarels     	break;
145224434Skarels 
145324434Skarels     case CLEARVC:			/* clear by VCN */
145424434Skarels     	send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */
145524434Skarels     	break;
145624434Skarels 
145724434Skarels     case RESET:				/* X25 reset */
145824434Skarels 	send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */
145924434Skarels     	printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
146024434Skarels 	break;
146124434Skarels 
146224434Skarels     case INTERRUPT:			/* X25 interrupt */
146324434Skarels     	printf("X25 INTERRUPT on lcn = %d, code = %d\n",	/* log it */
146424434Skarels     	    p[1] / 2, p[2]);
146524434Skarels 	break;
146624434Skarels 
146724434Skarels     default:
146824434Skarels     	printf("ddn%d: supervisor error, code=%x\n",
146924434Skarels 	   ds->ddn_if.if_unit, p[0]);
147024434Skarels       }
147124434Skarels   }
147224434Skarels 
147324434Skarels 
147424434Skarels /***********************************************************************\
147524434Skarels *				decode_ring()				*
147624434Skarels *************************************************************************
147724434Skarels *									*
147824434Skarels *	This routine parses and validates the incoming call msg.	*
147924434Skarels *									*
148024434Skarels \***********************************************************************/
148124434Skarels 
148224434Skarels static boolean decode_ring(p)
148324434Skarels register u_char *p;
148424434Skarels   {
148524434Skarels     register int cnt;
148624434Skarels 
148724434Skarels #ifdef DDNDEBUG
148824434Skarels if (ddn_debug > 3)
148924434Skarels   {
149024434Skarels printf("decode_ring()\n");
149124434Skarels   }
149224434Skarels #endif DDNDEBUG
149324434Skarels 
149424434Skarels 
149524434Skarels     p += 3;			/* skip to cmnd ext length */
149624434Skarels     if (*p++ < 5)		/* is count appropriate */
149724434Skarels 	return(0);		/*   return false if not */
149824434Skarels 
149924434Skarels     /* called address */
150024434Skarels     if ((cnt = *p + 1) > 16)	/* is called addr len legal? */
150124434Skarels 	return(0);		/*   return false if not */
150224434Skarels     bcopy(p, cb_called_addr, cnt); /* copy field */
150324434Skarels     p += cnt;
150424434Skarels 
150524434Skarels     /* calling address */
150624434Skarels     if ((cnt = *p + 1) > 16)	/* is calling addr len legal? */
150724434Skarels 	return(0);		/*   return false if not */
150824434Skarels     bcopy(p, cb_calling_addr, cnt); /* copy field */
150924434Skarels     p += cnt;
151024434Skarels 
151124434Skarels     /* protocol part of user data */
151224434Skarels     if ((cnt = *p + 1) > 5)	/* is protocol len legal? */
151324434Skarels 	return(0);		/*   return false if not */
151424434Skarels     bcopy(p, cb_protocol, cnt); /* copy field */
151524434Skarels     p += cnt;
151624434Skarels 
151724434Skarels     /* facilities */
151824434Skarels     if ((cnt = *p + 1) > 64)	/* is facilities len legal? */
151924434Skarels 	return(0);		/*   return false if not */
152024434Skarels     bcopy(p, cb_facilities, cnt); /* copy field */
152124434Skarels     p += cnt;
152224434Skarels 
152324434Skarels     /* ignore rest of user data for now */
152424434Skarels 
152524434Skarels     if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
152624434Skarels 	return(0);		/* bad if not IP */
152724434Skarels 
152824434Skarels     return(1);			/* looks ok */
152924434Skarels   }
153024434Skarels 
153124434Skarels 
153224434Skarels /***********************************************************************\
153324434Skarels *				clear_lcn()				*
153424434Skarels *************************************************************************
153524434Skarels *									*
153624434Skarels *	This routine clears an X25 circuit and releases any buffers	*
153724434Skarels *	queued for transmission.					*
153824434Skarels *									*
153924434Skarels \***********************************************************************/
154024434Skarels 
154124434Skarels static void clear_lcn(ds, dc)
154224434Skarels struct ddn_softc *ds;
154324434Skarels struct ddn_cb *dc;
154424434Skarels   {
154524434Skarels     register struct mbuf *m;
154624434Skarels 
154724434Skarels #ifdef DDNDEBUG
154824434Skarels if (ddn_debug > 3)
154924434Skarels   {
155024434Skarels printf("clear_lcn(%d)\n", dc->dc_lcn);
155124434Skarels   }
155224434Skarels #endif DDNDEBUG
155324434Skarels 
155424434Skarels     dc->dc_state = LC_CLR_PENDING;  /* set state */
155524434Skarels     dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
155624434Skarels     dc->dc_inaddr.s_addr = 0;	    /* clear associated address */
155724434Skarels     while (dc->dc_oq.ifq_len)	    /* drop any pending data */
155824434Skarels       {
155924434Skarels     	IF_DEQUEUE(&dc->dc_oq, m);
156024434Skarels     	m_freem(m);
156124434Skarels       }
156224434Skarels     send_supr(ds, CLEARLC, dc->dc_lcn * 2, 0);    /* send clear msg */
156324434Skarels   }
156424434Skarels 
156524434Skarels 
156624434Skarels /***********************************************************************\
156724434Skarels *				send_restart()				*
156824434Skarels *************************************************************************
156924434Skarels *									*
157024434Skarels *	This routine marks all LCNs as being in a restarting state	*
157124434Skarels *	and sends a restart command to X25.				*
157224434Skarels *									*
157324434Skarels \***********************************************************************/
157424434Skarels 
157524434Skarels static void send_restart(ds)
157624434Skarels struct ddn_softc *ds;
157724434Skarels   {
157824434Skarels     register struct ddn_cb *dc;
157924434Skarels     register int lcn;
158024434Skarels     struct mbuf *m;
158124434Skarels 
158224434Skarels #ifdef DDNDEBUG
158324434Skarels if (ddn_debug > 1)
158424434Skarels   {
158524434Skarels printf("send_restart()\n");
158624434Skarels   }
158724434Skarels #endif DDNDEBUG
158824434Skarels     dc = ds->ddn_cb;
158924434Skarels     for(lcn = 0; lcn <= NDDNCH; lcn++)	    /* for all LCN's */
159024434Skarels       {
159124434Skarels     	dc->dc_state = LC_RESTART;  /* set state */
159224434Skarels     	dc->dc_timer = TMO_RESTART; /* start restart timeout */
159324434Skarels     	dc->dc_inaddr.s_addr = 0;     /* forget address */
159424434Skarels     	while (dc->dc_oq.ifq_len)	/* drop any pending data */
159524434Skarels     	  {
159624434Skarels     	    IF_DEQUEUE(&dc->dc_oq, m);
159724434Skarels     	    m_freem(m);
159824434Skarels     	  }
159924434Skarels 	dc++;
160024434Skarels       }
160124434Skarels 
160224434Skarels     send_supr(ds, RESTART, 0, 0);	    /* send restart msg */
160324434Skarels   }
160424434Skarels 
160524434Skarels 
160624434Skarels /***********************************************************************\
160724434Skarels *				send_supr()				*
160824434Skarels *************************************************************************
160924434Skarels *									*
161024434Skarels *	This routine is used to send short (4 bytes only) supervisor	*
161124434Skarels *	commands.							*
161224434Skarels *									*
161324434Skarels \***********************************************************************/
161424434Skarels 
161524434Skarels static void send_supr(ds, cmd, p1, p2)
161624434Skarels struct ddn_softc *ds;
161724434Skarels int cmd, p1, p2;
161824434Skarels   {
161924434Skarels     struct mbuf *m;
162024434Skarels     register u_char *cp;
162124434Skarels 
162224434Skarels #ifdef DDNDEBUG
162324434Skarels if (ddn_debug > 6)
162424434Skarels   {
162524434Skarels printf("send_supr():  %x %x %x\n", cmd, p1, p2);
162624434Skarels   }
162724434Skarels #endif DDNDEBUG
162824434Skarels 
162924434Skarels     MGET(m, M_DONTWAIT, MT_DATA);
163024434Skarels 
163124434Skarels     if (m == 0)
163224434Skarels       {
163324434Skarels     	printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
163424434Skarels     	return;
163524434Skarels       }
163624434Skarels 
163724434Skarels     cp = mtod(m, u_char *);
163824434Skarels 
163924434Skarels     /* build supervisor message */
164024434Skarels 
164124434Skarels     *cp++ = (byte)cmd;
164224434Skarels     *cp++ = (byte)p1;
164324434Skarels     *cp++ = (byte)p2;
164424434Skarels     *cp++ = 0;
164524434Skarels 
164624434Skarels     m->m_len = 4;
164724434Skarels 
164824434Skarels     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
164924434Skarels     ddn_start(ds, &(ds->ddn_cb[0]));
165024434Skarels 
165124434Skarels   }
165224434Skarels 
165324434Skarels 
165424434Skarels #ifdef DDNDEBUG
165524434Skarels 
165624434Skarels /***********************************************************************\
165724434Skarels *				prt_addr()				*
165824434Skarels *************************************************************************
165924434Skarels *									*
166024434Skarels *	This routine is used to print internet addresses in the		*
166124434Skarels *	standard A.B.C.D format.					*
166224434Skarels *									*
166324434Skarels \***********************************************************************/
166424434Skarels 
166524434Skarels static void prt_addr(addr)
166624434Skarels struct in_addr addr;
166724434Skarels   {
166824434Skarels     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
166924434Skarels   }
167024434Skarels 
167124434Skarels /***********************************************************************\
167224434Skarels *				prt_bytes()				*
167324434Skarels *************************************************************************
167424434Skarels *									*
167524434Skarels *	This routine is used to print a string of bytes in hex.		*
167624434Skarels *									*
167724434Skarels \***********************************************************************/
167824434Skarels 
167924434Skarels static void prt_bytes(bp, cnt)
168024434Skarels u_char *bp;
168124434Skarels int cnt;
168224434Skarels   {
168324434Skarels     while(cnt--)
168424434Skarels       {
168524434Skarels 	printf(" %x", *bp++ & 0xff);
168624434Skarels       }
168724434Skarels   }
168824434Skarels 
168924434Skarels #endif DDNDEBUG
169024434Skarels 
169124434Skarels #endif NDDN
1692