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