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