1*15764Sleres /* if_vv.c 6.2 83/12/22 */ 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" 2211209Ssam #include "../h/time.h" 2311209Ssam #include "../h/kernel.h" 2413057Ssam #include "../h/ioctl.h" 258465Sroot 268465Sroot #include "../net/if.h" 2711209Ssam #include "../net/netisr.h" 288465Sroot #include "../net/route.h" 2911192Ssam 308421Swnj #include "../netinet/in.h" 318421Swnj #include "../netinet/in_systm.h" 328421Swnj #include "../netinet/ip.h" 338421Swnj #include "../netinet/ip_var.h" 348465Sroot 3511209Ssam #include "../vax/mtpr.h" 3611209Ssam #include "../vax/cpu.h" 3711192Ssam 388465Sroot #include "../vaxuba/ubareg.h" 398465Sroot #include "../vaxuba/ubavar.h" 407024Ssam 4111209Ssam #include "../vaxif/if_vv.h" 4211209Ssam #include "../vaxif/if_uba.h" 4311209Ssam 447024Ssam /* 457024Ssam * N.B. - if WIRECENTER is defined wrong, it can well break 467024Ssam * the hardware!! 477024Ssam */ 487024Ssam #define WIRECENTER 497024Ssam 507024Ssam #ifdef WIRECENTER 517024Ssam #define VV_CONF VV_HEN /* drive wire center relay */ 527024Ssam #else 537024Ssam #define VV_CONF VV_STE /* allow operation without wire center */ 547024Ssam #endif 557024Ssam 567024Ssam #define VVMTU (1024+512) 577640Ssam #define VVMRU (1024+512+16) /* space for trailer */ 587024Ssam 59*15764Sleres extern struct ifnet loif; /* loopback */ 60*15764Sleres 6113057Ssam int vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */ 62*15764Sleres vv_logreaderrors = 1; /* 1 => log all read errors */ 637640Ssam 6411192Ssam #define vvtracehdr if (vv_tracehdr) vvprt_hdr 6511192Ssam 667024Ssam int vvprobe(), vvattach(), vvrint(), vvxint(); 677024Ssam struct uba_device *vvinfo[NVV]; 687024Ssam u_short vvstd[] = { 0 }; 697024Ssam struct uba_driver vvdriver = 707024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 717024Ssam #define VVUNIT(x) minor(x) 72*15764Sleres int vvinit(),vvioctl(),vvoutput(),vvreset(),vvsetaddr(); 737024Ssam 747024Ssam /* 757024Ssam * Software status of each interface. 767024Ssam * 777024Ssam * Each interface is referenced by a network interface structure, 787024Ssam * vs_if, which the routing code uses to locate the interface. 797024Ssam * This structure contains the output queue for the interface, its address, ... 807024Ssam * We also have, for each interface, a UBA interface structure, which 817024Ssam * contains information about the UNIBUS resources held by the interface: 827024Ssam * map registers, buffered data paths, etc. Information is cached in this 837024Ssam * structure for use by the if_uba.c routines in running the interface 847024Ssam * efficiently. 857024Ssam */ 867024Ssam struct vv_softc { 877024Ssam struct ifnet vs_if; /* network-visible interface */ 887024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 8911192Ssam short vs_oactive; /* is output active */ 907024Ssam short vs_olen; /* length of last output */ 917024Ssam u_short vs_lastx; /* last destination address */ 9211192Ssam short vs_tries; /* transmit current retry count */ 937024Ssam short vs_init; /* number of ring inits */ 947024Ssam short vs_nottaken; /* number of packets refused */ 957024Ssam } vv_softc[NVV]; 967024Ssam 977024Ssam vvprobe(reg) 987024Ssam caddr_t reg; 997024Ssam { 1007024Ssam register int br, cvec; 1017024Ssam register struct vvreg *addr = (struct vvreg *)reg; 1027024Ssam 1037024Ssam #ifdef lint 104*15764Sleres br = 0; cvec = br; br = cvec; 1057024Ssam #endif 1067024Ssam /* reset interface, enable, and wait till dust settles */ 1077024Ssam addr->vvicsr = VV_RST; 1087024Ssam addr->vvocsr = VV_RST; 109*15764Sleres DELAY(100000); 1107024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1117024Ssam addr->vvocsr = VV_IEN; /* enable interrupt */ 1127024Ssam addr->vvoba = 0; /* low 16 bits */ 1137024Ssam addr->vvoea = 0; /* extended bits */ 1147024Ssam addr->vvowc = -1; /* for 1 word */ 1157024Ssam addr->vvocsr |= VV_DEN; /* start the DMA */ 1167024Ssam DELAY(100000); 1177024Ssam addr->vvocsr = 0; 1187024Ssam if (cvec && cvec != 0x200) 119*15764Sleres cvec -= 4; /* backup so vector => receive */ 1207024Ssam return(1); 1217024Ssam } 1227024Ssam 1237024Ssam /* 1247024Ssam * Interface exists: make available by filling in network interface 1257024Ssam * record. System will initialize the interface when it is ready 1267024Ssam * to accept packets. 1277024Ssam */ 1287024Ssam vvattach(ui) 1297024Ssam struct uba_device *ui; 1307024Ssam { 131*15764Sleres register struct vv_softc *vs; 1327024Ssam 133*15764Sleres vs = &vv_softc[ui->ui_unit]; 1347024Ssam vs->vs_if.if_unit = ui->ui_unit; 1357024Ssam vs->vs_if.if_name = "vv"; 1367024Ssam vs->vs_if.if_mtu = VVMTU; 1377024Ssam vs->vs_if.if_init = vvinit; 13813057Ssam vs->vs_if.if_ioctl = vvioctl; 1397024Ssam vs->vs_if.if_output = vvoutput; 14011209Ssam vs->vs_if.if_reset = vvreset; 1417640Ssam vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 14212354Smo #if defined(VAX750) 14312354Smo /* don't chew up 750 bdp's */ 14412354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 14512354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 14612354Smo #endif 1477024Ssam if_attach(&vs->vs_if); 1487024Ssam } 1497024Ssam 1507024Ssam /* 1517024Ssam * Reset of interface after UNIBUS reset. 1527024Ssam * If interface is on specified uba, reset its state. 1537024Ssam */ 1547024Ssam vvreset(unit, uban) 1557024Ssam int unit, uban; 1567024Ssam { 1577024Ssam register struct uba_device *ui; 1587024Ssam 1597024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 1607024Ssam ui->ui_ubanum != uban) 1617024Ssam return; 1627024Ssam printf(" vv%d", unit); 1637024Ssam vvinit(unit); 1647024Ssam } 1657024Ssam 1667024Ssam /* 1677024Ssam * Initialization of interface; clear recorded pending 1687024Ssam * operations, and reinitialize UNIBUS usage. 1697024Ssam */ 1707024Ssam vvinit(unit) 1717024Ssam int unit; 1727024Ssam { 173*15764Sleres register struct vv_softc *vs; 174*15764Sleres register struct uba_device *ui; 1757024Ssam register struct vvreg *addr; 1767024Ssam struct sockaddr_in *sin; 1777640Ssam int ubainfo, s; 1787024Ssam 179*15764Sleres vs = &vv_softc[unit]; 180*15764Sleres ui = vvinfo[unit]; 181*15764Sleres sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 182*15764Sleres /* 183*15764Sleres * If the network number is still zero, we've been 184*15764Sleres * called too soon. 185*15764Sleres */ 186*15764Sleres if (in_netof(sin->sin_addr) == 0) 18713057Ssam return; 1887640Ssam addr = (struct vvreg *)ui->ui_addr; 1897024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 190*15764Sleres sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 1917024Ssam printf("vv%d: can't initialize\n", unit); 1927640Ssam vs->vs_if.if_flags &= ~IFF_UP; 1937024Ssam return; 1947024Ssam } 1957024Ssam /* 196*15764Sleres * Now that the uba is set up, figure out our address and 197*15764Sleres * update complete our host address. 1987640Ssam */ 1997640Ssam vs->vs_if.if_host[0] = vvidentify(unit); 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; 2107640Ssam /* 2117640Ssam * Hang a receive and start any 2127640Ssam * pending writes by faking a transmit complete. 2137640Ssam */ 2147640Ssam s = splimp(); 2157640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 21613057Ssam addr->vviba = (u_short)ubainfo; 21713057Ssam addr->vviea = (u_short)(ubainfo >> 16); 2187640Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2197640Ssam addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 2207640Ssam vs->vs_oactive = 1; 22113057Ssam vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; 2227640Ssam vvxint(unit); 2237640Ssam splx(s); 2247640Ssam if_rtinit(&vs->vs_if, RTF_UP); 2257640Ssam } 2267640Ssam 2277640Ssam /* 228*15764Sleres * Return our host address. 2297640Ssam */ 23011209Ssam vvidentify(unit) 23113057Ssam int unit; 23211209Ssam { 233*15764Sleres register struct vv_softc *vs; 234*15764Sleres register struct uba_device *ui; 2357640Ssam register struct vvreg *addr; 2367640Ssam struct mbuf *m; 2377640Ssam struct vv_header *v; 23812774Ssam int ubainfo, attempts, waitcount; 2397640Ssam 2407640Ssam /* 2417024Ssam * Build a multicast message to identify our address 2427024Ssam */ 243*15764Sleres vs = &vv_softc[unit]; 244*15764Sleres ui = vvinfo[unit]; 2457640Ssam addr = (struct vvreg *)ui->ui_addr; 2467024Ssam attempts = 0; /* total attempts, including bad msg type */ 24711209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 24812774Ssam if (m == NULL) 24913057Ssam return (0); 25011192Ssam m->m_next = 0; 2517024Ssam m->m_off = MMINOFF; 2527024Ssam m->m_len = sizeof(struct vv_header); 2537024Ssam v = mtod(m, struct vv_header *); 25411192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 2557024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 2567024Ssam v->vh_version = RING_VERSION; 2577024Ssam v->vh_type = RING_WHOAMI; 2587024Ssam v->vh_info = 0; 25911192Ssam /* map xmit message into uba */ 2607640Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 2617640Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 2627640Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 2637024Ssam /* 2647024Ssam * Reset interface, establish Digital Loopback Mode, and 2657024Ssam * send the multicast (to myself) with Input Copy enabled. 2667024Ssam */ 2677024Ssam retry: 2687024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 2697024Ssam addr->vvicsr = VV_RST; 2707024Ssam addr->vviba = (u_short) ubainfo; 2717024Ssam addr->vviea = (u_short) (ubainfo >> 16); 2727024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2737024Ssam addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 2747640Ssam 2757640Ssam /* let flag timers fire so ring will initialize */ 276*15764Sleres DELAY(2000000); /* about 2 SECONDS on a 780!! */ 2777640Ssam 2787024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2797024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 2807024Ssam addr->vvoba = (u_short) ubainfo; 2817024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 2827024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 2837024Ssam addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 2847024Ssam /* 2857024Ssam * Wait for receive side to finish. 28611192Ssam * Extract source address (which will our own), 2877024Ssam * and post to interface structure. 2887024Ssam */ 289*15764Sleres DELAY(10000); 29011192Ssam for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { 2919876Ssam if (waitcount < 10) { 2927024Ssam DELAY(1000); 29311209Ssam continue; 29411192Ssam } 29511209Ssam if (attempts++ >= 10) { 29611209Ssam printf("vv%d: can't initialize\n", unit); 29711209Ssam printf("vvinit loopwait: icsr = %b\n", 29811209Ssam 0xffff&(addr->vvicsr), VV_IBITS); 29911209Ssam vs->vs_if.if_flags &= ~IFF_UP; 30012774Ssam return (0); 3017024Ssam } 30211209Ssam goto retry; 30311192Ssam } 3047024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3057024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3067024Ssam if (vs->vs_ifuba.ifu_xtofree) 3077024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 3087024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3097024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 3107024Ssam m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 31111209Ssam if (m != NULL) 3127024Ssam m_freem(m); 3137024Ssam /* 31411209Ssam * Check message type before we believe the source host address 3157024Ssam */ 3167024Ssam v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 31711209Ssam if (v->vh_type != RING_WHOAMI) 3187640Ssam goto retry; 31911209Ssam return(v->vh_shost); 3207024Ssam } 3217024Ssam 3227024Ssam /* 3237024Ssam * Start or restart output on interface. 32411192Ssam * If interface is active, this is a retransmit, so just 32511192Ssam * restuff registers and go. 3267024Ssam * If interface is not already active, get another datagram 3277024Ssam * to send off of the interface queue, and map it to the interface 3287024Ssam * before starting the output. 3297024Ssam */ 3307024Ssam vvstart(dev) 3317024Ssam dev_t dev; 3327024Ssam { 3337024Ssam int unit = VVUNIT(dev); 334*15764Sleres struct uba_device *ui; 335*15764Sleres register struct vv_softc *vs; 3367024Ssam register struct vvreg *addr; 3377024Ssam struct mbuf *m; 33811192Ssam int ubainfo; 33911192Ssam int dest; 3407024Ssam 341*15764Sleres ui = vvinfo[unit]; 342*15764Sleres vs = &vv_softc[unit]; 3437024Ssam if (vs->vs_oactive) 3447024Ssam goto restart; 3457024Ssam /* 3467024Ssam * Not already active: dequeue another request 3477024Ssam * and map it to the UNIBUS. If no more requests, 3487024Ssam * just return. 3497024Ssam */ 3507024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 35111209Ssam if (m == NULL) { 3527024Ssam vs->vs_oactive = 0; 3537024Ssam return; 3547024Ssam } 3557024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 3567024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 3577024Ssam vs->vs_lastx = dest; 3587024Ssam restart: 3597024Ssam /* 3607024Ssam * Have request mapped to UNIBUS for transmission. 3617024Ssam * Purge any stale data from this BDP, and start the otput. 3627024Ssam */ 363*15764Sleres /* 364*15764Sleres * The following test is questionable and isn't done in 365*15764Sleres * the en driver... 366*15764Sleres */ 36712363Ssam if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { 36811192Ssam printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); 36911192Ssam panic("vvdriver vs_olen botch"); 37011192Ssam } 3717024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3727024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3737024Ssam addr = (struct vvreg *)ui->ui_addr; 3747024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 3757024Ssam addr->vvoba = (u_short) ubainfo; 3767024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 3777024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 3787024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 3797024Ssam vs->vs_oactive = 1; 3807024Ssam } 3817024Ssam 3827024Ssam /* 3837024Ssam * VVLNI transmit interrupt 3847024Ssam * Start another output if more data to send. 3857024Ssam */ 3867024Ssam vvxint(unit) 3877024Ssam int unit; 3887024Ssam { 389*15764Sleres register struct uba_device *ui; 390*15764Sleres register struct vv_softc *vs; 3917024Ssam register struct vvreg *addr; 3927024Ssam register int oc; 3937024Ssam 394*15764Sleres ui = vvinfo[unit]; 395*15764Sleres vs = &vv_softc[unit]; 3967024Ssam addr = (struct vvreg *)ui->ui_addr; 3977024Ssam oc = 0xffff & (addr->vvocsr); 3987024Ssam if (vs->vs_oactive == 0) { 39911192Ssam printf("vv%d: stray interrupt vvocsr = %b\n", unit, 400*15764Sleres oc, VV_OBITS); 4017024Ssam return; 4027024Ssam } 4037024Ssam if (oc & (VV_OPT | VV_RFS)) { 4047640Ssam vs->vs_if.if_collisions++; 40511192Ssam if (vs->vs_tries++ < VVRETRY) { 4067024Ssam if (oc & VV_OPT) 4077024Ssam vs->vs_init++; 4087024Ssam if (oc & VV_RFS) 4097024Ssam vs->vs_nottaken++; 41011192Ssam vvstart(unit); /* restart this message */ 4117024Ssam return; 4127024Ssam } 4137024Ssam if (oc & VV_OPT) 414*15764Sleres printf("vv%d: output timeout\n", unit); 4157024Ssam } 4167024Ssam vs->vs_if.if_opackets++; 4177024Ssam vs->vs_oactive = 0; 4187024Ssam vs->vs_tries = 0; 4197024Ssam if (oc & VVXERR) { 4207024Ssam vs->vs_if.if_oerrors++; 42111192Ssam printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 422*15764Sleres VV_OBITS); 4237024Ssam } 4247024Ssam if (vs->vs_ifuba.ifu_xtofree) { 4257024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 4267024Ssam vs->vs_ifuba.ifu_xtofree = 0; 4277024Ssam } 4287024Ssam if (vs->vs_if.if_snd.ifq_head == 0) { 42911192Ssam vs->vs_lastx = 256; /* an invalid address */ 4307024Ssam return; 4317024Ssam } 4327024Ssam vvstart(unit); 4337024Ssam } 4347024Ssam 4357024Ssam /* 4367024Ssam * V2lni interface receiver interrupt. 4377024Ssam * If input error just drop packet. 438*15764Sleres * Otherwise purge input buffered data path and examine 4397024Ssam * packet to determine type. If can't determine length 440*15764Sleres * from type, then have to drop packet. Otherwise decapsulate 4417024Ssam * packet based on type and pass to type specific higher-level 4427024Ssam * input routine. 4437024Ssam */ 4447024Ssam vvrint(unit) 4457024Ssam int unit; 4467024Ssam { 447*15764Sleres register struct vv_softc *vs; 448*15764Sleres struct vvreg *addr; 4497024Ssam register struct vv_header *vv; 4507024Ssam register struct ifqueue *inq; 451*15764Sleres struct mbuf *m; 4527024Ssam int ubainfo, len, off; 4537640Ssam short resid; 4547024Ssam 455*15764Sleres vs = &vv_softc[unit]; 456*15764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 4577024Ssam vs->vs_if.if_ipackets++; 4587024Ssam /* 4597024Ssam * Purge BDP; drop if input error indicated. 4607024Ssam */ 4617024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 4627024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 4637024Ssam if (addr->vvicsr & VVRERR) { 464*15764Sleres if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors) 46511192Ssam printf("vv%d: error vvicsr = %b\n", unit, 466*15764Sleres 0xffff&(addr->vvicsr), VV_IBITS); 4677640Ssam goto dropit; 4687024Ssam } 4697640Ssam 4707024Ssam /* 4717640Ssam * Get packet length from word count residue 4727640Ssam * 4737640Ssam * Compute header offset if trailer protocol 4747640Ssam * 4757640Ssam * Pull packet off interface. Off is nonzero if packet 4767640Ssam * has trailing header; if_rubaget will then force this header 4777640Ssam * information to be at the front. The vh_info field 4787640Ssam * carries the offset to the trailer data in trailer 4797640Ssam * format packets. 4807024Ssam */ 4817640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 48211192Ssam vvtracehdr("vi", vv); 4837640Ssam resid = addr->vviwc; 4847640Ssam if (resid) 4857640Ssam resid |= 0176000; /* ugly!!!! */ 4867640Ssam len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 4877640Ssam len -= sizeof(struct vv_header); 48811192Ssam if (len > VVMRU || len <= 0) 4897640Ssam goto dropit; 4907640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 49113057Ssam if (vv->vh_type >= RING_IPTrailer && 49213057Ssam vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { 4937640Ssam off = (vv->vh_type - RING_IPTrailer) * 512; 4947640Ssam if (off > VVMTU) 4957640Ssam goto dropit; 4967640Ssam vv->vh_type = *vvdataaddr(vv, off, u_short *); 4977640Ssam resid = *(vvdataaddr(vv, off+2, u_short *)); 4987640Ssam if (off + resid > len) 4997640Ssam goto dropit; 5007640Ssam len = off + resid; 50111209Ssam } else 5027640Ssam off = 0; 5037640Ssam if (len == 0) 5047640Ssam goto dropit; 5057640Ssam m = if_rubaget(&vs->vs_ifuba, len, off); 50611209Ssam if (m == NULL) 5077640Ssam goto dropit; 5087640Ssam if (off) { 5097640Ssam m->m_off += 2 * sizeof(u_short); 5107640Ssam m->m_len -= 2 * sizeof(u_short); 5117640Ssam } 51211192Ssam 51311192Ssam /* 514*15764Sleres * Demultiplex on packet type 51511192Ssam */ 5167024Ssam switch (vv->vh_type) { 51711192Ssam 5187024Ssam #ifdef INET 5197024Ssam case RING_IP: 5207024Ssam schednetisr(NETISR_IP); 5217024Ssam inq = &ipintrq; 5227024Ssam break; 5237024Ssam #endif 5247024Ssam default: 5257024Ssam printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 5267640Ssam m_freem(m); 5277024Ssam goto setup; 5287024Ssam } 5297640Ssam if (IF_QFULL(inq)) { 5307640Ssam IF_DROP(inq); 5317640Ssam m_freem(m); 53211209Ssam } else 5337640Ssam IF_ENQUEUE(inq, m); 534*15764Sleres 5357024Ssam /* 536*15764Sleres * Reset for the next packet. 5377024Ssam */ 538*15764Sleres setup: 539*15764Sleres ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 540*15764Sleres addr->vviba = (u_short) ubainfo; 541*15764Sleres addr->vviea = (u_short) (ubainfo >> 16); 542*15764Sleres addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 543*15764Sleres addr->vvicsr = VV_RST | VV_CONF; 544*15764Sleres addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 545*15764Sleres return; 54611192Ssam 54711192Ssam /* 54811209Ssam * Drop packet on floor -- count them!! 54911192Ssam */ 5507640Ssam dropit: 5517640Ssam vs->vs_if.if_ierrors++; 552*15764Sleres if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors) 553*15764Sleres printf("vv%d: error vvicsr = %b\n", unit, 554*15764Sleres 0xffff&(addr->vvicsr), VV_IBITS); 5557640Ssam goto setup; 5567024Ssam } 5577024Ssam 5587024Ssam /* 5597024Ssam * V2lni output routine. 5607024Ssam * Encapsulate a packet of type family for the local net. 5617024Ssam * Use trailer local net encapsulation if enough data in first 5627024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 5637024Ssam */ 5647024Ssam vvoutput(ifp, m0, dst) 5657024Ssam struct ifnet *ifp; 5667024Ssam struct mbuf *m0; 5677024Ssam struct sockaddr *dst; 5687024Ssam { 5697024Ssam register struct mbuf *m = m0; 5707024Ssam register struct vv_header *vv; 5717640Ssam register int off; 5727640Ssam int type, dest, s, error; 5737024Ssam 5747024Ssam switch (dst->sa_family) { 57511192Ssam 5767024Ssam #ifdef INET 577*15764Sleres case AF_INET: 5787640Ssam dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 579*15764Sleres /* Check if the loopback can be used */ 580*15764Sleres if ((dest == 581*15764Sleres ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr) && 582*15764Sleres ((loif.if_flags & IFF_UP) != 0)) 583*15764Sleres return(looutput(&loif, m0, dst)); 58411192Ssam if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { 5857640Ssam error = EPERM; 5867640Ssam goto bad; 5877640Ssam } 5887640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 589*15764Sleres /* Need per host negotiation. */ 59013090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 59113090Ssam if (off > 0 && (off & 0x1ff) == 0 && 5927640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 5937640Ssam type = RING_IPTrailer + (off>>9); 5947640Ssam m->m_off -= 2 * sizeof (u_short); 5957640Ssam m->m_len += 2 * sizeof (u_short); 5967640Ssam *mtod(m, u_short *) = RING_IP; 5977640Ssam *(mtod(m, u_short *) + 1) = m->m_len; 5987640Ssam goto gottrailertype; 5997640Ssam } 6007024Ssam type = RING_IP; 6017024Ssam off = 0; 6027024Ssam goto gottype; 6037024Ssam #endif 6047024Ssam default: 6057024Ssam printf("vv%d: can't handle af%d\n", ifp->if_unit, 6067024Ssam dst->sa_family); 6077640Ssam error = EAFNOSUPPORT; 6087640Ssam goto bad; 6097024Ssam } 6107024Ssam 6117024Ssam gottrailertype: 6127024Ssam /* 6137024Ssam * Packet to be sent as trailer: move first packet 6147024Ssam * (control information) to end of chain. 6157024Ssam */ 6167024Ssam while (m->m_next) 6177024Ssam m = m->m_next; 6187024Ssam m->m_next = m0; 6197024Ssam m = m0->m_next; 6207024Ssam m0->m_next = 0; 6217024Ssam m0 = m; 6227024Ssam gottype: 6237024Ssam /* 6247024Ssam * Add local net header. If no space in first mbuf, 6257024Ssam * allocate another. 6267024Ssam */ 6277024Ssam if (m->m_off > MMAXOFF || 6287024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 62911209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 63011209Ssam if (m == NULL) { 6317640Ssam error = ENOBUFS; 6327640Ssam goto bad; 6337024Ssam } 6347024Ssam m->m_next = m0; 6357024Ssam m->m_off = MMINOFF; 6367024Ssam m->m_len = sizeof (struct vv_header); 6377024Ssam } else { 6387024Ssam m->m_off -= sizeof (struct vv_header); 6397024Ssam m->m_len += sizeof (struct vv_header); 6407024Ssam } 6417024Ssam vv = mtod(m, struct vv_header *); 6427024Ssam vv->vh_shost = ifp->if_host[0]; 643*15764Sleres /* Map the destination address if it's a broadcast */ 644*15764Sleres if ((vv->vh_dhost = dest) == INADDR_ANY) 645*15764Sleres vv->vh_dhost = VV_BROADCAST; 6467024Ssam vv->vh_version = RING_VERSION; 6477024Ssam vv->vh_type = type; 6487640Ssam vv->vh_info = off; 64911192Ssam vvtracehdr("vo", vv); 6507024Ssam 6517024Ssam /* 6527024Ssam * Queue message on interface, and start output if interface 6537024Ssam * not yet active. 6547024Ssam */ 6557024Ssam s = splimp(); 6567640Ssam if (IF_QFULL(&ifp->if_snd)) { 6577640Ssam IF_DROP(&ifp->if_snd); 6587640Ssam error = ENOBUFS; 6597640Ssam goto qfull; 6607640Ssam } 6617024Ssam IF_ENQUEUE(&ifp->if_snd, m); 6627024Ssam if (vv_softc[ifp->if_unit].vs_oactive == 0) 6637024Ssam vvstart(ifp->if_unit); 6647024Ssam splx(s); 6657640Ssam return (0); 6667640Ssam qfull: 6677640Ssam m0 = m; 6687640Ssam splx(s); 6697640Ssam bad: 6707640Ssam m_freem(m0); 6717640Ssam return(error); 6727024Ssam } 6737024Ssam 6747024Ssam /* 67513057Ssam * Process an ioctl request. 67613057Ssam */ 67713057Ssam vvioctl(ifp, cmd, data) 67813057Ssam register struct ifnet *ifp; 67913057Ssam int cmd; 68013057Ssam caddr_t data; 68113057Ssam { 682*15764Sleres struct ifreq *ifr; 683*15764Sleres int s, error; 68413057Ssam 685*15764Sleres ifr = (struct ifreq *)data; 686*15764Sleres error = 0; 687*15764Sleres s = splimp(); 68813057Ssam switch (cmd) { 68913057Ssam 69013057Ssam case SIOCSIFADDR: 69113057Ssam /* too difficult to change addr while running */ 69213057Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 693*15764Sleres vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 69413057Ssam vvinit(ifp->if_unit); 69513057Ssam } else 69613057Ssam error = EINVAL; 69713057Ssam break; 69813057Ssam 69913057Ssam default: 70013057Ssam error = EINVAL; 70113057Ssam } 70213057Ssam splx(s); 70313057Ssam return (error); 70413057Ssam } 70513057Ssam 70613057Ssam /* 707*15764Sleres * Set up the address for this interface. We use the network number 708*15764Sleres * from the passed address and an invalid host number because vvinit() 709*15764Sleres * is smart enough to figure out the host number out. 710*15764Sleres */ 711*15764Sleres vvsetaddr(ifp, sin) 712*15764Sleres register struct ifnet *ifp; 713*15764Sleres register struct sockaddr_in *sin; 714*15764Sleres { 715*15764Sleres ifp->if_net = in_netof(sin->sin_addr); 716*15764Sleres ifp->if_host[0] = 256; /* an invalid host number */ 717*15764Sleres sin = (struct sockaddr_in *)&ifp->if_addr; 718*15764Sleres sin->sin_family = AF_INET; 719*15764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 720*15764Sleres sin = (struct sockaddr_in *)&ifp->if_broadaddr; 721*15764Sleres sin->sin_family = AF_INET; 722*15764Sleres sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 723*15764Sleres ifp->if_flags |= IFF_BROADCAST; 724*15764Sleres } 725*15764Sleres 726*15764Sleres /* 7277024Ssam * vvprt_hdr(s, v) print the local net header in "v" 728*15764Sleres * with title is "s" 7297024Ssam */ 7307024Ssam vvprt_hdr(s, v) 7317024Ssam char *s; 7327024Ssam register struct vv_header *v; 7337024Ssam { 7347024Ssam printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 7357024Ssam s, 7367024Ssam 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 7377024Ssam 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 7387024Ssam 0xffff & (int)(v->vh_info)); 7397024Ssam } 7407024Ssam 74112774Ssam #ifdef notdef 7427024Ssam /* 7437024Ssam * print "l" hex bytes starting at "s" 7447024Ssam */ 745*15764Sleres vvprt_hex(s, l) 7467024Ssam char *s; 7477024Ssam int l; 7487024Ssam { 7497024Ssam register int i; 7507024Ssam register int z; 7517024Ssam 7527024Ssam for (i=0 ; i < l; i++) { 7537024Ssam z = 0xff & (int)(*(s + i)); 7547024Ssam printf("%c%c ", 7557024Ssam "0123456789abcdef"[(z >> 4) & 0x0f], 7567024Ssam "0123456789abcdef"[z & 0x0f] 7577024Ssam ); 7587024Ssam } 7597024Ssam } 76012774Ssam #endif 761