1*17117Sbloom /* if_vv.c 6.6 84/08/29 */ 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 14*17117Sbloom #include "param.h" 15*17117Sbloom #include "systm.h" 16*17117Sbloom #include "mbuf.h" 17*17117Sbloom #include "buf.h" 18*17117Sbloom #include "protosw.h" 19*17117Sbloom #include "socket.h" 20*17117Sbloom #include "vmmac.h" 21*17117Sbloom #include "errno.h" 22*17117Sbloom #include "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 3215794Sleres #include "../vax/cpu.h" 3311209Ssam #include "../vax/mtpr.h" 34*17117Sbloom #include "if_vv.h" 35*17117Sbloom #include "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 5416581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 5516581Skarels int vv_logreaderrors = 1; /* 1 => log all read errors */ 567640Ssam 5711192Ssam #define vvtracehdr if (vv_tracehdr) vvprt_hdr 5811192Ssam 5916581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 6016581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 6116581Skarels int vvrint(), vvoutput(), vvioctl(), vvsetaddr(); 627024Ssam struct uba_device *vvinfo[NVV]; 637024Ssam u_short vvstd[] = { 0 }; 647024Ssam struct uba_driver vvdriver = 657024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 667024Ssam #define VVUNIT(x) minor(x) 677024Ssam 687024Ssam /* 697024Ssam * Software status of each interface. 707024Ssam * 717024Ssam * Each interface is referenced by a network interface structure, 727024Ssam * vs_if, which the routing code uses to locate the interface. 737024Ssam * This structure contains the output queue for the interface, its address, ... 747024Ssam * We also have, for each interface, a UBA interface structure, which 757024Ssam * contains information about the UNIBUS resources held by the interface: 767024Ssam * map registers, buffered data paths, etc. Information is cached in this 777024Ssam * structure for use by the if_uba.c routines in running the interface 787024Ssam * efficiently. 797024Ssam */ 807024Ssam struct vv_softc { 817024Ssam struct ifnet vs_if; /* network-visible interface */ 827024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 8311192Ssam short vs_oactive; /* is output active */ 847024Ssam short vs_olen; /* length of last output */ 8515794Sleres u_short vs_lastx; /* address of last packet sent */ 8615794Sleres u_short vs_lastr; /* address of last packet received */ 8711192Ssam short vs_tries; /* transmit current retry count */ 887024Ssam short vs_init; /* number of ring inits */ 897024Ssam short vs_nottaken; /* number of packets refused */ 9015794Sleres short vs_timeouts; /* number of transmit timeouts */ 917024Ssam } vv_softc[NVV]; 927024Ssam 937024Ssam vvprobe(reg) 947024Ssam caddr_t reg; 957024Ssam { 967024Ssam register int br, cvec; 9716581Skarels register struct vvreg *addr; 987024Ssam 997024Ssam #ifdef lint 10015764Sleres br = 0; cvec = br; br = cvec; 1017024Ssam #endif 10216581Skarels addr = (struct vvreg *)reg; 1037024Ssam /* reset interface, enable, and wait till dust settles */ 1047024Ssam addr->vvicsr = VV_RST; 1057024Ssam addr->vvocsr = VV_RST; 10615764Sleres DELAY(100000); 1077024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1087024Ssam addr->vvocsr = VV_IEN; /* enable interrupt */ 1097024Ssam addr->vvoba = 0; /* low 16 bits */ 1107024Ssam addr->vvoea = 0; /* extended bits */ 1117024Ssam addr->vvowc = -1; /* for 1 word */ 1127024Ssam addr->vvocsr |= VV_DEN; /* start the DMA */ 1137024Ssam DELAY(100000); 1147024Ssam addr->vvocsr = 0; 1157024Ssam if (cvec && cvec != 0x200) 11615764Sleres cvec -= 4; /* backup so vector => receive */ 1177024Ssam return(1); 1187024Ssam } 1197024Ssam 1207024Ssam /* 1217024Ssam * Interface exists: make available by filling in network interface 1227024Ssam * record. System will initialize the interface when it is ready 1237024Ssam * to accept packets. 1247024Ssam */ 1257024Ssam vvattach(ui) 1267024Ssam struct uba_device *ui; 1277024Ssam { 12815764Sleres register struct vv_softc *vs; 1297024Ssam 13015764Sleres vs = &vv_softc[ui->ui_unit]; 1317024Ssam vs->vs_if.if_unit = ui->ui_unit; 1327024Ssam vs->vs_if.if_name = "vv"; 1337024Ssam vs->vs_if.if_mtu = VVMTU; 1347024Ssam vs->vs_if.if_init = vvinit; 13513057Ssam vs->vs_if.if_ioctl = vvioctl; 1367024Ssam vs->vs_if.if_output = vvoutput; 13711209Ssam vs->vs_if.if_reset = vvreset; 13815794Sleres vs->vs_if.if_timer = 0; 13915794Sleres vs->vs_if.if_watchdog = vvwatchdog; 1407640Ssam vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 14112354Smo #if defined(VAX750) 14212354Smo /* don't chew up 750 bdp's */ 14312354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 14412354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 14512354Smo #endif 1467024Ssam if_attach(&vs->vs_if); 1477024Ssam } 1487024Ssam 1497024Ssam /* 1507024Ssam * Reset of interface after UNIBUS reset. 1517024Ssam * If interface is on specified uba, reset its state. 1527024Ssam */ 1537024Ssam vvreset(unit, uban) 1547024Ssam int unit, uban; 1557024Ssam { 1567024Ssam register struct uba_device *ui; 1577024Ssam 1587024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 1597024Ssam ui->ui_ubanum != uban) 1607024Ssam return; 1617024Ssam printf(" vv%d", unit); 1627024Ssam vvinit(unit); 1637024Ssam } 1647024Ssam 1657024Ssam /* 1667024Ssam * Initialization of interface; clear recorded pending 1677024Ssam * operations, and reinitialize UNIBUS usage. 1687024Ssam */ 1697024Ssam vvinit(unit) 1707024Ssam int unit; 1717024Ssam { 17215764Sleres register struct vv_softc *vs; 17315764Sleres register struct uba_device *ui; 1747024Ssam register struct vvreg *addr; 17516581Skarels register struct sockaddr_in *sin; 17616581Skarels register int ubainfo, s; 1777024Ssam 17815764Sleres vs = &vv_softc[unit]; 17915764Sleres ui = vvinfo[unit]; 18015764Sleres sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 18115764Sleres /* 18215764Sleres * If the network number is still zero, we've been 18315764Sleres * called too soon. 18415764Sleres */ 18515764Sleres if (in_netof(sin->sin_addr) == 0) 18613057Ssam return; 1877640Ssam addr = (struct vvreg *)ui->ui_addr; 1887024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 18915764Sleres sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 19015794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 1917640Ssam vs->vs_if.if_flags &= ~IFF_UP; 1927024Ssam return; 1937024Ssam } 1947024Ssam /* 19515764Sleres * Now that the uba is set up, figure out our address and 19615764Sleres * update complete our host address. 1977640Ssam */ 19815794Sleres if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) { 19915794Sleres vs->vs_if.if_flags &= ~IFF_UP; 20015794Sleres return; 20115794Sleres } 2027640Ssam printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 20311209Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 2047640Ssam /* 2057640Ssam * Reset the interface, and join the ring 2067640Ssam */ 2077640Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2087640Ssam addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 20912351Smo DELAY(500000); /* let contacts settle */ 2107640Ssam vs->vs_init = 0; 2117640Ssam vs->vs_nottaken = 0; 21215794Sleres vs->vs_timeouts = 0; 21315794Sleres vs->vs_lastx = 256; /* an invalid address */ 21415794Sleres vs->vs_lastr = 256; /* an invalid address */ 2157640Ssam /* 2167640Ssam * Hang a receive and start any 2177640Ssam * pending writes by faking a transmit complete. 2187640Ssam */ 2197640Ssam s = splimp(); 2207640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 22113057Ssam addr->vviba = (u_short)ubainfo; 22213057Ssam addr->vviea = (u_short)(ubainfo >> 16); 2237640Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2247640Ssam addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 2257640Ssam vs->vs_oactive = 1; 22613057Ssam vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; 2277640Ssam vvxint(unit); 2287640Ssam splx(s); 2297640Ssam if_rtinit(&vs->vs_if, RTF_UP); 2307640Ssam } 2317640Ssam 2327640Ssam /* 23315764Sleres * Return our host address. 2347640Ssam */ 23511209Ssam vvidentify(unit) 23613057Ssam int unit; 23711209Ssam { 23815764Sleres register struct vv_softc *vs; 23915764Sleres register struct uba_device *ui; 2407640Ssam register struct vvreg *addr; 24116581Skarels register struct mbuf *m; 24216581Skarels register struct vv_header *v; 24316581Skarels register int ubainfo, attempts, waitcount; 2447640Ssam 2457640Ssam /* 2467024Ssam * Build a multicast message to identify our address 2477024Ssam */ 24815764Sleres vs = &vv_softc[unit]; 24915764Sleres ui = vvinfo[unit]; 2507640Ssam addr = (struct vvreg *)ui->ui_addr; 2517024Ssam attempts = 0; /* total attempts, including bad msg type */ 25211209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 25315794Sleres if (m == NULL) { 25415794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 25513057Ssam return (0); 25615794Sleres } 25711192Ssam m->m_next = 0; 2587024Ssam m->m_off = MMINOFF; 2597024Ssam m->m_len = sizeof(struct vv_header); 2607024Ssam v = mtod(m, struct vv_header *); 26111192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 2627024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 2637024Ssam v->vh_version = RING_VERSION; 2647024Ssam v->vh_type = RING_WHOAMI; 2657024Ssam v->vh_info = 0; 26611192Ssam /* map xmit message into uba */ 2677640Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 2687640Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 2697640Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 2707024Ssam /* 2717024Ssam * Reset interface, establish Digital Loopback Mode, and 2727024Ssam * send the multicast (to myself) with Input Copy enabled. 2737024Ssam */ 2747024Ssam retry: 2757024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 2767024Ssam addr->vvicsr = VV_RST; 2777024Ssam addr->vviba = (u_short) ubainfo; 2787024Ssam addr->vviea = (u_short) (ubainfo >> 16); 2797024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2807024Ssam addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 2817640Ssam 2827640Ssam /* let flag timers fire so ring will initialize */ 28315764Sleres DELAY(2000000); /* about 2 SECONDS on a 780!! */ 2847640Ssam 2857024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2867024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 2877024Ssam addr->vvoba = (u_short) ubainfo; 2887024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 2897024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 2907024Ssam addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 2917024Ssam /* 2927024Ssam * Wait for receive side to finish. 29315794Sleres * Extract source address (which will be our own), 2947024Ssam * and post to interface structure. 2957024Ssam */ 29615764Sleres DELAY(10000); 29711192Ssam for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { 2989876Ssam if (waitcount < 10) { 2997024Ssam DELAY(1000); 30011209Ssam continue; 30111192Ssam } 30215794Sleres if (attempts++ < VVIDENTRETRY) 30315794Sleres goto retry; 30411192Ssam } 30515794Sleres /* deallocate mbuf used for send packet */ 30615794Sleres if (vs->vs_ifuba.ifu_xtofree) { 3077024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 30815794Sleres vs->vs_ifuba.ifu_xtofree = 0; 30915794Sleres } 31015794Sleres if (attempts >= VVIDENTRETRY) { 31115794Sleres printf("vv%d: can't initialize after %d tries, icsr = %b\n", 31215794Sleres unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS); 31315794Sleres return (0); 31415794Sleres } 31515794Sleres /* Purge BDP before looking at packet we just received */ 3167024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3177024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 3187024Ssam m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 31911209Ssam if (m != NULL) 3207024Ssam m_freem(m); 3217024Ssam /* 32211209Ssam * Check message type before we believe the source host address 3237024Ssam */ 3247024Ssam v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 32511209Ssam if (v->vh_type != RING_WHOAMI) 3267640Ssam goto retry; 32711209Ssam return(v->vh_shost); 3287024Ssam } 3297024Ssam 3307024Ssam /* 3317024Ssam * Start or restart output on interface. 33211192Ssam * If interface is active, this is a retransmit, so just 33311192Ssam * restuff registers and go. 3347024Ssam * If interface is not already active, get another datagram 3357024Ssam * to send off of the interface queue, and map it to the interface 3367024Ssam * before starting the output. 3377024Ssam */ 3387024Ssam vvstart(dev) 3397024Ssam dev_t dev; 3407024Ssam { 34116581Skarels register struct uba_device *ui; 34215764Sleres register struct vv_softc *vs; 3437024Ssam register struct vvreg *addr; 34416581Skarels register struct mbuf *m; 34516581Skarels register int unit, ubainfo, dest, s; 3467024Ssam 34716581Skarels unit = VVUNIT(dev); 34815764Sleres ui = vvinfo[unit]; 34915764Sleres vs = &vv_softc[unit]; 3507024Ssam if (vs->vs_oactive) 3517024Ssam goto restart; 3527024Ssam /* 3537024Ssam * Not already active: dequeue another request 3547024Ssam * and map it to the UNIBUS. If no more requests, 3557024Ssam * just return. 3567024Ssam */ 35715794Sleres s = splimp(); 3587024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 35915794Sleres splx(s); 36011209Ssam if (m == NULL) { 3617024Ssam vs->vs_oactive = 0; 3627024Ssam return; 3637024Ssam } 3647024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 3657024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 3667024Ssam vs->vs_lastx = dest; 3677024Ssam restart: 3687024Ssam /* 3697024Ssam * Have request mapped to UNIBUS for transmission. 37015794Sleres * Purge any stale data from this BDP, and start the output. 37115794Sleres * 37215794Sleres * Make sure this packet will fit in the interface. 3737024Ssam */ 37412363Ssam if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { 37511192Ssam printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); 37611192Ssam panic("vvdriver vs_olen botch"); 37711192Ssam } 3787024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3797024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3807024Ssam addr = (struct vvreg *)ui->ui_addr; 3817024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 3827024Ssam addr->vvoba = (u_short) ubainfo; 3837024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 3847024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 3857024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 38615794Sleres vs->vs_if.if_timer = VVTIMEOUT; 3877024Ssam vs->vs_oactive = 1; 3887024Ssam } 3897024Ssam 3907024Ssam /* 3917024Ssam * VVLNI transmit interrupt 3927024Ssam * Start another output if more data to send. 3937024Ssam */ 3947024Ssam vvxint(unit) 3957024Ssam int unit; 3967024Ssam { 39715764Sleres register struct uba_device *ui; 39815764Sleres register struct vv_softc *vs; 3997024Ssam register struct vvreg *addr; 4007024Ssam register int oc; 4017024Ssam 40215764Sleres ui = vvinfo[unit]; 40315764Sleres vs = &vv_softc[unit]; 40415794Sleres vs->vs_if.if_timer = 0; 4057024Ssam addr = (struct vvreg *)ui->ui_addr; 4067024Ssam oc = 0xffff & (addr->vvocsr); 4077024Ssam if (vs->vs_oactive == 0) { 40811192Ssam printf("vv%d: stray interrupt vvocsr = %b\n", unit, 40915764Sleres oc, VV_OBITS); 4107024Ssam return; 4117024Ssam } 4127024Ssam if (oc & (VV_OPT | VV_RFS)) { 4137640Ssam vs->vs_if.if_collisions++; 41411192Ssam if (vs->vs_tries++ < VVRETRY) { 4157024Ssam if (oc & VV_OPT) 4167024Ssam vs->vs_init++; 4177024Ssam if (oc & VV_RFS) 4187024Ssam vs->vs_nottaken++; 41911192Ssam vvstart(unit); /* restart this message */ 4207024Ssam return; 4217024Ssam } 4227024Ssam if (oc & VV_OPT) 42315764Sleres printf("vv%d: output timeout\n", unit); 4247024Ssam } 4257024Ssam vs->vs_if.if_opackets++; 4267024Ssam vs->vs_oactive = 0; 4277024Ssam vs->vs_tries = 0; 4287024Ssam if (oc & VVXERR) { 4297024Ssam vs->vs_if.if_oerrors++; 43011192Ssam printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 43115764Sleres VV_OBITS); 4327024Ssam } 4337024Ssam if (vs->vs_ifuba.ifu_xtofree) { 4347024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 4357024Ssam vs->vs_ifuba.ifu_xtofree = 0; 4367024Ssam } 4377024Ssam vvstart(unit); 4387024Ssam } 4397024Ssam 4407024Ssam /* 44115794Sleres * Transmit watchdog timer routine. 44215794Sleres * This routine gets called when we lose a transmit interrupt. 44315794Sleres * The best we can do is try to restart output. 44415794Sleres */ 44515794Sleres vvwatchdog(unit) 44615794Sleres int unit; 44715794Sleres { 44815794Sleres register struct vv_softc *vs; 44915794Sleres register int s; 45015794Sleres 45115794Sleres vs = &vv_softc[unit]; 45215794Sleres if (vs->vs_if.if_flags & IFF_DEBUG) 45315794Sleres printf("vv%d: lost a transmit interrupt.\n", unit); 45415794Sleres vs->vs_timeouts++; 45515794Sleres s = splimp(); 45615794Sleres vvstart(unit); 45715794Sleres splx(s); 45815794Sleres } 45915794Sleres 46015794Sleres /* 4617024Ssam * V2lni interface receiver interrupt. 4627024Ssam * If input error just drop packet. 46315764Sleres * Otherwise purge input buffered data path and examine 4647024Ssam * packet to determine type. If can't determine length 46515764Sleres * from type, then have to drop packet. Otherwise decapsulate 4667024Ssam * packet based on type and pass to type specific higher-level 4677024Ssam * input routine. 4687024Ssam */ 4697024Ssam vvrint(unit) 4707024Ssam int unit; 4717024Ssam { 47215764Sleres register struct vv_softc *vs; 47316581Skarels register struct vvreg *addr; 4747024Ssam register struct vv_header *vv; 4757024Ssam register struct ifqueue *inq; 47616581Skarels register struct mbuf *m; 47715794Sleres int ubainfo, len, off, s; 4787640Ssam short resid; 4797024Ssam 48015764Sleres vs = &vv_softc[unit]; 48116581Skarels vs->vs_if.if_ipackets++; 48215764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 4837024Ssam /* 4847024Ssam * Purge BDP; drop if input error indicated. 4857024Ssam */ 4867024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 4877024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 4887024Ssam if (addr->vvicsr & VVRERR) { 48915794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 49015794Sleres printf("vv%d: VVRERR, vvicsr = %b\n", unit, 49115764Sleres 0xffff&(addr->vvicsr), VV_IBITS); 4927640Ssam goto dropit; 4937024Ssam } 4947640Ssam 4957024Ssam /* 4967640Ssam * Get packet length from word count residue 4977640Ssam * 4987640Ssam * Compute header offset if trailer protocol 4997640Ssam * 5007640Ssam * Pull packet off interface. Off is nonzero if packet 5017640Ssam * has trailing header; if_rubaget will then force this header 5027640Ssam * information to be at the front. The vh_info field 5037640Ssam * carries the offset to the trailer data in trailer 5047640Ssam * format packets. 5057024Ssam */ 5067640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 50711192Ssam vvtracehdr("vi", vv); 5087640Ssam resid = addr->vviwc; 5097640Ssam if (resid) 5107640Ssam resid |= 0176000; /* ugly!!!! */ 5117640Ssam len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 5127640Ssam len -= sizeof(struct vv_header); 51315794Sleres if (len > VVMRU || len <= 0) { 51415794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 51515794Sleres printf("vv%d: len too big, len = %d, vvicsr = %b\n", 51615794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 5177640Ssam goto dropit; 51815794Sleres } 5197640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 52013057Ssam if (vv->vh_type >= RING_IPTrailer && 52113057Ssam vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { 5227640Ssam off = (vv->vh_type - RING_IPTrailer) * 512; 52315794Sleres if (off > VVMTU) { 52415794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 52515794Sleres printf("vv%d: VVMTU, off = %d, vvicsr = %b\n", 52615794Sleres unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 5277640Ssam goto dropit; 52815794Sleres } 5297640Ssam vv->vh_type = *vvdataaddr(vv, off, u_short *); 5307640Ssam resid = *(vvdataaddr(vv, off+2, u_short *)); 53115794Sleres if (off + resid > len) { 53215794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 53315794Sleres printf( 53415794Sleres "vv%d: off = %d, resid = %d, vvicsr = %b\n", 53515794Sleres unit, off, resid, 53615794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5377640Ssam goto dropit; 53815794Sleres } 5397640Ssam len = off + resid; 54011209Ssam } else 5417640Ssam off = 0; 54215794Sleres if (len == 0) { 54315794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 54415794Sleres printf("vv%d: len is zero, vvicsr = %b\n", unit, 54515794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5467640Ssam goto dropit; 54715794Sleres } 5487640Ssam m = if_rubaget(&vs->vs_ifuba, len, off); 54915794Sleres if (m == NULL) { 55015794Sleres if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 55115794Sleres printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit, 55215794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5537640Ssam goto dropit; 55415794Sleres } 5557640Ssam if (off) { 5567640Ssam m->m_off += 2 * sizeof(u_short); 5577640Ssam m->m_len -= 2 * sizeof(u_short); 5587640Ssam } 55911192Ssam 56015794Sleres /* Keep track of source address of this packet */ 56115794Sleres vs->vs_lastr = vv->vh_shost; 56211192Ssam /* 56315764Sleres * Demultiplex on packet type 56411192Ssam */ 5657024Ssam switch (vv->vh_type) { 56611192Ssam 5677024Ssam #ifdef INET 5687024Ssam case RING_IP: 5697024Ssam schednetisr(NETISR_IP); 5707024Ssam inq = &ipintrq; 5717024Ssam break; 5727024Ssam #endif 5737024Ssam default: 5747024Ssam printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 5757640Ssam m_freem(m); 5767024Ssam goto setup; 5777024Ssam } 57815794Sleres s = splimp(); 5797640Ssam if (IF_QFULL(inq)) { 5807640Ssam IF_DROP(inq); 5817640Ssam m_freem(m); 58211209Ssam } else 5837640Ssam IF_ENQUEUE(inq, m); 58415764Sleres 58515794Sleres splx(s); 5867024Ssam /* 58715764Sleres * Reset for the next packet. 5887024Ssam */ 58915764Sleres setup: 59015764Sleres ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 59115764Sleres addr->vviba = (u_short) ubainfo; 59215764Sleres addr->vviea = (u_short) (ubainfo >> 16); 59315764Sleres addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 59415764Sleres addr->vvicsr = VV_RST | VV_CONF; 59515764Sleres addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 59615764Sleres return; 59711192Ssam 59811192Ssam /* 59911209Ssam * Drop packet on floor -- count them!! 60011192Ssam */ 6017640Ssam dropit: 6027640Ssam vs->vs_if.if_ierrors++; 6037640Ssam goto setup; 6047024Ssam } 6057024Ssam 6067024Ssam /* 6077024Ssam * V2lni output routine. 6087024Ssam * Encapsulate a packet of type family for the local net. 6097024Ssam * Use trailer local net encapsulation if enough data in first 6107024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 6117024Ssam */ 6127024Ssam vvoutput(ifp, m0, dst) 6137024Ssam struct ifnet *ifp; 6147024Ssam struct mbuf *m0; 6157024Ssam struct sockaddr *dst; 6167024Ssam { 61716581Skarels register struct mbuf *m; 6187024Ssam register struct vv_header *vv; 6197640Ssam register int off; 62016581Skarels register int unit; 62116581Skarels register struct vvreg *addr; 62216581Skarels register struct vv_softc *vs; 62316581Skarels register int s; 62416581Skarels int type, dest, error; 6257024Ssam 62616581Skarels m = m0; 62716581Skarels unit = ifp->if_unit; 62816581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 62916581Skarels vs = &vv_softc[unit]; 63016581Skarels /* 63116581Skarels * Check to see if the input side has wedged. 63216581Skarels * 63316581Skarels * We are lower than device ipl when we enter this routine, 63416581Skarels * so if the interface is ready with an input packet then 63516581Skarels * an input interrupt must have slipped through the cracks. 63616581Skarels * 63716581Skarels * Avoid the race with an input interrupt by watching to see 63816581Skarels * if any packets come in. 63916581Skarels */ 64016581Skarels s = vs->vs_if.if_ipackets; 64116581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 64216581Skarels if (vs->vs_if.if_flags & IFF_DEBUG) 64316581Skarels printf("vv%d: lost a receive interrupt, icsr = %b\n", 64416581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 64516581Skarels s = splimp(); 64616581Skarels vvrint(unit); 64716581Skarels splx(s); 64816581Skarels } 64916581Skarels 6507024Ssam switch (dst->sa_family) { 65111192Ssam 6527024Ssam #ifdef INET 65315764Sleres case AF_INET: 6547640Ssam dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 65511192Ssam if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { 6567640Ssam error = EPERM; 6577640Ssam goto bad; 6587640Ssam } 6597640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 66015764Sleres /* Need per host negotiation. */ 66113090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 66213090Ssam if (off > 0 && (off & 0x1ff) == 0 && 6637640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 6647640Ssam type = RING_IPTrailer + (off>>9); 6657640Ssam m->m_off -= 2 * sizeof (u_short); 6667640Ssam m->m_len += 2 * sizeof (u_short); 6677640Ssam *mtod(m, u_short *) = RING_IP; 6687640Ssam *(mtod(m, u_short *) + 1) = m->m_len; 6697640Ssam goto gottrailertype; 6707640Ssam } 6717024Ssam type = RING_IP; 6727024Ssam off = 0; 6737024Ssam goto gottype; 6747024Ssam #endif 6757024Ssam default: 67616581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 6777640Ssam error = EAFNOSUPPORT; 6787640Ssam goto bad; 6797024Ssam } 6807024Ssam 6817024Ssam gottrailertype: 6827024Ssam /* 6837024Ssam * Packet to be sent as trailer: move first packet 6847024Ssam * (control information) to end of chain. 6857024Ssam */ 6867024Ssam while (m->m_next) 6877024Ssam m = m->m_next; 6887024Ssam m->m_next = m0; 6897024Ssam m = m0->m_next; 6907024Ssam m0->m_next = 0; 6917024Ssam m0 = m; 6927024Ssam gottype: 6937024Ssam /* 6947024Ssam * Add local net header. If no space in first mbuf, 6957024Ssam * allocate another. 6967024Ssam */ 6977024Ssam if (m->m_off > MMAXOFF || 6987024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 69911209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 70011209Ssam if (m == NULL) { 7017640Ssam error = ENOBUFS; 7027640Ssam goto bad; 7037024Ssam } 7047024Ssam m->m_next = m0; 7057024Ssam m->m_off = MMINOFF; 7067024Ssam m->m_len = sizeof (struct vv_header); 7077024Ssam } else { 7087024Ssam m->m_off -= sizeof (struct vv_header); 7097024Ssam m->m_len += sizeof (struct vv_header); 7107024Ssam } 7117024Ssam vv = mtod(m, struct vv_header *); 7127024Ssam vv->vh_shost = ifp->if_host[0]; 71315764Sleres /* Map the destination address if it's a broadcast */ 71415764Sleres if ((vv->vh_dhost = dest) == INADDR_ANY) 71515764Sleres vv->vh_dhost = VV_BROADCAST; 7167024Ssam vv->vh_version = RING_VERSION; 7177024Ssam vv->vh_type = type; 7187640Ssam vv->vh_info = off; 71911192Ssam vvtracehdr("vo", vv); 7207024Ssam 7217024Ssam /* 7227024Ssam * Queue message on interface, and start output if interface 7237024Ssam * not yet active. 7247024Ssam */ 7257024Ssam s = splimp(); 7267640Ssam if (IF_QFULL(&ifp->if_snd)) { 7277640Ssam IF_DROP(&ifp->if_snd); 7287640Ssam error = ENOBUFS; 7297640Ssam goto qfull; 7307640Ssam } 7317024Ssam IF_ENQUEUE(&ifp->if_snd, m); 73216581Skarels if (vs->vs_oactive == 0) 73316581Skarels vvstart(unit); 7347024Ssam splx(s); 7357640Ssam return (0); 7367640Ssam qfull: 7377640Ssam m0 = m; 7387640Ssam splx(s); 7397640Ssam bad: 7407640Ssam m_freem(m0); 7417640Ssam return(error); 7427024Ssam } 7437024Ssam 7447024Ssam /* 74513057Ssam * Process an ioctl request. 74613057Ssam */ 74713057Ssam vvioctl(ifp, cmd, data) 74813057Ssam register struct ifnet *ifp; 74913057Ssam int cmd; 75013057Ssam caddr_t data; 75113057Ssam { 75216581Skarels register struct ifreq *ifr; 75316581Skarels register int s; 75416581Skarels int error; 75513057Ssam 75615764Sleres ifr = (struct ifreq *)data; 75715764Sleres error = 0; 75815764Sleres s = splimp(); 75913057Ssam switch (cmd) { 76013057Ssam 76113057Ssam case SIOCSIFADDR: 76216581Skarels if (ifp->if_flags & IFF_RUNNING) 76316581Skarels if_rtinit(ifp, -1); /* delete previous route */ 76416581Skarels vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 76516581Skarels if (ifp->if_flags & IFF_RUNNING) 76616581Skarels if_rtinit(ifp, RTF_UP); 76716581Skarels else 76813057Ssam vvinit(ifp->if_unit); 76913057Ssam break; 77013057Ssam 77113057Ssam default: 77213057Ssam error = EINVAL; 77313057Ssam } 77413057Ssam splx(s); 77516581Skarels return(error); 77613057Ssam } 77713057Ssam 77813057Ssam /* 77915764Sleres * Set up the address for this interface. We use the network number 78015794Sleres * from the passed address and an invalid host number; vvinit() will 78115794Sleres * figure out the host number and insert it later. 78215764Sleres */ 78315764Sleres vvsetaddr(ifp, sin) 78415764Sleres register struct ifnet *ifp; 78515764Sleres register struct sockaddr_in *sin; 78615764Sleres { 78715764Sleres ifp->if_net = in_netof(sin->sin_addr); 78815764Sleres ifp->if_host[0] = 256; /* an invalid host number */ 78915764Sleres sin = (struct sockaddr_in *)&ifp->if_addr; 79015764Sleres sin->sin_family = AF_INET; 79115764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 79215764Sleres sin = (struct sockaddr_in *)&ifp->if_broadaddr; 79315764Sleres sin->sin_family = AF_INET; 79415764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 79515764Sleres ifp->if_flags |= IFF_BROADCAST; 79615764Sleres } 79715764Sleres 79815764Sleres /* 7997024Ssam * vvprt_hdr(s, v) print the local net header in "v" 80015764Sleres * with title is "s" 8017024Ssam */ 8027024Ssam vvprt_hdr(s, v) 8037024Ssam char *s; 8047024Ssam register struct vv_header *v; 8057024Ssam { 8067024Ssam printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 8077024Ssam s, 8087024Ssam 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 8097024Ssam 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 8107024Ssam 0xffff & (int)(v->vh_info)); 8117024Ssam } 8127024Ssam 81312774Ssam #ifdef notdef 8147024Ssam /* 8157024Ssam * print "l" hex bytes starting at "s" 8167024Ssam */ 81715764Sleres vvprt_hex(s, l) 8187024Ssam char *s; 8197024Ssam int l; 8207024Ssam { 8217024Ssam register int i; 8227024Ssam register int z; 8237024Ssam 8247024Ssam for (i=0 ; i < l; i++) { 8257024Ssam z = 0xff & (int)(*(s + i)); 8267024Ssam printf("%c%c ", 8277024Ssam "0123456789abcdef"[(z >> 4) & 0x0f], 8287024Ssam "0123456789abcdef"[z & 0x0f] 8297024Ssam ); 8307024Ssam } 8317024Ssam } 83212774Ssam #endif 833