1*9876Ssam /* if_vv.c 4.12 82/12/23 */ 27024Ssam 39799Ssam #include "vv.h" 49799Ssam #if NVV > 0 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. 107024Ssam */ 119799Ssam #include "../machine/pte.h" 129799Ssam 137024Ssam #include "../h/param.h" 147024Ssam #include "../h/systm.h" 157024Ssam #include "../h/mbuf.h" 167024Ssam #include "../h/buf.h" 177024Ssam #include "../h/protosw.h" 187024Ssam #include "../h/socket.h" 197024Ssam #include "../h/vmmac.h" 20*9876Ssam #include <time.h> 21*9876Ssam #include "../h/kernel.h" 228465Sroot #include <errno.h> 238465Sroot 248465Sroot #include "../net/if.h" 25*9876Ssam #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 328465Sroot #include "../vax/cpu.h" 338465Sroot #include "../vax/mtpr.h" 348421Swnj #include "../vaxif/if_vv.h" 358421Swnj #include "../vaxif/if_uba.h" 368465Sroot #include "../vaxuba/ubareg.h" 378465Sroot #include "../vaxuba/ubavar.h" 387024Ssam 397024Ssam #include "vv.h" 407024Ssam 417024Ssam /* 427024Ssam * N.B. - if WIRECENTER is defined wrong, it can well break 437024Ssam * the hardware!! 447024Ssam */ 457640Ssam 467024Ssam #define WIRECENTER 477024Ssam 487024Ssam #ifdef WIRECENTER 497024Ssam #define VV_CONF VV_HEN /* drive wire center relay */ 507024Ssam #else 517024Ssam #define VV_CONF VV_STE /* allow operation without wire center */ 527024Ssam #endif 537024Ssam 547024Ssam #define VVMTU (1024+512) 557640Ssam #define VVMRU (1024+512+16) /* space for trailer */ 567024Ssam 577640Ssam int vv_dotrailer = 1, /* so can do trailers selectively */ 587640Ssam vv_trace = 0; 597640Ssam 607024Ssam int vvprobe(), vvattach(), vvrint(), vvxint(); 617024Ssam struct uba_device *vvinfo[NVV]; 627024Ssam u_short vvstd[] = { 0 }; 637024Ssam struct uba_driver vvdriver = 647024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 657024Ssam #define VVUNIT(x) minor(x) 667024Ssam int vvinit(),vvoutput(),vvreset(); 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 */ 837024Ssam short vs_oactive; /* is output active? */ 847024Ssam short vs_olen; /* length of last output */ 857024Ssam u_short vs_lastx; /* last destination address */ 867024Ssam short vs_tries; /* current retry count */ 877024Ssam short vs_init; /* number of ring inits */ 887024Ssam short vs_flush; /* number of flushed packets */ 897024Ssam short vs_nottaken; /* number of packets refused */ 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 997024Ssam 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; 1047024Ssam 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) 1147024Ssam cvec -= 4; /* backup so vector => recieve */ 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 { 1267024Ssam register struct vv_softc *vs = &vv_softc[ui->ui_unit]; 1277024Ssam register struct sockaddr_in *sin; 1287024Ssam 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_net = ui->ui_flags; 1337024Ssam vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ 1347024Ssam 1357024Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 1367024Ssam sin->sin_family = AF_INET; 1377024Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 1387024Ssam 1397024Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; 1407024Ssam sin->sin_family = AF_INET; 1417024Ssam sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); 1427024Ssam vs->vs_if.if_flags = IFF_BROADCAST; 1437024Ssam 1447024Ssam vs->vs_if.if_init = vvinit; 1457024Ssam vs->vs_if.if_output = vvoutput; 1468980Sroot vs->vs_if.if_reset = vvreset; 1477640Ssam vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 1487024Ssam if_attach(&vs->vs_if); 1497024Ssam } 1507024Ssam 1517024Ssam /* 1527024Ssam * Reset of interface after UNIBUS reset. 1537024Ssam * If interface is on specified uba, reset its state. 1547024Ssam */ 1557024Ssam vvreset(unit, uban) 1567024Ssam int unit, uban; 1577024Ssam { 1587024Ssam register struct uba_device *ui; 1597024Ssam 1607024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 1617024Ssam ui->ui_ubanum != uban) 1627024Ssam return; 1637024Ssam printf(" vv%d", unit); 1647024Ssam vvinit(unit); 1657024Ssam } 1667024Ssam 1677024Ssam /* 1687024Ssam * Initialization of interface; clear recorded pending 1697024Ssam * operations, and reinitialize UNIBUS usage. 1707024Ssam */ 1717024Ssam vvinit(unit) 1727024Ssam int unit; 1737024Ssam { 1747024Ssam register struct vv_softc *vs = &vv_softc[unit]; 1757024Ssam register struct uba_device *ui = vvinfo[unit]; 1767024Ssam register struct vvreg *addr; 1777024Ssam struct sockaddr_in *sin; 1787640Ssam int ubainfo, s; 1797024Ssam 1807640Ssam addr = (struct vvreg *)ui->ui_addr; 1817024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 1827024Ssam sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 1837640Ssam nogo: 1847024Ssam printf("vv%d: can't initialize\n", unit); 1857640Ssam vs->vs_if.if_flags &= ~IFF_UP; 1867024Ssam return; 1877024Ssam } 1887024Ssam 1897024Ssam /* 1907640Ssam * discover our host address and post it 1917640Ssam */ 1927640Ssam 1937640Ssam vs->vs_if.if_host[0] = vvidentify(unit); 1947640Ssam if (vs->vs_if.if_host[0] == 0) 1957640Ssam goto nogo; 1967640Ssam printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 1977640Ssam sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 1987640Ssam sin->sin_family = AF_INET; 1997640Ssam sin->sin_addr = 2007640Ssam if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 2017640Ssam 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 */ 2077640Ssam sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */ 2087640Ssam vs->vs_init = 0; 2097640Ssam vs->vs_flush = 0; 2107640Ssam vs->vs_nottaken = 0; 2117640Ssam 2127640Ssam /* 2137640Ssam * Hang a receive and start any 2147640Ssam * pending writes by faking a transmit complete. 2157640Ssam */ 2167640Ssam s = splimp(); 2177640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 2187640Ssam addr->vviba = (u_short) ubainfo; 2197640Ssam addr->vviea = (u_short) (ubainfo >> 16); 2207640Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2217640Ssam addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 2227640Ssam vs->vs_oactive = 1; 2237640Ssam vs->vs_if.if_flags |= IFF_UP; 2247640Ssam vvxint(unit); 2257640Ssam splx(s); 2267640Ssam if_rtinit(&vs->vs_if, RTF_UP); 2277640Ssam } 2287640Ssam 2297640Ssam /* 2307640Ssam * vvidentify() - return our host address 2317640Ssam */ 2327640Ssam vvidentify(unit) 2337640Ssam { 2347640Ssam register struct vv_softc *vs = &vv_softc[unit]; 2357640Ssam register struct uba_device *ui = vvinfo[unit]; 2367640Ssam register struct vvreg *addr; 2377640Ssam struct mbuf *m; 2387640Ssam struct vv_header *v; 2397640Ssam int ubainfo, retrying, attempts, waitcount, s; 2407640Ssam 2417640Ssam /* 2427024Ssam * Build a multicast message to identify our address 2437024Ssam */ 2447640Ssam addr = (struct vvreg *)ui->ui_addr; 2457024Ssam attempts = 0; /* total attempts, including bad msg type */ 2467024Ssam retrying = 0; /* first time through */ 2479652Ssam m = m_get(M_DONTWAIT, MT_HEADER); 2487640Ssam if (m == 0) { 2497640Ssam printf("vvinit: can't get mbuf"); 2507640Ssam return (0); 2517640Ssam } 2527024Ssam m->m_off = MMINOFF; 2537024Ssam m->m_len = sizeof(struct vv_header); 2547024Ssam 2557024Ssam v = mtod(m, struct vv_header *); 2567024Ssam v->vh_dhost = 0; /* multicast destination address */ 2577024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 2587024Ssam v->vh_version = RING_VERSION; 2597024Ssam v->vh_type = RING_WHOAMI; 2607024Ssam v->vh_info = 0; 2617640Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 2627640Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 2637640Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 2647024Ssam 2657024Ssam /* 2667024Ssam * Reset interface, establish Digital Loopback Mode, and 2677024Ssam * send the multicast (to myself) with Input Copy enabled. 2687024Ssam */ 2697024Ssam retry: 2707024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 2717024Ssam addr->vvicsr = VV_RST; 2727024Ssam addr->vviba = (u_short) ubainfo; 2737024Ssam addr->vviea = (u_short) (ubainfo >> 16); 2747024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 2757024Ssam addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 2767640Ssam 2777640Ssam /* let flag timers fire so ring will initialize */ 2787640Ssam sleep((caddr_t) &lbolt, PZERO); 2797640Ssam sleep((caddr_t) &lbolt, PZERO); 2807640Ssam 2817024Ssam addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 2827024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 2837024Ssam addr->vvoba = (u_short) ubainfo; 2847024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 2857024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 2867024Ssam addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 2877024Ssam 2887024Ssam /* 2897024Ssam * Wait for receive side to finish. 2907640Ssam * Extract source address (which will be our own), 2917024Ssam * and post to interface structure. 2927024Ssam */ 2937024Ssam DELAY(1000); 2947640Ssam for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) 295*9876Ssam if (waitcount < 10) { 2967024Ssam DELAY(1000); 297*9876Ssam } else { 2987640Ssam if (attempts++ < 10) 2997024Ssam goto retry; 3007024Ssam else { 3017024Ssam printf("vv%d: can't initialize\n", unit); 3027024Ssam printf("vvinit loopwait: icsr = %b\n", 3037024Ssam 0xffff&(addr->vvicsr),VV_IBITS); 3047640Ssam vs->vs_if.if_flags &= ~IFF_UP; 3057640Ssam return (0); 3067024Ssam } 3077024Ssam } 3087024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3097024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3107024Ssam if (vs->vs_ifuba.ifu_xtofree) 3117024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 3127024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3137024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 3147024Ssam m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 3157024Ssam if (m) 3167024Ssam m_freem(m); 3177024Ssam /* 3187024Ssam * check message type before we believe the source host address 3197024Ssam */ 3207024Ssam v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 3217640Ssam if (v->vh_type != RING_WHOAMI) 3227640Ssam goto retry; 3237640Ssam return (v->vh_shost); 3247024Ssam } 3257024Ssam 3267024Ssam /* 3277024Ssam * Start or restart output on interface. 3287024Ssam * If interface is not already active, get another datagram 3297024Ssam * to send off of the interface queue, and map it to the interface 3307024Ssam * before starting the output. 3317024Ssam */ 3327024Ssam vvstart(dev) 3337024Ssam dev_t dev; 3347024Ssam { 3357024Ssam int unit = VVUNIT(dev); 3367024Ssam struct uba_device *ui = vvinfo[unit]; 3377024Ssam register struct vv_softc *vs = &vv_softc[unit]; 3387024Ssam register struct vvreg *addr; 3397024Ssam struct mbuf *m; 3407640Ssam int ubainfo, dest; 3417024Ssam 3427024Ssam if (vs->vs_oactive) 3437024Ssam goto restart; 3447024Ssam /* 3457024Ssam * Not already active: dequeue another request 3467024Ssam * and map it to the UNIBUS. If no more requests, 3477024Ssam * just return. 3487024Ssam */ 3497024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 3507024Ssam if (m == 0) { 3517024Ssam vs->vs_oactive = 0; 3527024Ssam return; 3537024Ssam } 3547024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 3557024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 3567024Ssam vs->vs_lastx = dest; 3577024Ssam 3587024Ssam restart: 3597024Ssam /* 3607024Ssam * Have request mapped to UNIBUS for transmission. 3617024Ssam * Purge any stale data from this BDP, and start the otput. 3627024Ssam */ 3637024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 3647024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 3657024Ssam addr = (struct vvreg *)ui->ui_addr; 3667024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 3677024Ssam addr->vvoba = (u_short) ubainfo; 3687024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 3697024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 3707024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 3717024Ssam vs->vs_oactive = 1; 3727024Ssam } 3737024Ssam 3747024Ssam /* 3757024Ssam * VVLNI transmit interrupt 3767024Ssam * Start another output if more data to send. 3777024Ssam */ 3787024Ssam vvxint(unit) 3797024Ssam int unit; 3807024Ssam { 3817024Ssam register struct uba_device *ui = vvinfo[unit]; 3827024Ssam register struct vv_softc *vs = &vv_softc[unit]; 3837024Ssam register struct vvreg *addr; 3847024Ssam register int oc; 3857024Ssam 3867024Ssam addr = (struct vvreg *)ui->ui_addr; 3877024Ssam oc = 0xffff & (addr->vvocsr); 3887024Ssam if (vs->vs_oactive == 0) { 3897640Ssam printf("vv%d: stray interrupt, vvocsr=%b\n", unit, 3907024Ssam oc, VV_OBITS); 3917024Ssam return; 3927024Ssam } 3937024Ssam if (oc & (VV_OPT | VV_RFS)) { 3947640Ssam vs->vs_if.if_collisions++; 3957024Ssam if (++(vs->vs_tries) < VVRETRY) { 3967024Ssam if (oc & VV_OPT) 3977024Ssam vs->vs_init++; 3987024Ssam if (oc & VV_RFS) 3997024Ssam vs->vs_nottaken++; 4007024Ssam addr->vvocsr = VV_IEN | VV_ENB | VV_INR; 4017024Ssam return; 4027024Ssam } 4037024Ssam if (oc & VV_OPT) 4047024Ssam printf("vv%d: output timeout\n"); 4057024Ssam } 4067024Ssam vs->vs_if.if_opackets++; 4077024Ssam vs->vs_oactive = 0; 4087024Ssam vs->vs_tries = 0; 4097024Ssam if (oc & VVXERR) { 4107024Ssam vs->vs_if.if_oerrors++; 4117640Ssam printf("vv%d: error, vvocsr=%b\n", unit, 0xffff & oc, 4127024Ssam VV_OBITS); 4137024Ssam } 4147024Ssam if (vs->vs_ifuba.ifu_xtofree) { 4157024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 4167024Ssam vs->vs_ifuba.ifu_xtofree = 0; 4177024Ssam } 4187024Ssam if (vs->vs_if.if_snd.ifq_head == 0) { 4197640Ssam vs->vs_lastx = 256; 4207024Ssam return; 4217024Ssam } 4227024Ssam vvstart(unit); 4237024Ssam } 4247024Ssam 4257024Ssam /* 4267024Ssam * V2lni interface receiver interrupt. 4277024Ssam * If input error just drop packet. 4287024Ssam * Otherwise purge input buffered data path and examine 4297024Ssam * packet to determine type. If can't determine length 4307024Ssam * from type, then have to drop packet. Othewise decapsulate 4317024Ssam * packet based on type and pass to type specific higher-level 4327024Ssam * input routine. 4337024Ssam */ 4347024Ssam vvrint(unit) 4357024Ssam int unit; 4367024Ssam { 4377024Ssam register struct vv_softc *vs = &vv_softc[unit]; 4387024Ssam struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 4397024Ssam register struct vv_header *vv; 4407024Ssam register struct ifqueue *inq; 4417024Ssam struct mbuf *m; 4427024Ssam int ubainfo, len, off; 4437640Ssam short resid; 4447024Ssam 4457024Ssam vs->vs_if.if_ipackets++; 4467024Ssam /* 4477024Ssam * Purge BDP; drop if input error indicated. 4487024Ssam */ 4497024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 4507024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 4517024Ssam if (addr->vvicsr & VVRERR) { 4527640Ssam /* 4537024Ssam printf("vv%d: error vvicsr = %b\n", unit, 4547024Ssam 0xffff&(addr->vvicsr), VV_IBITS); 4557640Ssam */ 4567640Ssam goto dropit; 4577024Ssam } 4587640Ssam 4597024Ssam /* 4607640Ssam * Get packet length from word count residue 4617640Ssam * 4627640Ssam * Compute header offset if trailer protocol 4637640Ssam * 4647640Ssam * Pull packet off interface. Off is nonzero if packet 4657640Ssam * has trailing header; if_rubaget will then force this header 4667640Ssam * information to be at the front. The vh_info field 4677640Ssam * carries the offset to the trailer data in trailer 4687640Ssam * format packets. 4697024Ssam */ 4707640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 4717640Ssam if (vv_trace) 4727640Ssam vvprt_hdr("vi", vv); 4737640Ssam resid = addr->vviwc; 4747640Ssam if (resid) 4757640Ssam resid |= 0176000; /* ugly!!!! */ 4767640Ssam len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 4777640Ssam len -= sizeof(struct vv_header); 4787640Ssam if (len > VVMRU) 4797640Ssam goto dropit; 4807640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 4817640Ssam if (vv_dotrailer && vv->vh_type >= RING_IPTrailer && 4827640Ssam vv->vh_type < RING_IPTrailer+RING_IPNTrailer){ 4837640Ssam off = (vv->vh_type - RING_IPTrailer) * 512; 4847640Ssam if (off > VVMTU) 4857640Ssam goto dropit; 4867640Ssam vv->vh_type = *vvdataaddr(vv, off, u_short *); 4877640Ssam resid = *(vvdataaddr(vv, off+2, u_short *)); 4887640Ssam if (off + resid > len) 4897640Ssam goto dropit; 4907640Ssam len = off + resid; 4917640Ssam } else 4927640Ssam off = 0; 4937640Ssam if (len == 0) 4947640Ssam goto dropit; 4957640Ssam m = if_rubaget(&vs->vs_ifuba, len, off); 4967640Ssam if (m == 0) 4977640Ssam goto dropit; 4987640Ssam if (off) { 4997640Ssam m->m_off += 2 * sizeof(u_short); 5007640Ssam m->m_len -= 2 * sizeof(u_short); 5017640Ssam } 5027024Ssam switch (vv->vh_type) { 5037024Ssam #ifdef INET 5047024Ssam case RING_IP: 5057024Ssam schednetisr(NETISR_IP); 5067024Ssam inq = &ipintrq; 5077024Ssam break; 5087024Ssam #endif 5097024Ssam default: 5107024Ssam printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 5117640Ssam m_freem(m); 5127024Ssam goto setup; 5137024Ssam } 5147640Ssam if (IF_QFULL(inq)) { 5157640Ssam IF_DROP(inq); 5167640Ssam m_freem(m); 5177640Ssam } else 5187640Ssam IF_ENQUEUE(inq, m); 5197024Ssam 5207024Ssam setup: 5217024Ssam /* 5227640Ssam * Restart the read for next packet. 5237024Ssam */ 5247024Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 5257024Ssam addr->vviba = (u_short) ubainfo; 5267024Ssam addr->vviea = (u_short) (ubainfo >> 16); 5277024Ssam addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 5287024Ssam addr->vvicsr = VV_RST | VV_CONF; 5297024Ssam addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 5307640Ssam return; 5317024Ssam 5327640Ssam dropit: 5337640Ssam vs->vs_if.if_ierrors++; 5347640Ssam /* 5357640Ssam printf("vv%d: error vvicsr = %b\n", unit, 5367640Ssam 0xffff&(addr->vvicsr), VV_IBITS); 5377640Ssam */ 5387640Ssam goto setup; 5397024Ssam } 5407024Ssam 5417024Ssam /* 5427024Ssam * V2lni output routine. 5437024Ssam * Encapsulate a packet of type family for the local net. 5447024Ssam * Use trailer local net encapsulation if enough data in first 5457024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 5467024Ssam */ 5477024Ssam vvoutput(ifp, m0, dst) 5487024Ssam struct ifnet *ifp; 5497024Ssam struct mbuf *m0; 5507024Ssam struct sockaddr *dst; 5517024Ssam { 5527024Ssam register struct mbuf *m = m0; 5537024Ssam register struct vv_header *vv; 5547640Ssam register int off; 5557640Ssam int type, dest, s, error; 5567024Ssam 5577024Ssam switch (dst->sa_family) { 5587024Ssam #ifdef INET 5597024Ssam case AF_INET: { 5607640Ssam dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 5617640Ssam if (dest & 0x00ffff00) { 5627640Ssam error = EPERM; 5637640Ssam goto bad; 5647640Ssam } 5657640Ssam dest = (dest >> 24) & 0xff; 5667640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 5677640Ssam if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 && 5687640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 5697640Ssam type = RING_IPTrailer + (off>>9); 5707640Ssam m->m_off -= 2 * sizeof (u_short); 5717640Ssam m->m_len += 2 * sizeof (u_short); 5727640Ssam *mtod(m, u_short *) = RING_IP; 5737640Ssam *(mtod(m, u_short *) + 1) = m->m_len; 5747640Ssam goto gottrailertype; 5757640Ssam } 5767024Ssam type = RING_IP; 5777024Ssam off = 0; 5787024Ssam goto gottype; 5797024Ssam } 5807024Ssam #endif 5817024Ssam default: 5827024Ssam printf("vv%d: can't handle af%d\n", ifp->if_unit, 5837024Ssam dst->sa_family); 5847640Ssam error = EAFNOSUPPORT; 5857640Ssam goto bad; 5867024Ssam } 5877024Ssam 5887024Ssam gottrailertype: 5897024Ssam /* 5907024Ssam * Packet to be sent as trailer: move first packet 5917024Ssam * (control information) to end of chain. 5927024Ssam */ 5937024Ssam while (m->m_next) 5947024Ssam m = m->m_next; 5957024Ssam m->m_next = m0; 5967024Ssam m = m0->m_next; 5977024Ssam m0->m_next = 0; 5987024Ssam m0 = m; 5997024Ssam 6007024Ssam gottype: 6017024Ssam /* 6027024Ssam * Add local net header. If no space in first mbuf, 6037024Ssam * allocate another. 6047024Ssam */ 6057024Ssam if (m->m_off > MMAXOFF || 6067024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 6079652Ssam m = m_get(M_DONTWAIT, MT_HEADER); 6087024Ssam if (m == 0) { 6097640Ssam error = ENOBUFS; 6107640Ssam goto bad; 6117024Ssam } 6127024Ssam m->m_next = m0; 6137024Ssam m->m_off = MMINOFF; 6147024Ssam m->m_len = sizeof (struct vv_header); 6157024Ssam } else { 6167024Ssam m->m_off -= sizeof (struct vv_header); 6177024Ssam m->m_len += sizeof (struct vv_header); 6187024Ssam } 6197024Ssam vv = mtod(m, struct vv_header *); 6207024Ssam vv->vh_shost = ifp->if_host[0]; 6217024Ssam vv->vh_dhost = dest; 6227024Ssam vv->vh_version = RING_VERSION; 6237024Ssam vv->vh_type = type; 6247640Ssam vv->vh_info = off; 6257640Ssam if (vv_trace) 6267640Ssam vvprt_hdr("vo", vv); 6277024Ssam 6287024Ssam /* 6297024Ssam * Queue message on interface, and start output if interface 6307024Ssam * not yet active. 6317024Ssam */ 6327024Ssam s = splimp(); 6337640Ssam if (IF_QFULL(&ifp->if_snd)) { 6347640Ssam IF_DROP(&ifp->if_snd); 6357640Ssam error = ENOBUFS; 6367640Ssam goto qfull; 6377640Ssam } 6387024Ssam IF_ENQUEUE(&ifp->if_snd, m); 6397024Ssam if (vv_softc[ifp->if_unit].vs_oactive == 0) 6407024Ssam vvstart(ifp->if_unit); 6417024Ssam splx(s); 6427640Ssam return (0); 6437640Ssam 6447640Ssam qfull: 6457640Ssam m0 = m; 6467640Ssam splx(s); 6477640Ssam bad: 6487640Ssam m_freem(m0); 6497640Ssam return(error); 6507024Ssam } 6517024Ssam 6527024Ssam /* 6537024Ssam * vvprt_hdr(s, v) print the local net header in "v" 6547024Ssam * with title is "s" 6557024Ssam */ 6567024Ssam vvprt_hdr(s, v) 6577024Ssam char *s; 6587024Ssam register struct vv_header *v; 6597024Ssam { 6607024Ssam printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 6617024Ssam s, 6627024Ssam 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 6637024Ssam 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 6647024Ssam 0xffff & (int)(v->vh_info)); 6657024Ssam } 6667024Ssam 6677024Ssam /* 6687024Ssam * print "l" hex bytes starting at "s" 6697024Ssam */ 6707024Ssam vvprt_hex(s, l) 6717024Ssam char *s; 6727024Ssam int l; 6737024Ssam { 6747024Ssam register int i; 6757024Ssam register int z; 6767024Ssam 6777024Ssam for (i=0 ; i < l; i++) { 6787024Ssam z = 0xff & (int)(*(s + i)); 6797024Ssam printf("%c%c ", 6807024Ssam "0123456789abcdef"[(z >> 4) & 0x0f], 6817024Ssam "0123456789abcdef"[z & 0x0f] 6827024Ssam ); 6837024Ssam } 6847024Ssam } 6859799Ssam #endif 686