1*15794Sleres /* if_vv.c 6.4 84/01/03 */ 27024Ssam 39799Ssam #include "vv.h" 411192Ssam 57024Ssam /* 67024Ssam * Proteon 10 Meg Ring Driver. 77024Ssam * This device is called "vv" because its "real name", 87024Ssam * V2LNI won't work if shortened to the obvious "v2". 97024Ssam * Hence the subterfuge. 1011192Ssam * 117024Ssam */ 1211209Ssam #include "../machine/pte.h" 139799Ssam 147024Ssam #include "../h/param.h" 157024Ssam #include "../h/systm.h" 167024Ssam #include "../h/mbuf.h" 177024Ssam #include "../h/buf.h" 187024Ssam #include "../h/protosw.h" 197024Ssam #include "../h/socket.h" 207024Ssam #include "../h/vmmac.h" 2111192Ssam #include "../h/errno.h" 2213057Ssam #include "../h/ioctl.h" 238465Sroot 248465Sroot #include "../net/if.h" 2511209Ssam #include "../net/netisr.h" 268465Sroot #include "../net/route.h" 278421Swnj #include "../netinet/in.h" 288421Swnj #include "../netinet/in_systm.h" 298421Swnj #include "../netinet/ip.h" 308421Swnj #include "../netinet/ip_var.h" 318465Sroot 32*15794Sleres #include "../vax/cpu.h" 3311209Ssam #include "../vax/mtpr.h" 34*15794Sleres #include "../vaxif/if_vv.h" 35*15794Sleres #include "../vaxif/if_uba.h" 368465Sroot #include "../vaxuba/ubareg.h" 378465Sroot #include "../vaxuba/ubavar.h" 387024Ssam 397024Ssam /* 407024Ssam * N.B. - if WIRECENTER is defined wrong, it can well break 417024Ssam * the hardware!! 427024Ssam */ 437024Ssam #define WIRECENTER 447024Ssam 457024Ssam #ifdef WIRECENTER 467024Ssam #define VV_CONF VV_HEN /* drive wire center relay */ 477024Ssam #else 487024Ssam #define VV_CONF VV_STE /* allow operation without wire center */ 497024Ssam #endif 507024Ssam 517024Ssam #define VVMTU (1024+512) 527640Ssam #define VVMRU (1024+512+16) /* space for trailer */ 537024Ssam 5413057Ssam int vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */ 5515764Sleres vv_logreaderrors = 1; /* 1 => log all read errors */ 567640Ssam 5711192Ssam #define vvtracehdr if (vv_tracehdr) vvprt_hdr 5811192Ssam 59*15794Sleres int vvprobe(), vvattach(), vvrint(), vvxint(), vvwatchdog(); 607024Ssam struct uba_device *vvinfo[NVV]; 617024Ssam u_short vvstd[] = { 0 }; 627024Ssam struct uba_driver vvdriver = 637024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 647024Ssam #define VVUNIT(x) minor(x) 6515764Sleres int vvinit(),vvioctl(),vvoutput(),vvreset(),vvsetaddr(); 667024Ssam 677024Ssam /* 687024Ssam * Software status of each interface. 697024Ssam * 707024Ssam * Each interface is referenced by a network interface structure, 717024Ssam * vs_if, which the routing code uses to locate the interface. 727024Ssam * This structure contains the output queue for the interface, its address, ... 737024Ssam * We also have, for each interface, a UBA interface structure, which 747024Ssam * contains information about the UNIBUS resources held by the interface: 757024Ssam * map registers, buffered data paths, etc. Information is cached in this 767024Ssam * structure for use by the if_uba.c routines in running the interface 777024Ssam * efficiently. 787024Ssam */ 797024Ssam struct vv_softc { 807024Ssam struct ifnet vs_if; /* network-visible interface */ 817024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 8211192Ssam short vs_oactive; /* is output active */ 837024Ssam short vs_olen; /* length of last output */ 84*15794Sleres u_short vs_lastx; /* address of last packet sent */ 85*15794Sleres u_short vs_lastr; /* address of last packet received */ 8611192Ssam short vs_tries; /* transmit current retry count */ 877024Ssam short vs_init; /* number of ring inits */ 887024Ssam short vs_nottaken; /* number of packets refused */ 89*15794Sleres short vs_timeouts; /* number of transmit timeouts */ 907024Ssam } vv_softc[NVV]; 917024Ssam 927024Ssam vvprobe(reg) 937024Ssam caddr_t reg; 947024Ssam { 957024Ssam register int br, cvec; 967024Ssam register struct vvreg *addr = (struct vvreg *)reg; 977024Ssam 987024Ssam #ifdef lint 9915764Sleres br = 0; cvec = br; br = cvec; 1007024Ssam #endif 1017024Ssam /* reset interface, enable, and wait till dust settles */ 1027024Ssam addr->vvicsr = VV_RST; 1037024Ssam addr->vvocsr = VV_RST; 10415764Sleres DELAY(100000); 1057024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1067024Ssam addr->vvocsr = VV_IEN; /* enable interrupt */ 1077024Ssam addr->vvoba = 0; /* low 16 bits */ 1087024Ssam addr->vvoea = 0; /* extended bits */ 1097024Ssam addr->vvowc = -1; /* for 1 word */ 1107024Ssam addr->vvocsr |= VV_DEN; /* start the DMA */ 1117024Ssam DELAY(100000); 1127024Ssam addr->vvocsr = 0; 1137024Ssam if (cvec && cvec != 0x200) 11415764Sleres cvec -= 4; /* backup so vector => receive */ 1157024Ssam return(1); 1167024Ssam } 1177024Ssam 1187024Ssam /* 1197024Ssam * Interface exists: make available by filling in network interface 1207024Ssam * record. System will initialize the interface when it is ready 1217024Ssam * to accept packets. 1227024Ssam */ 1237024Ssam vvattach(ui) 1247024Ssam struct uba_device *ui; 1257024Ssam { 12615764Sleres register struct vv_softc *vs; 1277024Ssam 12815764Sleres vs = &vv_softc[ui->ui_unit]; 1297024Ssam vs->vs_if.if_unit = ui->ui_unit; 1307024Ssam vs->vs_if.if_name = "vv"; 1317024Ssam vs->vs_if.if_mtu = VVMTU; 1327024Ssam vs->vs_if.if_init = vvinit; 13313057Ssam vs->vs_if.if_ioctl = vvioctl; 1347024Ssam vs->vs_if.if_output = vvoutput; 13511209Ssam vs->vs_if.if_reset = vvreset; 136*15794Sleres vs->vs_if.if_timer = 0; 137*15794Sleres vs->vs_if.if_watchdog = vvwatchdog; 1387640Ssam vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 13912354Smo #if defined(VAX750) 14012354Smo /* don't chew up 750 bdp's */ 14112354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 14212354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 14312354Smo #endif 1447024Ssam if_attach(&vs->vs_if); 1457024Ssam } 1467024Ssam 1477024Ssam /* 1487024Ssam * Reset of interface after UNIBUS reset. 1497024Ssam * If interface is on specified uba, reset its state. 1507024Ssam */ 1517024Ssam vvreset(unit, uban) 1527024Ssam int unit, uban; 1537024Ssam { 1547024Ssam register struct uba_device *ui; 1557024Ssam 1567024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 1577024Ssam ui->ui_ubanum != uban) 1587024Ssam return; 1597024Ssam printf(" vv%d", unit); 1607024Ssam vvinit(unit); 1617024Ssam } 1627024Ssam 1637024Ssam /* 1647024Ssam * Initialization of interface; clear recorded pending 1657024Ssam * operations, and reinitialize UNIBUS usage. 1667024Ssam */ 1677024Ssam vvinit(unit) 1687024Ssam int unit; 1697024Ssam { 17015764Sleres register struct vv_softc *vs; 17115764Sleres register struct uba_device *ui; 1727024Ssam register struct vvreg *addr; 1737024Ssam struct sockaddr_in *sin; 1747640Ssam int ubainfo, s; 1757024Ssam 17615764Sleres vs = &vv_softc[unit]; 17715764Sleres ui = vvinfo[unit]; 17815764Sleres sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 17915764Sleres /* 18015764Sleres * If the network number is still zero, we've been 18115764Sleres * called too soon. 18215764Sleres */ 18315764Sleres if (in_netof(sin->sin_addr) == 0) 18413057Ssam return; 1857640Ssam addr = (struct vvreg *)ui->ui_addr; 1867024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 18715764Sleres sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 188*15794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 1897640Ssam vs->vs_if.if_flags &= ~IFF_UP; 1907024Ssam return; 1917024Ssam } 1927024Ssam /* 19315764Sleres * Now that the uba is set up, figure out our address and 19415764Sleres * update complete our host address. 1957640Ssam */ 196*15794Sleres if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) { 197*15794Sleres vs->vs_if.if_flags &= ~IFF_UP; 198*15794Sleres return; 199*15794Sleres } 2007640Ssam printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 20111209Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 2027640Ssam /* 2037640Ssam * Reset the interface, and join the ring 2047640Ssam */ 2057640Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2067640Ssam addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 20712351Smo DELAY(500000); /* let contacts settle */ 2087640Ssam vs->vs_init = 0; 2097640Ssam vs->vs_nottaken = 0; 210*15794Sleres vs->vs_timeouts = 0; 211*15794Sleres vs->vs_lastx = 256; /* an invalid address */ 212*15794Sleres vs->vs_lastr = 256; /* an invalid address */ 2137640Ssam /* 2147640Ssam * Hang a receive and start any 2157640Ssam * pending writes by faking a transmit complete. 2167640Ssam */ 2177640Ssam s = splimp(); 2187640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 21913057Ssam addr->vviba = (u_short)ubainfo; 22013057Ssam addr->vviea = (u_short)(ubainfo >> 16); 2217640Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2227640Ssam addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 2237640Ssam vs->vs_oactive = 1; 22413057Ssam vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; 2257640Ssam vvxint(unit); 2267640Ssam splx(s); 2277640Ssam if_rtinit(&vs->vs_if, RTF_UP); 2287640Ssam } 2297640Ssam 2307640Ssam /* 23115764Sleres * Return our host address. 2327640Ssam */ 23311209Ssam vvidentify(unit) 23413057Ssam int unit; 23511209Ssam { 23615764Sleres register struct vv_softc *vs; 23715764Sleres register struct uba_device *ui; 2387640Ssam register struct vvreg *addr; 2397640Ssam struct mbuf *m; 2407640Ssam struct vv_header *v; 24112774Ssam int ubainfo, attempts, waitcount; 2427640Ssam 2437640Ssam /* 2447024Ssam * Build a multicast message to identify our address 2457024Ssam */ 24615764Sleres vs = &vv_softc[unit]; 24715764Sleres ui = vvinfo[unit]; 2487640Ssam addr = (struct vvreg *)ui->ui_addr; 2497024Ssam attempts = 0; /* total attempts, including bad msg type */ 25011209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 251*15794Sleres if (m == NULL) { 252*15794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 25313057Ssam return (0); 254*15794Sleres } 25511192Ssam m->m_next = 0; 2567024Ssam m->m_off = MMINOFF; 2577024Ssam m->m_len = sizeof(struct vv_header); 2587024Ssam v = mtod(m, struct vv_header *); 25911192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 2607024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 2617024Ssam v->vh_version = RING_VERSION; 2627024Ssam v->vh_type = RING_WHOAMI; 2637024Ssam v->vh_info = 0; 26411192Ssam /* map xmit message into uba */ 2657640Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 2667640Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 2677640Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 2687024Ssam /* 2697024Ssam * Reset interface, establish Digital Loopback Mode, and 2707024Ssam * send the multicast (to myself) with Input Copy enabled. 2717024Ssam */ 2727024Ssam retry: 2737024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 2747024Ssam addr->vvicsr = VV_RST; 2757024Ssam addr->vviba = (u_short) ubainfo; 2767024Ssam addr->vviea = (u_short) (ubainfo >> 16); 2777024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2787024Ssam addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 2797640Ssam 2807640Ssam /* let flag timers fire so ring will initialize */ 28115764Sleres DELAY(2000000); /* about 2 SECONDS on a 780!! */ 2827640Ssam 2837024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2847024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 2857024Ssam addr->vvoba = (u_short) ubainfo; 2867024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 2877024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 2887024Ssam addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 2897024Ssam /* 2907024Ssam * Wait for receive side to finish. 291*15794Sleres * Extract source address (which will be our own), 2927024Ssam * and post to interface structure. 2937024Ssam */ 29415764Sleres DELAY(10000); 29511192Ssam for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { 2969876Ssam if (waitcount < 10) { 2977024Ssam DELAY(1000); 29811209Ssam continue; 29911192Ssam } 300*15794Sleres if (attempts++ < VVIDENTRETRY) 301*15794Sleres goto retry; 30211192Ssam } 303*15794Sleres /* deallocate mbuf used for send packet */ 304*15794Sleres if (vs->vs_ifuba.ifu_xtofree) { 3057024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 306*15794Sleres vs->vs_ifuba.ifu_xtofree = 0; 307*15794Sleres } 308*15794Sleres if (attempts >= VVIDENTRETRY) { 309*15794Sleres printf("vv%d: can't initialize after %d tries, icsr = %b\n", 310*15794Sleres unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS); 311*15794Sleres return (0); 312*15794Sleres } 313*15794Sleres /* Purge BDP before looking at packet we just received */ 3147024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3157024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 3167024Ssam m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 31711209Ssam if (m != NULL) 3187024Ssam m_freem(m); 3197024Ssam /* 32011209Ssam * Check message type before we believe the source host address 3217024Ssam */ 3227024Ssam v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 32311209Ssam if (v->vh_type != RING_WHOAMI) 3247640Ssam goto retry; 32511209Ssam return(v->vh_shost); 3267024Ssam } 3277024Ssam 3287024Ssam /* 3297024Ssam * Start or restart output on interface. 33011192Ssam * If interface is active, this is a retransmit, so just 33111192Ssam * restuff registers and go. 3327024Ssam * If interface is not already active, get another datagram 3337024Ssam * to send off of the interface queue, and map it to the interface 3347024Ssam * before starting the output. 3357024Ssam */ 3367024Ssam vvstart(dev) 3377024Ssam dev_t dev; 3387024Ssam { 3397024Ssam int unit = VVUNIT(dev); 34015764Sleres struct uba_device *ui; 34115764Sleres register struct vv_softc *vs; 3427024Ssam register struct vvreg *addr; 3437024Ssam struct mbuf *m; 344*15794Sleres int ubainfo, dest, s; 3457024Ssam 34615764Sleres ui = vvinfo[unit]; 34715764Sleres vs = &vv_softc[unit]; 3487024Ssam if (vs->vs_oactive) 3497024Ssam goto restart; 3507024Ssam /* 3517024Ssam * Not already active: dequeue another request 3527024Ssam * and map it to the UNIBUS. If no more requests, 3537024Ssam * just return. 3547024Ssam */ 355*15794Sleres s = splimp(); 3567024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 357*15794Sleres splx(s); 35811209Ssam if (m == NULL) { 3597024Ssam vs->vs_oactive = 0; 3607024Ssam return; 3617024Ssam } 3627024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 3637024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 3647024Ssam vs->vs_lastx = dest; 3657024Ssam restart: 3667024Ssam /* 3677024Ssam * Have request mapped to UNIBUS for transmission. 368*15794Sleres * Purge any stale data from this BDP, and start the output. 369*15794Sleres * 370*15794Sleres * Make sure this packet will fit in the interface. 3717024Ssam */ 37212363Ssam if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { 37311192Ssam printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); 37411192Ssam panic("vvdriver vs_olen botch"); 37511192Ssam } 3767024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3777024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3787024Ssam addr = (struct vvreg *)ui->ui_addr; 3797024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 3807024Ssam addr->vvoba = (u_short) ubainfo; 3817024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 3827024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 3837024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 384*15794Sleres vs->vs_if.if_timer = VVTIMEOUT; 3857024Ssam vs->vs_oactive = 1; 3867024Ssam } 3877024Ssam 3887024Ssam /* 3897024Ssam * VVLNI transmit interrupt 3907024Ssam * Start another output if more data to send. 3917024Ssam */ 3927024Ssam vvxint(unit) 3937024Ssam int unit; 3947024Ssam { 39515764Sleres register struct uba_device *ui; 39615764Sleres register struct vv_softc *vs; 3977024Ssam register struct vvreg *addr; 3987024Ssam register int oc; 3997024Ssam 40015764Sleres ui = vvinfo[unit]; 40115764Sleres vs = &vv_softc[unit]; 402*15794Sleres vs->vs_if.if_timer = 0; 4037024Ssam addr = (struct vvreg *)ui->ui_addr; 4047024Ssam oc = 0xffff & (addr->vvocsr); 4057024Ssam if (vs->vs_oactive == 0) { 40611192Ssam printf("vv%d: stray interrupt vvocsr = %b\n", unit, 40715764Sleres oc, VV_OBITS); 4087024Ssam return; 4097024Ssam } 4107024Ssam if (oc & (VV_OPT | VV_RFS)) { 4117640Ssam vs->vs_if.if_collisions++; 41211192Ssam if (vs->vs_tries++ < VVRETRY) { 4137024Ssam if (oc & VV_OPT) 4147024Ssam vs->vs_init++; 4157024Ssam if (oc & VV_RFS) 4167024Ssam vs->vs_nottaken++; 41711192Ssam vvstart(unit); /* restart this message */ 4187024Ssam return; 4197024Ssam } 4207024Ssam if (oc & VV_OPT) 42115764Sleres printf("vv%d: output timeout\n", unit); 4227024Ssam } 4237024Ssam vs->vs_if.if_opackets++; 4247024Ssam vs->vs_oactive = 0; 4257024Ssam vs->vs_tries = 0; 4267024Ssam if (oc & VVXERR) { 4277024Ssam vs->vs_if.if_oerrors++; 42811192Ssam printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 42915764Sleres VV_OBITS); 4307024Ssam } 4317024Ssam if (vs->vs_ifuba.ifu_xtofree) { 4327024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 4337024Ssam vs->vs_ifuba.ifu_xtofree = 0; 4347024Ssam } 4357024Ssam vvstart(unit); 4367024Ssam } 4377024Ssam 4387024Ssam /* 439*15794Sleres * Transmit watchdog timer routine. 440*15794Sleres * This routine gets called when we lose a transmit interrupt. 441*15794Sleres * The best we can do is try to restart output. 442*15794Sleres */ 443*15794Sleres vvwatchdog(unit) 444*15794Sleres int unit; 445*15794Sleres { 446*15794Sleres register struct vv_softc *vs; 447*15794Sleres register int s; 448*15794Sleres 449*15794Sleres vs = &vv_softc[unit]; 450*15794Sleres if (vs->vs_if.if_flags & IFF_DEBUG) 451*15794Sleres printf("vv%d: lost a transmit interrupt.\n", unit); 452*15794Sleres vs->vs_timeouts++; 453*15794Sleres s = splimp(); 454*15794Sleres vvstart(unit); 455*15794Sleres splx(s); 456*15794Sleres } 457*15794Sleres 458*15794Sleres /* 4597024Ssam * V2lni interface receiver interrupt. 4607024Ssam * If input error just drop packet. 46115764Sleres * Otherwise purge input buffered data path and examine 4627024Ssam * packet to determine type. If can't determine length 46315764Sleres * from type, then have to drop packet. Otherwise decapsulate 4647024Ssam * packet based on type and pass to type specific higher-level 4657024Ssam * input routine. 4667024Ssam */ 4677024Ssam vvrint(unit) 4687024Ssam int unit; 4697024Ssam { 47015764Sleres register struct vv_softc *vs; 47115764Sleres struct vvreg *addr; 4727024Ssam register struct vv_header *vv; 4737024Ssam register struct ifqueue *inq; 47415764Sleres struct mbuf *m; 475*15794Sleres int ubainfo, len, off, s; 4767640Ssam short resid; 4777024Ssam 47815764Sleres vs = &vv_softc[unit]; 47915764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 4807024Ssam vs->vs_if.if_ipackets++; 4817024Ssam /* 4827024Ssam * Purge BDP; drop if input error indicated. 4837024Ssam */ 4847024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 4857024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 4867024Ssam if (addr->vvicsr & VVRERR) { 487*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 488*15794Sleres printf("vv%d: VVRERR, vvicsr = %b\n", unit, 48915764Sleres 0xffff&(addr->vvicsr), VV_IBITS); 4907640Ssam goto dropit; 4917024Ssam } 4927640Ssam 4937024Ssam /* 4947640Ssam * Get packet length from word count residue 4957640Ssam * 4967640Ssam * Compute header offset if trailer protocol 4977640Ssam * 4987640Ssam * Pull packet off interface. Off is nonzero if packet 4997640Ssam * has trailing header; if_rubaget will then force this header 5007640Ssam * information to be at the front. The vh_info field 5017640Ssam * carries the offset to the trailer data in trailer 5027640Ssam * format packets. 5037024Ssam */ 5047640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 50511192Ssam vvtracehdr("vi", vv); 5067640Ssam resid = addr->vviwc; 5077640Ssam if (resid) 5087640Ssam resid |= 0176000; /* ugly!!!! */ 5097640Ssam len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 5107640Ssam len -= sizeof(struct vv_header); 511*15794Sleres if (len > VVMRU || len <= 0) { 512*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 513*15794Sleres printf("vv%d: len too big, len = %d, vvicsr = %b\n", 514*15794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 5157640Ssam goto dropit; 516*15794Sleres } 5177640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 51813057Ssam if (vv->vh_type >= RING_IPTrailer && 51913057Ssam vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { 5207640Ssam off = (vv->vh_type - RING_IPTrailer) * 512; 521*15794Sleres if (off > VVMTU) { 522*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 523*15794Sleres printf("vv%d: VVMTU, off = %d, vvicsr = %b\n", 524*15794Sleres unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 5257640Ssam goto dropit; 526*15794Sleres } 5277640Ssam vv->vh_type = *vvdataaddr(vv, off, u_short *); 5287640Ssam resid = *(vvdataaddr(vv, off+2, u_short *)); 529*15794Sleres if (off + resid > len) { 530*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 531*15794Sleres printf( 532*15794Sleres "vv%d: off = %d, resid = %d, vvicsr = %b\n", 533*15794Sleres unit, off, resid, 534*15794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5357640Ssam goto dropit; 536*15794Sleres } 5377640Ssam len = off + resid; 53811209Ssam } else 5397640Ssam off = 0; 540*15794Sleres if (len == 0) { 541*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 542*15794Sleres printf("vv%d: len is zero, vvicsr = %b\n", unit, 543*15794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5447640Ssam goto dropit; 545*15794Sleres } 5467640Ssam m = if_rubaget(&vs->vs_ifuba, len, off); 547*15794Sleres if (m == NULL) { 548*15794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 549*15794Sleres printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit, 550*15794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5517640Ssam goto dropit; 552*15794Sleres } 5537640Ssam if (off) { 5547640Ssam m->m_off += 2 * sizeof(u_short); 5557640Ssam m->m_len -= 2 * sizeof(u_short); 5567640Ssam } 55711192Ssam 558*15794Sleres /* Keep track of source address of this packet */ 559*15794Sleres vs->vs_lastr = vv->vh_shost; 56011192Ssam /* 56115764Sleres * Demultiplex on packet type 56211192Ssam */ 5637024Ssam switch (vv->vh_type) { 56411192Ssam 5657024Ssam #ifdef INET 5667024Ssam case RING_IP: 5677024Ssam schednetisr(NETISR_IP); 5687024Ssam inq = &ipintrq; 5697024Ssam break; 5707024Ssam #endif 5717024Ssam default: 5727024Ssam printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 5737640Ssam m_freem(m); 5747024Ssam goto setup; 5757024Ssam } 576*15794Sleres s = splimp(); 5777640Ssam if (IF_QFULL(inq)) { 5787640Ssam IF_DROP(inq); 5797640Ssam m_freem(m); 58011209Ssam } else 5817640Ssam IF_ENQUEUE(inq, m); 58215764Sleres 583*15794Sleres splx(s); 5847024Ssam /* 58515764Sleres * Reset for the next packet. 5867024Ssam */ 58715764Sleres setup: 58815764Sleres ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 58915764Sleres addr->vviba = (u_short) ubainfo; 59015764Sleres addr->vviea = (u_short) (ubainfo >> 16); 59115764Sleres addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 59215764Sleres addr->vvicsr = VV_RST | VV_CONF; 59315764Sleres addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 59415764Sleres return; 59511192Ssam 59611192Ssam /* 59711209Ssam * Drop packet on floor -- count them!! 59811192Ssam */ 5997640Ssam dropit: 6007640Ssam vs->vs_if.if_ierrors++; 6017640Ssam goto setup; 6027024Ssam } 6037024Ssam 6047024Ssam /* 6057024Ssam * V2lni output routine. 6067024Ssam * Encapsulate a packet of type family for the local net. 6077024Ssam * Use trailer local net encapsulation if enough data in first 6087024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 6097024Ssam */ 6107024Ssam vvoutput(ifp, m0, dst) 6117024Ssam struct ifnet *ifp; 6127024Ssam struct mbuf *m0; 6137024Ssam struct sockaddr *dst; 6147024Ssam { 6157024Ssam register struct mbuf *m = m0; 6167024Ssam register struct vv_header *vv; 6177640Ssam register int off; 6187640Ssam int type, dest, s, error; 6197024Ssam 6207024Ssam switch (dst->sa_family) { 62111192Ssam 6227024Ssam #ifdef INET 62315764Sleres case AF_INET: 6247640Ssam dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 62511192Ssam if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { 6267640Ssam error = EPERM; 6277640Ssam goto bad; 6287640Ssam } 6297640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 63015764Sleres /* Need per host negotiation. */ 63113090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 63213090Ssam if (off > 0 && (off & 0x1ff) == 0 && 6337640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 6347640Ssam type = RING_IPTrailer + (off>>9); 6357640Ssam m->m_off -= 2 * sizeof (u_short); 6367640Ssam m->m_len += 2 * sizeof (u_short); 6377640Ssam *mtod(m, u_short *) = RING_IP; 6387640Ssam *(mtod(m, u_short *) + 1) = m->m_len; 6397640Ssam goto gottrailertype; 6407640Ssam } 6417024Ssam type = RING_IP; 6427024Ssam off = 0; 6437024Ssam goto gottype; 6447024Ssam #endif 6457024Ssam default: 6467024Ssam printf("vv%d: can't handle af%d\n", ifp->if_unit, 6477024Ssam dst->sa_family); 6487640Ssam error = EAFNOSUPPORT; 6497640Ssam goto bad; 6507024Ssam } 6517024Ssam 6527024Ssam gottrailertype: 6537024Ssam /* 6547024Ssam * Packet to be sent as trailer: move first packet 6557024Ssam * (control information) to end of chain. 6567024Ssam */ 6577024Ssam while (m->m_next) 6587024Ssam m = m->m_next; 6597024Ssam m->m_next = m0; 6607024Ssam m = m0->m_next; 6617024Ssam m0->m_next = 0; 6627024Ssam m0 = m; 6637024Ssam gottype: 6647024Ssam /* 6657024Ssam * Add local net header. If no space in first mbuf, 6667024Ssam * allocate another. 6677024Ssam */ 6687024Ssam if (m->m_off > MMAXOFF || 6697024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 67011209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 67111209Ssam if (m == NULL) { 6727640Ssam error = ENOBUFS; 6737640Ssam goto bad; 6747024Ssam } 6757024Ssam m->m_next = m0; 6767024Ssam m->m_off = MMINOFF; 6777024Ssam m->m_len = sizeof (struct vv_header); 6787024Ssam } else { 6797024Ssam m->m_off -= sizeof (struct vv_header); 6807024Ssam m->m_len += sizeof (struct vv_header); 6817024Ssam } 6827024Ssam vv = mtod(m, struct vv_header *); 6837024Ssam vv->vh_shost = ifp->if_host[0]; 68415764Sleres /* Map the destination address if it's a broadcast */ 68515764Sleres if ((vv->vh_dhost = dest) == INADDR_ANY) 68615764Sleres vv->vh_dhost = VV_BROADCAST; 6877024Ssam vv->vh_version = RING_VERSION; 6887024Ssam vv->vh_type = type; 6897640Ssam vv->vh_info = off; 69011192Ssam vvtracehdr("vo", vv); 6917024Ssam 6927024Ssam /* 6937024Ssam * Queue message on interface, and start output if interface 6947024Ssam * not yet active. 6957024Ssam */ 6967024Ssam s = splimp(); 6977640Ssam if (IF_QFULL(&ifp->if_snd)) { 6987640Ssam IF_DROP(&ifp->if_snd); 6997640Ssam error = ENOBUFS; 7007640Ssam goto qfull; 7017640Ssam } 7027024Ssam IF_ENQUEUE(&ifp->if_snd, m); 7037024Ssam if (vv_softc[ifp->if_unit].vs_oactive == 0) 7047024Ssam vvstart(ifp->if_unit); 7057024Ssam splx(s); 7067640Ssam return (0); 7077640Ssam qfull: 7087640Ssam m0 = m; 7097640Ssam splx(s); 7107640Ssam bad: 7117640Ssam m_freem(m0); 7127640Ssam return(error); 7137024Ssam } 7147024Ssam 7157024Ssam /* 71613057Ssam * Process an ioctl request. 71713057Ssam */ 71813057Ssam vvioctl(ifp, cmd, data) 71913057Ssam register struct ifnet *ifp; 72013057Ssam int cmd; 72113057Ssam caddr_t data; 72213057Ssam { 72315764Sleres struct ifreq *ifr; 72415764Sleres int s, error; 72513057Ssam 72615764Sleres ifr = (struct ifreq *)data; 72715764Sleres error = 0; 72815764Sleres s = splimp(); 72913057Ssam switch (cmd) { 73013057Ssam 73113057Ssam case SIOCSIFADDR: 732*15794Sleres /* too difficult to change address while running */ 73313057Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 73415764Sleres vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 73513057Ssam vvinit(ifp->if_unit); 73613057Ssam } else 73713057Ssam error = EINVAL; 73813057Ssam break; 73913057Ssam 74013057Ssam default: 74113057Ssam error = EINVAL; 74213057Ssam } 74313057Ssam splx(s); 74413057Ssam return (error); 74513057Ssam } 74613057Ssam 74713057Ssam /* 74815764Sleres * Set up the address for this interface. We use the network number 749*15794Sleres * from the passed address and an invalid host number; vvinit() will 750*15794Sleres * figure out the host number and insert it later. 75115764Sleres */ 75215764Sleres vvsetaddr(ifp, sin) 75315764Sleres register struct ifnet *ifp; 75415764Sleres register struct sockaddr_in *sin; 75515764Sleres { 75615764Sleres ifp->if_net = in_netof(sin->sin_addr); 75715764Sleres ifp->if_host[0] = 256; /* an invalid host number */ 75815764Sleres sin = (struct sockaddr_in *)&ifp->if_addr; 75915764Sleres sin->sin_family = AF_INET; 76015764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 76115764Sleres sin = (struct sockaddr_in *)&ifp->if_broadaddr; 76215764Sleres sin->sin_family = AF_INET; 76315764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 76415764Sleres ifp->if_flags |= IFF_BROADCAST; 76515764Sleres } 76615764Sleres 76715764Sleres /* 7687024Ssam * vvprt_hdr(s, v) print the local net header in "v" 76915764Sleres * with title is "s" 7707024Ssam */ 7717024Ssam vvprt_hdr(s, v) 7727024Ssam char *s; 7737024Ssam register struct vv_header *v; 7747024Ssam { 7757024Ssam printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 7767024Ssam s, 7777024Ssam 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 7787024Ssam 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 7797024Ssam 0xffff & (int)(v->vh_info)); 7807024Ssam } 7817024Ssam 78212774Ssam #ifdef notdef 7837024Ssam /* 7847024Ssam * print "l" hex bytes starting at "s" 7857024Ssam */ 78615764Sleres vvprt_hex(s, l) 7877024Ssam char *s; 7887024Ssam int l; 7897024Ssam { 7907024Ssam register int i; 7917024Ssam register int z; 7927024Ssam 7937024Ssam for (i=0 ; i < l; i++) { 7947024Ssam z = 0xff & (int)(*(s + i)); 7957024Ssam printf("%c%c ", 7967024Ssam "0123456789abcdef"[(z >> 4) & 0x0f], 7977024Ssam "0123456789abcdef"[z & 0x0f] 7987024Ssam ); 7997024Ssam } 8007024Ssam } 80112774Ssam #endif 802