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