1*7024Ssam /* if_vv.c 4.1 82/06/04 */ 2*7024Ssam 3*7024Ssam /* 4*7024Ssam * Proteon 10 Meg Ring Driver. 5*7024Ssam * This device is called "vv" because its "real name", 6*7024Ssam * V2LNI won't work if shortened to the obvious "v2". 7*7024Ssam * Hence the subterfuge. 8*7024Ssam */ 9*7024Ssam #include "../h/param.h" 10*7024Ssam #include "../h/systm.h" 11*7024Ssam #include "../h/mbuf.h" 12*7024Ssam #include "../h/pte.h" 13*7024Ssam #include "../h/buf.h" 14*7024Ssam #include "../h/protosw.h" 15*7024Ssam #include "../h/socket.h" 16*7024Ssam #include "../h/ubareg.h" 17*7024Ssam #include "../h/ubavar.h" 18*7024Ssam #include "../h/cpu.h" 19*7024Ssam #include "../h/mtpr.h" 20*7024Ssam #include "../h/vmmac.h" 21*7024Ssam #include "../net/in.h" 22*7024Ssam #include "../net/in_systm.h" 23*7024Ssam #include "../net/if.h" 24*7024Ssam #include "../net/if_vv.h" 25*7024Ssam #include "../net/if_uba.h" 26*7024Ssam #include "../net/ip.h" 27*7024Ssam #include "../net/ip_var.h" 28*7024Ssam #include "../net/route.h" 29*7024Ssam 30*7024Ssam #include "vv.h" 31*7024Ssam #include "imp.h" 32*7024Ssam 33*7024Ssam /* 34*7024Ssam * N.B. - if WIRECENTER is defined wrong, it can well break 35*7024Ssam * the hardware!! 36*7024Ssam */ 37*7024Ssam #undef AUTOIDENTIFY 38*7024Ssam #define WIRECENTER 39*7024Ssam 40*7024Ssam #ifdef WIRECENTER 41*7024Ssam #define VV_CONF VV_HEN /* drive wire center relay */ 42*7024Ssam #else 43*7024Ssam #define VV_CONF VV_STE /* allow operation without wire center */ 44*7024Ssam #endif 45*7024Ssam 46*7024Ssam #define VVMTU (1024+512) 47*7024Ssam 48*7024Ssam int vvprobe(), vvattach(), vvrint(), vvxint(); 49*7024Ssam struct uba_device *vvinfo[NVV]; 50*7024Ssam u_short vvstd[] = { 0 }; 51*7024Ssam struct uba_driver vvdriver = 52*7024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 53*7024Ssam #define VVUNIT(x) minor(x) 54*7024Ssam int vvinit(),vvoutput(),vvreset(); 55*7024Ssam 56*7024Ssam /* 57*7024Ssam * Software status of each interface. 58*7024Ssam * 59*7024Ssam * Each interface is referenced by a network interface structure, 60*7024Ssam * vs_if, which the routing code uses to locate the interface. 61*7024Ssam * This structure contains the output queue for the interface, its address, ... 62*7024Ssam * We also have, for each interface, a UBA interface structure, which 63*7024Ssam * contains information about the UNIBUS resources held by the interface: 64*7024Ssam * map registers, buffered data paths, etc. Information is cached in this 65*7024Ssam * structure for use by the if_uba.c routines in running the interface 66*7024Ssam * efficiently. 67*7024Ssam */ 68*7024Ssam struct vv_softc { 69*7024Ssam struct ifnet vs_if; /* network-visible interface */ 70*7024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 71*7024Ssam short vs_oactive; /* is output active? */ 72*7024Ssam short vs_olen; /* length of last output */ 73*7024Ssam u_short vs_lastx; /* last destination address */ 74*7024Ssam short vs_tries; /* current retry count */ 75*7024Ssam short vs_init; /* number of ring inits */ 76*7024Ssam short vs_flush; /* number of flushed packets */ 77*7024Ssam short vs_nottaken; /* number of packets refused */ 78*7024Ssam } vv_softc[NVV]; 79*7024Ssam 80*7024Ssam vvprobe(reg) 81*7024Ssam caddr_t reg; 82*7024Ssam { 83*7024Ssam register int br, cvec; 84*7024Ssam register struct vvreg *addr = (struct vvreg *)reg; 85*7024Ssam 86*7024Ssam #ifdef lint 87*7024Ssam br = 0; cvec = br; br = cvec; 88*7024Ssam #endif 89*7024Ssam /* reset interface, enable, and wait till dust settles */ 90*7024Ssam addr->vvicsr = VV_RST; 91*7024Ssam addr->vvocsr = VV_RST; 92*7024Ssam DELAY(100000); 93*7024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 94*7024Ssam addr->vvocsr = VV_IEN; /* enable interrupt */ 95*7024Ssam addr->vvoba = 0; /* low 16 bits */ 96*7024Ssam addr->vvoea = 0; /* extended bits */ 97*7024Ssam addr->vvowc = -1; /* for 1 word */ 98*7024Ssam addr->vvocsr |= VV_DEN; /* start the DMA */ 99*7024Ssam DELAY(100000); 100*7024Ssam addr->vvocsr = 0; 101*7024Ssam if (cvec && cvec != 0x200) 102*7024Ssam cvec -= 4; /* backup so vector => recieve */ 103*7024Ssam return(1); 104*7024Ssam } 105*7024Ssam 106*7024Ssam /* 107*7024Ssam * Interface exists: make available by filling in network interface 108*7024Ssam * record. System will initialize the interface when it is ready 109*7024Ssam * to accept packets. 110*7024Ssam */ 111*7024Ssam vvattach(ui) 112*7024Ssam struct uba_device *ui; 113*7024Ssam { 114*7024Ssam register struct vv_softc *vs = &vv_softc[ui->ui_unit]; 115*7024Ssam register struct sockaddr_in *sin; 116*7024Ssam COUNT(VVATTACH); 117*7024Ssam 118*7024Ssam vs->vs_if.if_unit = ui->ui_unit; 119*7024Ssam vs->vs_if.if_name = "vv"; 120*7024Ssam vs->vs_if.if_mtu = VVMTU; 121*7024Ssam vs->vs_if.if_net = ui->ui_flags; 122*7024Ssam vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ 123*7024Ssam 124*7024Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 125*7024Ssam sin->sin_family = AF_INET; 126*7024Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 127*7024Ssam 128*7024Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; 129*7024Ssam sin->sin_family = AF_INET; 130*7024Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); 131*7024Ssam vs->vs_if.if_flags = IFF_BROADCAST; 132*7024Ssam 133*7024Ssam vs->vs_if.if_init = vvinit; 134*7024Ssam vs->vs_if.if_output = vvoutput; 135*7024Ssam vs->vs_if.if_ubareset = vvreset; 136*7024Ssam vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16; 137*7024Ssam if_attach(&vs->vs_if); 138*7024Ssam #if NIMP == 0 139*7024Ssam if (ui->ui_flags & ~0xff) 140*7024Ssam vvlhinit((ui->ui_flags &~ 0xff) | 0x0a); 141*7024Ssam #endif 142*7024Ssam } 143*7024Ssam 144*7024Ssam /* 145*7024Ssam * Reset of interface after UNIBUS reset. 146*7024Ssam * If interface is on specified uba, reset its state. 147*7024Ssam */ 148*7024Ssam vvreset(unit, uban) 149*7024Ssam int unit, uban; 150*7024Ssam { 151*7024Ssam register struct uba_device *ui; 152*7024Ssam COUNT(VVRESET); 153*7024Ssam 154*7024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 155*7024Ssam ui->ui_ubanum != uban) 156*7024Ssam return; 157*7024Ssam printf(" vv%d", unit); 158*7024Ssam vvinit(unit); 159*7024Ssam } 160*7024Ssam 161*7024Ssam /* 162*7024Ssam * Initialization of interface; clear recorded pending 163*7024Ssam * operations, and reinitialize UNIBUS usage. 164*7024Ssam */ 165*7024Ssam vvinit(unit) 166*7024Ssam int unit; 167*7024Ssam { 168*7024Ssam register struct vv_softc *vs = &vv_softc[unit]; 169*7024Ssam register struct uba_device *ui = vvinfo[unit]; 170*7024Ssam register struct vvreg *addr; 171*7024Ssam struct sockaddr_in *sin; 172*7024Ssam struct mbuf *m; 173*7024Ssam struct vv_header *v; 174*7024Ssam int ubainfo, retrying, attempts, waitcount, s; 175*7024Ssam 176*7024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 177*7024Ssam sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 178*7024Ssam printf("vv%d: can't initialize\n", unit); 179*7024Ssam return; 180*7024Ssam } 181*7024Ssam addr = (struct vvreg *)ui->ui_addr; 182*7024Ssam 183*7024Ssam #ifdef AUTOIDENTIFY 184*7024Ssam /* 185*7024Ssam * Build a multicast message to identify our address 186*7024Ssam */ 187*7024Ssam attempts = 0; /* total attempts, including bad msg type */ 188*7024Ssam top: 189*7024Ssam retrying = 0; /* first time through */ 190*7024Ssam m = m_get(M_DONTWAIT); 191*7024Ssam if (m == 0) 192*7024Ssam panic("vvinit: can't get mbuf"); 193*7024Ssam m->m_next = 0; 194*7024Ssam m->m_off = MMINOFF; 195*7024Ssam m->m_len = sizeof(struct vv_header); 196*7024Ssam 197*7024Ssam v = mtod(m, struct vv_header *); 198*7024Ssam v->vh_dhost = 0; /* multicast destination address */ 199*7024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 200*7024Ssam v->vh_version = RING_VERSION; 201*7024Ssam v->vh_type = RING_WHOAMI; 202*7024Ssam v->vh_info = 0; 203*7024Ssam 204*7024Ssam /* 205*7024Ssam * Reset interface, establish Digital Loopback Mode, and 206*7024Ssam * send the multicast (to myself) with Input Copy enabled. 207*7024Ssam */ 208*7024Ssam retry: 209*7024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 210*7024Ssam addr->vvicsr = VV_RST; 211*7024Ssam addr->vviba = (u_short) ubainfo; 212*7024Ssam addr->vviea = (u_short) (ubainfo >> 16); 213*7024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 214*7024Ssam addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 215*7024Ssam /* map xmit message into uba if not already there */ 216*7024Ssam if (!retrying) 217*7024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 218*7024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 219*7024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 220*7024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 221*7024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 222*7024Ssam addr->vvoba = (u_short) ubainfo; 223*7024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 224*7024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 225*7024Ssam addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 226*7024Ssam 227*7024Ssam /* 228*7024Ssam * Wait for receive side to finish. 229*7024Ssam * Extract source address (which will our own), 230*7024Ssam * and post to interface structure. 231*7024Ssam */ 232*7024Ssam DELAY(1000); 233*7024Ssam for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) { 234*7024Ssam if (waitcount < 10) 235*7024Ssam DELAY(1000); 236*7024Ssam else { 237*7024Ssam if (attempts++ < 10)s 238*7024Ssam goto retry; 239*7024Ssam else { 240*7024Ssam printf("vv%d: can't initialize\n", unit); 241*7024Ssam printf("vvinit loopwait: icsr = %b\n", 242*7024Ssam 0xffff&(addr->vvicsr),VV_IBITS); 243*7024Ssam return; 244*7024Ssam } 245*7024Ssam } 246*7024Ssam } 247*7024Ssam 248*7024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 249*7024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 250*7024Ssam if (vs->vs_ifuba.ifu_xtofree) 251*7024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 252*7024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 253*7024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 254*7024Ssam m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 255*7024Ssam if (m) 256*7024Ssam m_freem(m); 257*7024Ssam /* 258*7024Ssam * check message type before we believe the source host address 259*7024Ssam */ 260*7024Ssam v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 261*7024Ssam if (v->vh_type == RING_WHOAMI) 262*7024Ssam vs->vs_if.if_host[0] = v->vh_shost; 263*7024Ssam else 264*7024Ssam goto top; 265*7024Ssam #else 266*7024Ssam vs->vs_if.if_host[0] = 24; 267*7024Ssam #endif 268*7024Ssam 269*7024Ssam printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 270*7024Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 271*7024Ssam sin->sin_family = AF_INET; 272*7024Ssam sin->sin_addr = 273*7024Ssam if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 274*7024Ssam 275*7024Ssam /* 276*7024Ssam * Reset the interface, and join the ring 277*7024Ssam */ 278*7024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 279*7024Ssam addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 280*7024Ssam sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */ 281*7024Ssam vs->vs_init = 0; 282*7024Ssam vs->vs_flush = 0; 283*7024Ssam vs->vs_nottaken = 0; 284*7024Ssam 285*7024Ssam /* 286*7024Ssam * Hang a receive and start any 287*7024Ssam * pending writes by faking a transmit complete. 288*7024Ssam */ 289*7024Ssam s = splimp(); 290*7024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 291*7024Ssam addr->vviba = (u_short) ubainfo; 292*7024Ssam addr->vviea = (u_short) (ubainfo >> 16); 293*7024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 294*7024Ssam addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 295*7024Ssam vs->vs_oactive = 1; 296*7024Ssam vvxint(unit); 297*7024Ssam splx(s); 298*7024Ssam if_rtinit(&vs->vs_if, RTF_DIRECT|RTF_UP); 299*7024Ssam } 300*7024Ssam 301*7024Ssam /* 302*7024Ssam * Start or restart output on interface. 303*7024Ssam * If interface is not already active, get another datagram 304*7024Ssam * to send off of the interface queue, and map it to the interface 305*7024Ssam * before starting the output. 306*7024Ssam */ 307*7024Ssam vvstart(dev) 308*7024Ssam dev_t dev; 309*7024Ssam { 310*7024Ssam int unit = VVUNIT(dev); 311*7024Ssam struct uba_device *ui = vvinfo[unit]; 312*7024Ssam register struct vv_softc *vs = &vv_softc[unit]; 313*7024Ssam register struct vvreg *addr; 314*7024Ssam struct mbuf *m; 315*7024Ssam int ubainfo; 316*7024Ssam int dest; 317*7024Ssam COUNT(VVSTART); 318*7024Ssam 319*7024Ssam if (vs->vs_oactive) 320*7024Ssam goto restart; 321*7024Ssam 322*7024Ssam /* 323*7024Ssam * Not already active: dequeue another request 324*7024Ssam * and map it to the UNIBUS. If no more requests, 325*7024Ssam * just return. 326*7024Ssam */ 327*7024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 328*7024Ssam if (m == 0) { 329*7024Ssam vs->vs_oactive = 0; 330*7024Ssam return; 331*7024Ssam } 332*7024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 333*7024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 334*7024Ssam vs->vs_lastx = dest; 335*7024Ssam 336*7024Ssam restart: 337*7024Ssam /* 338*7024Ssam * Have request mapped to UNIBUS for transmission. 339*7024Ssam * Purge any stale data from this BDP, and start the otput. 340*7024Ssam */ 341*7024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 342*7024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 343*7024Ssam addr = (struct vvreg *)ui->ui_addr; 344*7024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 345*7024Ssam addr->vvoba = (u_short) ubainfo; 346*7024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 347*7024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 348*7024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 349*7024Ssam vs->vs_oactive = 1; 350*7024Ssam } 351*7024Ssam 352*7024Ssam /* 353*7024Ssam * VVLNI transmit interrupt 354*7024Ssam * Start another output if more data to send. 355*7024Ssam */ 356*7024Ssam vvxint(unit) 357*7024Ssam int unit; 358*7024Ssam { 359*7024Ssam register struct uba_device *ui = vvinfo[unit]; 360*7024Ssam register struct vv_softc *vs = &vv_softc[unit]; 361*7024Ssam register struct vvreg *addr; 362*7024Ssam register int oc; 363*7024Ssam COUNT(ENXINT); 364*7024Ssam 365*7024Ssam addr = (struct vvreg *)ui->ui_addr; 366*7024Ssam oc = 0xffff & (addr->vvocsr); 367*7024Ssam if (vs->vs_oactive == 0) { 368*7024Ssam printf("vv%d: stray interrupt vvocsr = %b\n", unit, 369*7024Ssam oc, VV_OBITS); 370*7024Ssam return; 371*7024Ssam } 372*7024Ssam if (oc & (VV_OPT | VV_RFS)) { 373*7024Ssam if (++(vs->vs_tries) < VVRETRY) { 374*7024Ssam if (oc & VV_OPT) 375*7024Ssam vs->vs_init++; 376*7024Ssam if (oc & VV_RFS) 377*7024Ssam vs->vs_nottaken++; 378*7024Ssam addr->vvocsr = VV_IEN | VV_ENB | VV_INR; 379*7024Ssam return; 380*7024Ssam } 381*7024Ssam if (oc & VV_OPT) 382*7024Ssam printf("vv%d: output timeout\n"); 383*7024Ssam } 384*7024Ssam vs->vs_if.if_opackets++; 385*7024Ssam vs->vs_oactive = 0; 386*7024Ssam vs->vs_tries = 0; 387*7024Ssam if (oc & VVXERR) { 388*7024Ssam vs->vs_if.if_oerrors++; 389*7024Ssam printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 390*7024Ssam VV_OBITS); 391*7024Ssam } 392*7024Ssam if (vs->vs_ifuba.ifu_xtofree) { 393*7024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 394*7024Ssam vs->vs_ifuba.ifu_xtofree = 0; 395*7024Ssam } 396*7024Ssam if (vs->vs_if.if_snd.ifq_head == 0) { 397*7024Ssam vs->vs_lastx = 0; 398*7024Ssam return; 399*7024Ssam } 400*7024Ssam vvstart(unit); 401*7024Ssam } 402*7024Ssam 403*7024Ssam /* 404*7024Ssam * V2lni interface receiver interrupt. 405*7024Ssam * If input error just drop packet. 406*7024Ssam * Otherwise purge input buffered data path and examine 407*7024Ssam * packet to determine type. If can't determine length 408*7024Ssam * from type, then have to drop packet. Othewise decapsulate 409*7024Ssam * packet based on type and pass to type specific higher-level 410*7024Ssam * input routine. 411*7024Ssam */ 412*7024Ssam vvrint(unit) 413*7024Ssam int unit; 414*7024Ssam { 415*7024Ssam register struct vv_softc *vs = &vv_softc[unit]; 416*7024Ssam struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 417*7024Ssam register struct vv_header *vv; 418*7024Ssam register struct ifqueue *inq; 419*7024Ssam struct mbuf *m; 420*7024Ssam int ubainfo, len, off; 421*7024Ssam COUNT(VVRINT); 422*7024Ssam 423*7024Ssam vs->vs_if.if_ipackets++; 424*7024Ssam /* 425*7024Ssam * Purge BDP; drop if input error indicated. 426*7024Ssam */ 427*7024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 428*7024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 429*7024Ssam if (addr->vvicsr & VVRERR) { 430*7024Ssam vs->vs_if.if_ierrors++; 431*7024Ssam printf("vv%d: error vvicsr = %b\n", unit, 432*7024Ssam 0xffff&(addr->vvicsr), VV_IBITS); 433*7024Ssam goto setup; 434*7024Ssam } 435*7024Ssam off = 0; 436*7024Ssam len = 0; 437*7024Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 438*7024Ssam /* 439*7024Ssam * Demultiplex on packet type and deal with oddities of 440*7024Ssam * trailer protocol format 441*7024Ssam */ 442*7024Ssam switch (vv->vh_type) { 443*7024Ssam 444*7024Ssam #ifdef INET 445*7024Ssam case RING_IP: 446*7024Ssam len = htons((u_short)((struct ip *) vv)->ip_len); 447*7024Ssam schednetisr(NETISR_IP); 448*7024Ssam inq = &ipintrq; 449*7024Ssam break; 450*7024Ssam #endif 451*7024Ssam default: 452*7024Ssam printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 453*7024Ssam goto setup; 454*7024Ssam } 455*7024Ssam if (len == 0) 456*7024Ssam goto setup; 457*7024Ssam /* 458*7024Ssam * Pull packet off interface. Off is nonzero if packet 459*7024Ssam * has trailing header; if_rubaget will then force this header 460*7024Ssam * information to be at the front, but we still have to drop 461*7024Ssam * the two-byte type which is at the front of any trailer data. 462*7024Ssam */ 463*7024Ssam m = if_rubaget(&vs->vs_ifuba, len, off); 464*7024Ssam if (m == 0) 465*7024Ssam goto setup; 466*7024Ssam IF_ENQUEUE(inq, m); 467*7024Ssam 468*7024Ssam setup: 469*7024Ssam /* 470*7024Ssam * Reset for next packet. 471*7024Ssam */ 472*7024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 473*7024Ssam addr->vviba = (u_short) ubainfo; 474*7024Ssam addr->vviea = (u_short) (ubainfo >> 16); 475*7024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 476*7024Ssam addr->vvicsr = VV_RST | VV_CONF; 477*7024Ssam addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 478*7024Ssam 479*7024Ssam } 480*7024Ssam 481*7024Ssam /* 482*7024Ssam * V2lni output routine. 483*7024Ssam * Encapsulate a packet of type family for the local net. 484*7024Ssam * Use trailer local net encapsulation if enough data in first 485*7024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 486*7024Ssam */ 487*7024Ssam vvoutput(ifp, m0, dst) 488*7024Ssam struct ifnet *ifp; 489*7024Ssam struct mbuf *m0; 490*7024Ssam struct sockaddr *dst; 491*7024Ssam { 492*7024Ssam register struct mbuf *m = m0; 493*7024Ssam register struct vv_header *vv; 494*7024Ssam int type, dest, s; 495*7024Ssam 496*7024Ssam switch (dst->sa_family) { 497*7024Ssam 498*7024Ssam #ifdef INET 499*7024Ssam case AF_INET: { 500*7024Ssam register struct ip *ip = mtod(m0, struct ip *); 501*7024Ssam int off; 502*7024Ssam 503*7024Ssam dest = ip->ip_dst.s_addr >> 24; 504*7024Ssam type = RING_IP; 505*7024Ssam off = 0; 506*7024Ssam goto gottype; 507*7024Ssam } 508*7024Ssam #endif 509*7024Ssam default: 510*7024Ssam printf("vv%d: can't handle af%d\n", ifp->if_unit, 511*7024Ssam dst->sa_family); 512*7024Ssam m_freem(m0); 513*7024Ssam return (0); 514*7024Ssam } 515*7024Ssam 516*7024Ssam gottrailertype: 517*7024Ssam /* 518*7024Ssam * Packet to be sent as trailer: move first packet 519*7024Ssam * (control information) to end of chain. 520*7024Ssam */ 521*7024Ssam while (m->m_next) 522*7024Ssam m = m->m_next; 523*7024Ssam m->m_next = m0; 524*7024Ssam m = m0->m_next; 525*7024Ssam m0->m_next = 0; 526*7024Ssam m0 = m; 527*7024Ssam 528*7024Ssam gottype: 529*7024Ssam /* 530*7024Ssam * Add local net header. If no space in first mbuf, 531*7024Ssam * allocate another. 532*7024Ssam */ 533*7024Ssam if (m->m_off > MMAXOFF || 534*7024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 535*7024Ssam m = m_get(M_DONTWAIT); 536*7024Ssam if (m == 0) { 537*7024Ssam m_freem(m0); 538*7024Ssam return (0); 539*7024Ssam } 540*7024Ssam m->m_next = m0; 541*7024Ssam m->m_off = MMINOFF; 542*7024Ssam m->m_len = sizeof (struct vv_header); 543*7024Ssam } else { 544*7024Ssam m->m_off -= sizeof (struct vv_header); 545*7024Ssam m->m_len += sizeof (struct vv_header); 546*7024Ssam } 547*7024Ssam vv = mtod(m, struct vv_header *); 548*7024Ssam vv->vh_shost = ifp->if_host[0]; 549*7024Ssam vv->vh_dhost = dest; 550*7024Ssam vv->vh_version = RING_VERSION; 551*7024Ssam vv->vh_type = type; 552*7024Ssam vv->vh_info = m->m_len; 553*7024Ssam 554*7024Ssam /* 555*7024Ssam * Queue message on interface, and start output if interface 556*7024Ssam * not yet active. 557*7024Ssam */ 558*7024Ssam s = splimp(); 559*7024Ssam IF_ENQUEUE(&ifp->if_snd, m); 560*7024Ssam if (vv_softc[ifp->if_unit].vs_oactive == 0) 561*7024Ssam vvstart(ifp->if_unit); 562*7024Ssam splx(s); 563*7024Ssam return (1); 564*7024Ssam } 565*7024Ssam 566*7024Ssam #ifdef notdef 567*7024Ssam /* 568*7024Ssam * vvprt_hdr(s, v) print the local net header in "v" 569*7024Ssam * with title is "s" 570*7024Ssam */ 571*7024Ssam vvprt_hdr(s, v) 572*7024Ssam char *s; 573*7024Ssam register struct vv_header *v; 574*7024Ssam { 575*7024Ssam printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 576*7024Ssam s, 577*7024Ssam 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 578*7024Ssam 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 579*7024Ssam 0xffff & (int)(v->vh_info)); 580*7024Ssam } 581*7024Ssam 582*7024Ssam /* 583*7024Ssam * print "l" hex bytes starting at "s" 584*7024Ssam */ 585*7024Ssam vvprt_hex(s, l) 586*7024Ssam char *s; 587*7024Ssam int l; 588*7024Ssam { 589*7024Ssam register int i; 590*7024Ssam register int z; 591*7024Ssam 592*7024Ssam for (i=0 ; i < l; i++) { 593*7024Ssam z = 0xff & (int)(*(s + i)); 594*7024Ssam printf("%c%c ", 595*7024Ssam "0123456789abcdef"[(z >> 4) & 0x0f], 596*7024Ssam "0123456789abcdef"[z & 0x0f] 597*7024Ssam ); 598*7024Ssam } 599*7024Ssam } 600*7024Ssam #endif 601*7024Ssam 602*7024Ssam #if NIMP == 0 && NVV > 0 603*7024Ssam /* 604*7024Ssam * Logical host interface driver. 605*7024Ssam * Allows host to appear as an ARPAnet 606*7024Ssam * logical host. Must also have routing 607*7024Ssam * table entry set up to forward packets 608*7024Ssam * to appropriate geteway on localnet. 609*7024Ssam */ 610*7024Ssam struct ifnet vvlhif; 611*7024Ssam int looutput(); 612*7024Ssam 613*7024Ssam /* 614*7024Ssam * Called by localnet interface to allow logical 615*7024Ssam * host interface to "attach". 616*7024Ssam */ 617*7024Ssam vvlhinit(vvifp, addr) 618*7024Ssam struct ifnet *vvifp; 619*7024Ssam int addr; 620*7024Ssam { 621*7024Ssam register struct ifnet *ifp = &vvlhif; 622*7024Ssam register struct sockaddr_in *sin; 623*7024Ssam 624*7024Ssam COUNT(VVLHINIT); 625*7024Ssam ifp->if_name = "lh"; 626*7024Ssam ifp->if_mtu = VVMTU; 627*7024Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 628*7024Ssam sin->sin_family = AF_INET; 629*7024Ssam sin->sin_addr.s_addr = addr; 630*7024Ssam ifp->if_net = netpart(sin->sin_addr); 631*7024Ssam ifp->if_flags = IFF_UP; 632*7024Ssam ifp->if_output = looutput; 633*7024Ssam if_attach(ifp); 634*7024Ssam rtinit(&ifp->if_addr, &ifp->if_addr, RTF_DIRECT|RTF_UP|RTF_HOST); 635*7024Ssam } 636*7024Ssam #endif 637