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