123305Smckusick /* 2*36085Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 335328Sbostic * All rights reserved. 423305Smckusick * 535328Sbostic * Redistribution and use in source and binary forms are permitted 635328Sbostic * provided that the above copyright notice and this paragraph are 735328Sbostic * duplicated in all such forms and that any documentation, 835328Sbostic * advertising materials, and other materials related to such 935328Sbostic * distribution and use acknowledge that the software was developed 1035328Sbostic * by the University of California, Berkeley. The name of the 1135328Sbostic * University may not be used to endorse or promote products derived 1235328Sbostic * from this software without specific prior written permission. 1335328Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435328Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535328Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635328Sbostic * 17*36085Skarels * @(#)if_vv.c 7.4 (Berkeley) 10/22/88 1823305Smckusick */ 197024Ssam 209799Ssam #include "vv.h" 2125275Sbloom #if NVV > 0 2211192Ssam 237024Ssam /* 2435805Skarels * Proteon ProNET-10 and ProNET-80 token ring driver. 2520997Skarels * The name of this device driver derives from the old MIT 2620997Skarels * name of V2LNI for the proNET hardware, would would abbreviate 2735805Skarels * to "v2", but this won't work right in config. Thus the name is "vv". 2811192Ssam * 2935805Skarels * This driver is compatible with the Unibus ProNET 10 megabit and 3020997Skarels * 80 megabit token ring interfaces (models p1000 and p1080). 3126903Sjas * A unit may be marked as 80 megabit using "flags 1" in the 3226903Sjas * config file. 3320997Skarels * 3435805Skarels * This driver is also compatible with the Q-bus ProNET 10 megabit and 3535805Skarels * 80 megabit token ring interfaces (models p1100 and p1180), but 3635805Skarels * only on a MicroVAX-II or MicroVAX-III. No attempt is made to 3735805Skarels * support the MicroVAX-I. 3835805Skarels * 3926950Sjas * TRAILERS: This driver has a new implementation of trailers that 4026950Sjas * is at least a tolerable neighbor on the ring. The offset is not 4126950Sjas * stored in the protocol type, but instead only in the vh_info 4226950Sjas * field. Also, the vh_info field, and the two shorts before the 4326950Sjas * trailing header, are in network byte order, not VAX byte order. 4420997Skarels * 4526950Sjas * Of course, nothing but BSD UNIX supports trailers on ProNET. 4635805Skarels * If you need interoperability with anything else (like the p4200), 4735805Skarels * turn off trailers using the -trailers option to /etc/ifconfig! 4826950Sjas * 4926903Sjas * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) 5020997Skarels * have a serial number >= 040, which is about March, 1982. Older 5126903Sjas * HSBUs do not carry across 64kbyte boundaries. They can be supported 5226903Sjas * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization 5326903Sjas * in vvattach(). 5426903Sjas * 5526903Sjas * The old warning about use without Wire Centers applies only to CTL 5626903Sjas * (p1002) cards with serial <= 057, which have not received ECO 176-743, 5726903Sjas * which was implemented in March, 1982. Most such CTLs have received 5826903Sjas * this ECO. 597024Ssam */ 6011209Ssam #include "../machine/pte.h" 619799Ssam 6217117Sbloom #include "param.h" 6317117Sbloom #include "systm.h" 6417117Sbloom #include "mbuf.h" 6517117Sbloom #include "buf.h" 6617117Sbloom #include "protosw.h" 6717117Sbloom #include "socket.h" 6817117Sbloom #include "vmmac.h" 6917117Sbloom #include "errno.h" 7017117Sbloom #include "ioctl.h" 718465Sroot 728465Sroot #include "../net/if.h" 7311209Ssam #include "../net/netisr.h" 748465Sroot #include "../net/route.h" 7524793Skarels 7624793Skarels #ifdef INET 778421Swnj #include "../netinet/in.h" 788421Swnj #include "../netinet/in_systm.h" 7921779Skarels #include "../netinet/in_var.h" 808421Swnj #include "../netinet/ip.h" 8124793Skarels #endif 828465Sroot 8315794Sleres #include "../vax/cpu.h" 8411209Ssam #include "../vax/mtpr.h" 8517117Sbloom #include "if_vv.h" 8617117Sbloom #include "if_uba.h" 878465Sroot #include "../vaxuba/ubareg.h" 888465Sroot #include "../vaxuba/ubavar.h" 897024Ssam 907024Ssam /* 9120997Skarels * maximum transmission unit definition -- 9235805Skarels * you can set VVMTU at anything from 576 to 2036. 9320997Skarels * 1536 is a popular "large" value, because it is a multiple 9420997Skarels * of 512, which the trailer scheme likes. 9535805Skarels * The absolute maximum size is 2036, which is enforced. 9620997Skarels */ 9720997Skarels 9835805Skarels #define VVMTU (2036) 9920997Skarels 10035805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short))) 10120997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 10235805Skarels #if VVMTU>2036 10320997Skarels #undef VVMTU 10420997Skarels #undef VVMRU 10520997Skarels #undef VVBUFSIZE 10620997Skarels #define VVBUFSIZE (2046) 10720997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 10835805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short))) 1097024Ssam #endif 1107024Ssam 11120997Skarels /* 11220997Skarels * debugging and tracing stuff 11320997Skarels */ 11416581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 1157640Ssam 11620997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 11721779Skarels #define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf 11811192Ssam 11920997Skarels /* 12020997Skarels * externals, types, etc. 12120997Skarels */ 12216581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 12316581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 12426394Skarels int vvrint(), vvoutput(), vvioctl(); 1257024Ssam struct uba_device *vvinfo[NVV]; 1267024Ssam u_short vvstd[] = { 0 }; 1277024Ssam struct uba_driver vvdriver = 1287024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1297024Ssam #define VVUNIT(x) minor(x) 1307024Ssam 13120997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 13220997Skarels #ifdef LOOPBACK 13320997Skarels extern struct ifnet loif; 13420997Skarels #endif 13520997Skarels 1367024Ssam /* 1377024Ssam * Software status of each interface. 1387024Ssam * 1397024Ssam * Each interface is referenced by a network interface structure, 1407024Ssam * vs_if, which the routing code uses to locate the interface. 1417024Ssam * This structure contains the output queue for the interface, its address, ... 1427024Ssam * We also have, for each interface, a UBA interface structure, which 1437024Ssam * contains information about the UNIBUS resources held by the interface: 1447024Ssam * map registers, buffered data paths, etc. Information is cached in this 1457024Ssam * structure for use by the if_uba.c routines in running the interface 1467024Ssam * efficiently. 1477024Ssam */ 1487024Ssam struct vv_softc { 1497024Ssam struct ifnet vs_if; /* network-visible interface */ 1507024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 15126298Skarels u_short vs_host; /* this interface address */ 15211192Ssam short vs_oactive; /* is output active */ 15326903Sjas short vs_is80; /* is 80 megabit version */ 1547024Ssam short vs_olen; /* length of last output */ 15515794Sleres u_short vs_lastx; /* address of last packet sent */ 15615794Sleres u_short vs_lastr; /* address of last packet received */ 15711192Ssam short vs_tries; /* transmit current retry count */ 1587024Ssam short vs_init; /* number of ring inits */ 15920997Skarels short vs_refused; /* number of packets refused */ 16015794Sleres short vs_timeouts; /* number of transmit timeouts */ 16120997Skarels short vs_otimeout; /* number of output timeouts */ 16220997Skarels short vs_ibadf; /* number of input bad formats */ 16320997Skarels short vs_parity; /* number of parity errors on 10 meg, */ 16420997Skarels /* link data errors on 80 meg */ 165*36085Skarels short vs_ipl; /* interrupt priority on Q-bus */ 1667024Ssam } vv_softc[NVV]; 1677024Ssam 16826311Skarels #define NOHOST 0xffff /* illegal host number */ 16926311Skarels 17020997Skarels /* 17120997Skarels * probe the interface to see that the registers exist, and then 17220997Skarels * cause an interrupt to find its vector 17320997Skarels */ 174*36085Skarels vvprobe(reg, ui) 1757024Ssam caddr_t reg; 176*36085Skarels struct uba_device *ui; 1777024Ssam { 1787024Ssam register int br, cvec; 17916581Skarels register struct vvreg *addr; 1807024Ssam 1817024Ssam #ifdef lint 18215764Sleres br = 0; cvec = br; br = cvec; 1837024Ssam #endif 18416581Skarels addr = (struct vvreg *)reg; 18520997Skarels 1867024Ssam /* reset interface, enable, and wait till dust settles */ 187*36085Skarels #ifdef QBA 188*36085Skarels (void) spl6(); 189*36085Skarels #endif 1907024Ssam addr->vvicsr = VV_RST; 1917024Ssam addr->vvocsr = VV_RST; 19215764Sleres DELAY(100000); 19320997Skarels 1947024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1957024Ssam addr->vvoba = 0; /* low 16 bits */ 1967024Ssam addr->vvoea = 0; /* extended bits */ 1977024Ssam addr->vvowc = -1; /* for 1 word */ 19820997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 1997024Ssam DELAY(100000); 200*36085Skarels #ifdef QBA 201*36085Skarels vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri(); 202*36085Skarels #endif 20320997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 2047024Ssam if (cvec && cvec != 0x200) 20515764Sleres cvec -= 4; /* backup so vector => receive */ 206*36085Skarels return (sizeof(struct vvreg)); 2077024Ssam } 2087024Ssam 2097024Ssam /* 2107024Ssam * Interface exists: make available by filling in network interface 2117024Ssam * record. System will initialize the interface when it is ready 2127024Ssam * to accept packets. 2137024Ssam */ 2147024Ssam vvattach(ui) 2157024Ssam struct uba_device *ui; 2167024Ssam { 21715764Sleres register struct vv_softc *vs; 2187024Ssam 21915764Sleres vs = &vv_softc[ui->ui_unit]; 2207024Ssam vs->vs_if.if_unit = ui->ui_unit; 2217024Ssam vs->vs_if.if_name = "vv"; 2227024Ssam vs->vs_if.if_mtu = VVMTU; 22321779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 2247024Ssam vs->vs_if.if_init = vvinit; 22513057Ssam vs->vs_if.if_ioctl = vvioctl; 2267024Ssam vs->vs_if.if_output = vvoutput; 22711209Ssam vs->vs_if.if_reset = vvreset; 22815794Sleres vs->vs_if.if_timer = 0; 22915794Sleres vs->vs_if.if_watchdog = vvwatchdog; 23026201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 23126903Sjas 23226903Sjas /* use flag to determine if this is proNET-80 */ 23326903Sjas vs->vs_is80 = (short)(ui->ui_flags & 01); 23426903Sjas 23512354Smo #if defined(VAX750) 23612354Smo /* don't chew up 750 bdp's */ 23712354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 23812354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 23912354Smo #endif 2407024Ssam if_attach(&vs->vs_if); 2417024Ssam } 2427024Ssam 2437024Ssam /* 2447024Ssam * Reset of interface after UNIBUS reset. 2457024Ssam * If interface is on specified uba, reset its state. 2467024Ssam */ 2477024Ssam vvreset(unit, uban) 2487024Ssam int unit, uban; 2497024Ssam { 2507024Ssam register struct uba_device *ui; 2517024Ssam 2527024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2537024Ssam ui->ui_ubanum != uban) 2547024Ssam return; 2557024Ssam printf(" vv%d", unit); 2567024Ssam vvinit(unit); 2577024Ssam } 2587024Ssam 2597024Ssam /* 2607024Ssam * Initialization of interface; clear recorded pending 2617024Ssam * operations, and reinitialize UNIBUS usage. 2627024Ssam */ 2637024Ssam vvinit(unit) 2647024Ssam int unit; 2657024Ssam { 26615764Sleres register struct vv_softc *vs; 26715764Sleres register struct uba_device *ui; 2687024Ssam register struct vvreg *addr; 26935805Skarels register int ubaaddr, s; 2707024Ssam 27115764Sleres vs = &vv_softc[unit]; 27215764Sleres ui = vvinfo[unit]; 27320997Skarels 27421779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 27513057Ssam return; 27620997Skarels 2777640Ssam addr = (struct vvreg *)ui->ui_addr; 278*36085Skarels if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 && 279*36085Skarels if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 280*36085Skarels sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) { 28115794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 2827640Ssam vs->vs_if.if_flags &= ~IFF_UP; 2837024Ssam return; 2847024Ssam } 285*36085Skarels vs->vs_if.if_flags |= IFF_RUNNING; 28620997Skarels 2877024Ssam /* 28815764Sleres * Now that the uba is set up, figure out our address and 28915764Sleres * update complete our host address. 2907640Ssam */ 29126311Skarels if ((vs->vs_host = vvidentify(unit)) == NOHOST) { 29215794Sleres vs->vs_if.if_flags &= ~IFF_UP; 29315794Sleres return; 29415794Sleres } 29526903Sjas printf("vv%d: host %u\n", unit, vs->vs_host); 29620997Skarels 2977640Ssam /* 29820997Skarels * Reset the interface, and stay in the ring 2997640Ssam */ 30020997Skarels addr->vvocsr = VV_RST; /* take over output */ 30120997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 30220997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 30320997Skarels /* keep relay closed */ 30412351Smo DELAY(500000); /* let contacts settle */ 30520997Skarels 30620997Skarels vs->vs_init = 0; /* clear counters, etc. */ 30720997Skarels vs->vs_refused = 0; 30815794Sleres vs->vs_timeouts = 0; 30920997Skarels vs->vs_otimeout = 0; 31020997Skarels vs->vs_ibadf = 0; 31120997Skarels vs->vs_parity = 0; 31215794Sleres vs->vs_lastx = 256; /* an invalid address */ 31315794Sleres vs->vs_lastr = 256; /* an invalid address */ 31420997Skarels 3157640Ssam /* 3167640Ssam * Hang a receive and start any 3177640Ssam * pending writes by faking a transmit complete. 3187640Ssam */ 3197640Ssam s = splimp(); 32035805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 32135805Skarels addr->vviba = (u_short)ubaaddr; 32235805Skarels addr->vviea = (u_short)(ubaaddr >> 16); 32320997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 32420997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 3257640Ssam vs->vs_oactive = 1; 326*36085Skarels vs->vs_if.if_flags |= IFF_UP; 3277640Ssam vvxint(unit); 3287640Ssam splx(s); 3297640Ssam } 3307640Ssam 3317640Ssam /* 33220997Skarels * Do a moderately thorough self-test in all three modes. Mostly 33320997Skarels * to keeps defective nodes off the ring, rather than to be especially 33420997Skarels * thorough. The key issue is to detect any cable breaks before joining 33520997Skarels * the ring. Return our node address on success, return -1 on failure. 33620997Skarels * 3377640Ssam */ 33820997Skarels 33920997Skarels /* the three self-test modes */ 34020997Skarels static u_short vv_modes[] = { 34120997Skarels VV_STE|VV_LPB, /* digital loopback */ 34220997Skarels VV_STE, /* analog loopback */ 34320997Skarels VV_HEN /* network mode */ 34420997Skarels }; 34520997Skarels 34611209Ssam vvidentify(unit) 34713057Ssam int unit; 34811209Ssam { 34915764Sleres register struct vv_softc *vs; 35015764Sleres register struct uba_device *ui; 3517640Ssam register struct vvreg *addr; 35216581Skarels register struct mbuf *m; 35316581Skarels register struct vv_header *v; 35435805Skarels register int ubaaddr; 35520997Skarels register int i, successes, failures, waitcount; 35626311Skarels u_short shost = NOHOST; 3577640Ssam 35820997Skarels vs = &vv_softc[unit]; 35920997Skarels ui = vvinfo[unit]; 36020997Skarels addr = (struct vvreg *)ui->ui_addr; 36120997Skarels 3627640Ssam /* 3637024Ssam * Build a multicast message to identify our address 36420997Skarels * We need do this only once, since nobody else is about to use 36520997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 36620997Skarels * if_ubainit() aquired for us. 3677024Ssam */ 36811209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 36915794Sleres if (m == NULL) { 37015794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 37113057Ssam return (0); 37215794Sleres } 37311192Ssam m->m_next = 0; 3747024Ssam m->m_off = MMINOFF; 3757024Ssam m->m_len = sizeof(struct vv_header); 3767024Ssam v = mtod(m, struct vv_header *); 37711192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 3787024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 3797024Ssam v->vh_version = RING_VERSION; 38020997Skarels v->vh_type = RING_DIAGNOSTICS; 3817024Ssam v->vh_info = 0; 38220997Skarels /* map xmit message into uba, copying to intermediate buffer */ 38320997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 38420997Skarels 3857024Ssam /* 38620997Skarels * For each of the modes (digital, analog, network), go through 38720997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 38820997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 38920997Skarels * who I am, then use this as my address to check my address match 39020997Skarels * logic. Only data checked is the vh_type field. 3917024Ssam */ 3927640Ssam 39320997Skarels for (i = 0; i < 3; i++) { 39420997Skarels successes = 0; /* clear successes for this mode */ 39520997Skarels failures = 0; /* and clear failures, too */ 3967640Ssam 39720997Skarels /* take over device, and leave ring */ 39820997Skarels addr->vvicsr = VV_RST; 39920997Skarels addr->vvocsr = VV_RST; 40020997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 40120997Skarels 40220997Skarels /* 40320997Skarels * let the flag and token timers pop so that the init ring bit 40420997Skarels * will be allowed to work, by waiting about 1 second 40520997Skarels */ 40620997Skarels DELAY(1000000L); 40720997Skarels 40820997Skarels /* 40920997Skarels * retry loop 41020997Skarels */ 41120997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 41220997Skarels { 41320997Skarels /* start a receive */ 41435805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 41520997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 41635805Skarels addr->vviba = (u_short) ubaaddr; 41735805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 41820997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 41920997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 42020997Skarels 42120997Skarels /* purge stale data from BDP */ 42220997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 42320997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 42420997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 42520997Skarels 42620997Skarels /* do a transmit */ 42735805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 42820997Skarels addr->vvocsr = VV_RST; /* abort last try */ 42935805Skarels addr->vvoba = (u_short) ubaaddr; 43035805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 43120997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 43220997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 43320997Skarels 43420997Skarels /* poll receive side for completion */ 43520997Skarels DELAY(10000); /* give it a chance */ 43620997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 43720997Skarels if (addr->vvicsr & VV_RDY) 43820997Skarels goto gotit; 43920997Skarels DELAY(1000); 44020997Skarels } 44120997Skarels failures++; /* no luck */ 44211209Ssam continue; 44320997Skarels 44420997Skarels gotit: /* we got something--is it any good? */ 44520997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 44621779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 44720997Skarels failures++; 44820997Skarels continue; 44920997Skarels } 45020997Skarels 45120997Skarels /* Purge BDP before looking at received packet */ 45220997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 45320997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 45420997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 45524793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 45626394Skarels 0, &vs->vs_if); 45720997Skarels if (m != NULL) 45820997Skarels m_freem(m); 45920997Skarels 46020997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 46120997Skarels 46220997Skarels /* check message type, catch our node address */ 46320997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 46426311Skarels if (shost == NOHOST) { 46520997Skarels shost = v->vh_shost & 0xff; 46620997Skarels /* send to ourself now */ 46720997Skarels ((struct vv_header *) 46820997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 46920997Skarels ->vh_dhost = shost; 47020997Skarels } 47120997Skarels successes++; 47226903Sjas } else { 47326903Sjas failures++; 47420997Skarels } 47526903Sjas v->vh_type = 0; /* clear to check again */ 47611192Ssam } 47720997Skarels 47820997Skarels if (failures >= VVIDENTRETRY) 47920997Skarels { 48020997Skarels printf("vv%d: failed self-test after %d tries \ 48120997Skarels in %s mode\n", 48220997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 48320997Skarels (i == 1 ? "analog loopback" : "network")); 48420997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 48520997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 48620997Skarels 0xffff & addr->vvocsr, VV_OBITS); 48720997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 48820997Skarels addr->vvocsr = VV_RST; 48926311Skarels shost = NOHOST; 49020997Skarels goto done; 49120997Skarels } 49211192Ssam } 49320997Skarels 49420997Skarels done: 49520997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 49615794Sleres if (vs->vs_ifuba.ifu_xtofree) { 4977024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 49815794Sleres vs->vs_ifuba.ifu_xtofree = 0; 49915794Sleres } 50020997Skarels 50120997Skarels return(shost); 5027024Ssam } 5037024Ssam 5047024Ssam /* 5057024Ssam * Start or restart output on interface. 50611192Ssam * If interface is active, this is a retransmit, so just 50711192Ssam * restuff registers and go. 5087024Ssam * If interface is not already active, get another datagram 5097024Ssam * to send off of the interface queue, and map it to the interface 5107024Ssam * before starting the output. 5117024Ssam */ 5127024Ssam vvstart(dev) 5137024Ssam dev_t dev; 5147024Ssam { 51516581Skarels register struct uba_device *ui; 51615764Sleres register struct vv_softc *vs; 5177024Ssam register struct vvreg *addr; 51816581Skarels register struct mbuf *m; 51935805Skarels register int unit, ubaaddr, dest, s; 5207024Ssam 52116581Skarels unit = VVUNIT(dev); 52215764Sleres ui = vvinfo[unit]; 52315764Sleres vs = &vv_softc[unit]; 5247024Ssam if (vs->vs_oactive) 5257024Ssam goto restart; 5267024Ssam /* 5277024Ssam * Not already active: dequeue another request 5287024Ssam * and map it to the UNIBUS. If no more requests, 5297024Ssam * just return. 5307024Ssam */ 53115794Sleres s = splimp(); 5327024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 53315794Sleres splx(s); 53411209Ssam if (m == NULL) { 5357024Ssam vs->vs_oactive = 0; 5367024Ssam return; 5377024Ssam } 5387024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5397024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5407024Ssam vs->vs_lastx = dest; 5417024Ssam restart: 5427024Ssam /* 5437024Ssam * Have request mapped to UNIBUS for transmission. 54415794Sleres * Purge any stale data from this BDP, and start the output. 54515794Sleres * 54615794Sleres * Make sure this packet will fit in the interface. 5477024Ssam */ 54820997Skarels if (vs->vs_olen > VVBUFSIZE) { 54920997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 55011192Ssam panic("vvdriver vs_olen botch"); 55111192Ssam } 55220997Skarels 55320997Skarels vs->vs_if.if_timer = VVTIMEOUT; 55420997Skarels vs->vs_oactive = 1; 55520997Skarels 55620997Skarels /* ship it */ 557*36085Skarels #ifdef notdef 5587024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 5597024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 560*36085Skarels #endif 5617024Ssam addr = (struct vvreg *)ui->ui_addr; 56235805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 56335805Skarels addr->vvoba = (u_short) ubaaddr; 56435805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 5657024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 56620997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 56720997Skarels if (addr->vvocsr & VV_NOK) 56820997Skarels vs->vs_init++; /* count ring inits */ 5697024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 5707024Ssam } 5717024Ssam 5727024Ssam /* 57320997Skarels * proNET transmit interrupt 5747024Ssam * Start another output if more data to send. 5757024Ssam */ 5767024Ssam vvxint(unit) 5777024Ssam int unit; 5787024Ssam { 57915764Sleres register struct uba_device *ui; 58015764Sleres register struct vv_softc *vs; 5817024Ssam register struct vvreg *addr; 5827024Ssam register int oc; 5837024Ssam 584*36085Skarels #ifdef QBA 585*36085Skarels splx(vv_softc[unit].vs_ipl); 586*36085Skarels #endif 58715764Sleres ui = vvinfo[unit]; 58815764Sleres vs = &vv_softc[unit]; 58915794Sleres vs->vs_if.if_timer = 0; 5907024Ssam addr = (struct vvreg *)ui->ui_addr; 5917024Ssam oc = 0xffff & (addr->vvocsr); 5927024Ssam if (vs->vs_oactive == 0) { 59320997Skarels vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit, 59415764Sleres oc, VV_OBITS); 5957024Ssam return; 5967024Ssam } 59720997Skarels 59820997Skarels /* 59920997Skarels * we retransmit on soft error 60020997Skarels * TODO: sort retransmits to end of queue if possible! 60120997Skarels */ 60220997Skarels if (oc & (VV_OPT | VV_RFS)) { 60311192Ssam if (vs->vs_tries++ < VVRETRY) { 6047024Ssam if (oc & VV_OPT) 60520997Skarels vs->vs_otimeout++; 60620997Skarels if (oc & VV_RFS) { 60720997Skarels vs->vs_if.if_collisions++; 60820997Skarels vs->vs_refused++; 60920997Skarels } 61011192Ssam vvstart(unit); /* restart this message */ 6117024Ssam return; 6127024Ssam } 6137024Ssam } 6147024Ssam vs->vs_if.if_opackets++; 6157024Ssam vs->vs_oactive = 0; 6167024Ssam vs->vs_tries = 0; 61720997Skarels 6187024Ssam if (oc & VVXERR) { 6197024Ssam vs->vs_if.if_oerrors++; 62020997Skarels vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 62115764Sleres VV_OBITS); 6227024Ssam } 6237024Ssam if (vs->vs_ifuba.ifu_xtofree) { 6247024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 6257024Ssam vs->vs_ifuba.ifu_xtofree = 0; 6267024Ssam } 6277024Ssam vvstart(unit); 6287024Ssam } 6297024Ssam 6307024Ssam /* 63115794Sleres * Transmit watchdog timer routine. 63215794Sleres * This routine gets called when we lose a transmit interrupt. 63315794Sleres * The best we can do is try to restart output. 63415794Sleres */ 63515794Sleres vvwatchdog(unit) 63615794Sleres int unit; 63715794Sleres { 63815794Sleres register struct vv_softc *vs; 63915794Sleres register int s; 64015794Sleres 64115794Sleres vs = &vv_softc[unit]; 64220997Skarels vvprintf("vv%d: lost a transmit interrupt.\n", unit); 64315794Sleres vs->vs_timeouts++; 64415794Sleres s = splimp(); 64515794Sleres vvstart(unit); 64615794Sleres splx(s); 64715794Sleres } 64815794Sleres 64915794Sleres /* 65020997Skarels * proNET interface receiver interrupt. 6517024Ssam * If input error just drop packet. 65215764Sleres * Otherwise purge input buffered data path and examine 6537024Ssam * packet to determine type. If can't determine length 65415764Sleres * from type, then have to drop packet. Otherwise decapsulate 6557024Ssam * packet based on type and pass to type specific higher-level 6567024Ssam * input routine. 6577024Ssam */ 6587024Ssam vvrint(unit) 6597024Ssam int unit; 6607024Ssam { 66115764Sleres register struct vv_softc *vs; 66216581Skarels register struct vvreg *addr; 6637024Ssam register struct vv_header *vv; 6647024Ssam register struct ifqueue *inq; 66516581Skarels register struct mbuf *m; 66635805Skarels int ubaaddr, len, off, s; 6677640Ssam short resid; 6687024Ssam 669*36085Skarels #ifdef QBA 670*36085Skarels splx(vv_softc[unit].vs_ipl); 671*36085Skarels #endif 67215764Sleres vs = &vv_softc[unit]; 67316581Skarels vs->vs_if.if_ipackets++; 67415764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 67520997Skarels 6767024Ssam /* 67726903Sjas * Purge BDP 6787024Ssam */ 6797024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 6807024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 68120997Skarels 68220997Skarels /* 68320997Skarels * receive errors? 68420997Skarels */ 6857024Ssam if (addr->vvicsr & VVRERR) { 68620997Skarels vvprintf("vv%d: receive error, vvicsr = %b\n", unit, 68720997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 68820997Skarels if (addr->vvicsr & VV_BDF) 68920997Skarels vs->vs_ibadf++; 6907640Ssam goto dropit; 6917024Ssam } 6927640Ssam 6937024Ssam /* 69420997Skarels * parity errors? 69520997Skarels */ 69620997Skarels if (addr->vvicsr & VV_LDE) { 69720997Skarels /* we don't have to clear it because the receive command */ 69820997Skarels /* writes 0 to parity bit */ 69920997Skarels vs->vs_parity++; 70026903Sjas 70120997Skarels /* 70220997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 70320997Skarels * bit. On 80 megabit, it returns to the intended use of 70420997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 70520997Skarels * give VV_BDF. 70620997Skarels */ 70726903Sjas if (vs->vs_is80 == 0) 70826903Sjas goto dropit; 70920997Skarels } 71020997Skarels 71120997Skarels /* 71220997Skarels * Get packet length from residual word count 7137640Ssam * 7147640Ssam * Compute header offset if trailer protocol 7157640Ssam * 7167640Ssam * Pull packet off interface. Off is nonzero if packet 7177640Ssam * has trailing header; if_rubaget will then force this header 7187640Ssam * information to be at the front. The vh_info field 7197640Ssam * carries the offset to the trailer data in trailer 7207640Ssam * format packets. 7217024Ssam */ 7227640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 72311192Ssam vvtracehdr("vi", vv); 72420997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 7257640Ssam if (resid) 72620997Skarels resid |= 0176000; /* high 6 bits are undefined */ 72720997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 7287640Ssam len -= sizeof(struct vv_header); 72920997Skarels 73020997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 73120997Skarels vvprintf("vv%d: len too long or short, \ 73220997Skarels len = %d, vvicsr = %b\n", 73315794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 7347640Ssam goto dropit; 73515794Sleres } 73620997Skarels 73720997Skarels /* check the protocol header version */ 73820997Skarels if (vv->vh_version != RING_VERSION) { 73920997Skarels vvprintf("vv%d: bad protocol header version %d\n", 74020997Skarels unit, vv->vh_version & 0xff); 74120997Skarels goto dropit; 74220997Skarels } 74320997Skarels 7447640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 74526950Sjas if (vv->vh_type == RING_TRAILER ) { 74628954Skarels off = ntohs((u_short)vv->vh_info); 74715794Sleres if (off > VVMTU) { 74820997Skarels vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 74915794Sleres unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7507640Ssam goto dropit; 75115794Sleres } 75226903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 75326950Sjas resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *))); 75415794Sleres if (off + resid > len) { 75520997Skarels vvprintf("vv%d: trailer packet too short\n", unit); 75620997Skarels vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n", 75715794Sleres unit, off, resid, 75815794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7597640Ssam goto dropit; 76015794Sleres } 7617640Ssam len = off + resid; 76211209Ssam } else 7637640Ssam off = 0; 76420997Skarels 76515794Sleres if (len == 0) { 76620997Skarels vvprintf("vv%d: len is zero, vvicsr = %b\n", unit, 76715794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7687640Ssam goto dropit; 76915794Sleres } 77020997Skarels 77124793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 77215794Sleres if (m == NULL) { 77320997Skarels vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit, 77415794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7757640Ssam goto dropit; 77615794Sleres } 7777640Ssam if (off) { 77824793Skarels struct ifnet *ifp; 77924793Skarels 78024793Skarels ifp = *(mtod(m, struct ifnet **)); 78124793Skarels m->m_off += 2 * sizeof (u_short); 78224793Skarels m->m_len -= 2 * sizeof (u_short); 78324793Skarels *(mtod(m, struct ifnet **)) = ifp; 7847640Ssam } 78511192Ssam 78615794Sleres /* Keep track of source address of this packet */ 78715794Sleres vs->vs_lastr = vv->vh_shost; 78820997Skarels 78911192Ssam /* 79015764Sleres * Demultiplex on packet type 79111192Ssam */ 7927024Ssam switch (vv->vh_type) { 79311192Ssam 7947024Ssam #ifdef INET 7957024Ssam case RING_IP: 7967024Ssam schednetisr(NETISR_IP); 7977024Ssam inq = &ipintrq; 7987024Ssam break; 7997024Ssam #endif 8007024Ssam default: 80120997Skarels vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 8027640Ssam m_freem(m); 8037024Ssam goto setup; 8047024Ssam } 80515794Sleres s = splimp(); 8067640Ssam if (IF_QFULL(inq)) { 8077640Ssam IF_DROP(inq); 8087640Ssam m_freem(m); 80911209Ssam } else 8107640Ssam IF_ENQUEUE(inq, m); 81115764Sleres 81215794Sleres splx(s); 8137024Ssam /* 81415764Sleres * Reset for the next packet. 8157024Ssam */ 81615764Sleres setup: 81735805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 81835805Skarels addr->vviba = (u_short) ubaaddr; 81935805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 82020997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 82120997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 82215764Sleres return; 82311192Ssam 82411192Ssam /* 82511209Ssam * Drop packet on floor -- count them!! 82611192Ssam */ 8277640Ssam dropit: 8287640Ssam vs->vs_if.if_ierrors++; 8297640Ssam goto setup; 8307024Ssam } 8317024Ssam 8327024Ssam /* 83320997Skarels * proNET output routine. 8347024Ssam * Encapsulate a packet of type family for the local net. 8357024Ssam * Use trailer local net encapsulation if enough data in first 8367024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8377024Ssam */ 8387024Ssam vvoutput(ifp, m0, dst) 8397024Ssam struct ifnet *ifp; 8407024Ssam struct mbuf *m0; 8417024Ssam struct sockaddr *dst; 8427024Ssam { 84316581Skarels register struct mbuf *m; 8447024Ssam register struct vv_header *vv; 8457640Ssam register int off; 84616581Skarels register int unit; 84716581Skarels register struct vvreg *addr; 84816581Skarels register struct vv_softc *vs; 84916581Skarels register int s; 85016581Skarels int type, dest, error; 8517024Ssam 85216581Skarels m = m0; 85316581Skarels unit = ifp->if_unit; 85416581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 85516581Skarels vs = &vv_softc[unit]; 85620997Skarels 85716581Skarels /* 85820997Skarels * Check to see if the input side has wedged due the UBA 85920997Skarels * vectoring through 0. 86016581Skarels * 86116581Skarels * We are lower than device ipl when we enter this routine, 86216581Skarels * so if the interface is ready with an input packet then 86316581Skarels * an input interrupt must have slipped through the cracks. 86416581Skarels * 86516581Skarels * Avoid the race with an input interrupt by watching to see 86616581Skarels * if any packets come in. 86716581Skarels */ 86816581Skarels s = vs->vs_if.if_ipackets; 86916581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 87020997Skarels vvprintf("vv%d: lost a receive interrupt, icsr = %b\n", 87116581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 87216581Skarels s = splimp(); 87316581Skarels vvrint(unit); 87416581Skarels splx(s); 87516581Skarels } 87616581Skarels 8777024Ssam switch (dst->sa_family) { 87811192Ssam 8797024Ssam #ifdef INET 88015764Sleres case AF_INET: 88121779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 88221779Skarels dest = VV_BROADCAST; 88321779Skarels else 88421779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 88520997Skarels #ifdef LOOPBACK 88621779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 88721779Skarels return (looutput(&loif, m0, dst)); 88820997Skarels #endif LOOPBACK 88921779Skarels if (dest >= 0x100) { 8907640Ssam error = EPERM; 8917640Ssam goto bad; 8927640Ssam } 8937640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 89420997Skarels /* 89520997Skarels * Trailerize, if the configuration allows it. 89620997Skarels * TODO: Need per host negotiation. 89720997Skarels */ 89813090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 89913090Ssam if (off > 0 && (off & 0x1ff) == 0 && 9007640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 90126950Sjas type = RING_TRAILER; 9027640Ssam m->m_off -= 2 * sizeof (u_short); 9037640Ssam m->m_len += 2 * sizeof (u_short); 90428954Skarels *mtod(m, u_short *) = htons((short)RING_IP); 90528954Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 9067640Ssam goto gottrailertype; 9077640Ssam } 9087024Ssam type = RING_IP; 9097024Ssam off = 0; 9107024Ssam goto gottype; 9117024Ssam #endif 9127024Ssam default: 91316581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 9147640Ssam error = EAFNOSUPPORT; 9157640Ssam goto bad; 9167024Ssam } 9177024Ssam 9187024Ssam gottrailertype: 9197024Ssam /* 9207024Ssam * Packet to be sent as trailer: move first packet 9217024Ssam * (control information) to end of chain. 9227024Ssam */ 9237024Ssam while (m->m_next) 9247024Ssam m = m->m_next; 9257024Ssam m->m_next = m0; 9267024Ssam m = m0->m_next; 9277024Ssam m0->m_next = 0; 9287024Ssam m0 = m; 9297024Ssam gottype: 9307024Ssam /* 9317024Ssam * Add local net header. If no space in first mbuf, 9327024Ssam * allocate another. 9337024Ssam */ 9347024Ssam if (m->m_off > MMAXOFF || 9357024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 93611209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 93711209Ssam if (m == NULL) { 9387640Ssam error = ENOBUFS; 9397640Ssam goto bad; 9407024Ssam } 9417024Ssam m->m_next = m0; 9427024Ssam m->m_off = MMINOFF; 9437024Ssam m->m_len = sizeof (struct vv_header); 9447024Ssam } else { 9457024Ssam m->m_off -= sizeof (struct vv_header); 9467024Ssam m->m_len += sizeof (struct vv_header); 9477024Ssam } 9487024Ssam vv = mtod(m, struct vv_header *); 94921779Skarels vv->vh_shost = vs->vs_host; 95021779Skarels vv->vh_dhost = dest; 9517024Ssam vv->vh_version = RING_VERSION; 9527024Ssam vv->vh_type = type; 95328954Skarels vv->vh_info = htons((u_short)off); 95411192Ssam vvtracehdr("vo", vv); 9557024Ssam 9567024Ssam /* 9577024Ssam * Queue message on interface, and start output if interface 9587024Ssam * not yet active. 9597024Ssam */ 9607024Ssam s = splimp(); 9617640Ssam if (IF_QFULL(&ifp->if_snd)) { 9627640Ssam IF_DROP(&ifp->if_snd); 9637640Ssam error = ENOBUFS; 9647640Ssam goto qfull; 9657640Ssam } 9667024Ssam IF_ENQUEUE(&ifp->if_snd, m); 96716581Skarels if (vs->vs_oactive == 0) 96816581Skarels vvstart(unit); 9697024Ssam splx(s); 9707640Ssam return (0); 9717640Ssam qfull: 9727640Ssam m0 = m; 9737640Ssam splx(s); 9747640Ssam bad: 9757640Ssam m_freem(m0); 9767640Ssam return(error); 9777024Ssam } 9787024Ssam 9797024Ssam /* 98013057Ssam * Process an ioctl request. 98113057Ssam */ 98213057Ssam vvioctl(ifp, cmd, data) 98313057Ssam register struct ifnet *ifp; 98413057Ssam int cmd; 98513057Ssam caddr_t data; 98613057Ssam { 98721779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 98821779Skarels int s = splimp(), error = 0; 98913057Ssam 99013057Ssam switch (cmd) { 99113057Ssam 99213057Ssam case SIOCSIFADDR: 99321779Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 99413057Ssam vvinit(ifp->if_unit); 99526903Sjas /* 99626903Sjas * Did self-test succeed? 99726903Sjas */ 99826903Sjas if ((ifp->if_flags & IFF_UP) == 0) 99926903Sjas error = ENETDOWN; 1000*36085Skarels else { 1001*36085Skarels /* 1002*36085Skarels * Attempt to check agreement of protocol address 1003*36085Skarels * and board address. 1004*36085Skarels */ 1005*36085Skarels switch (ifa->ifa_addr.sa_family) { 1006*36085Skarels case AF_INET: 1007*36085Skarels if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) != 1008*36085Skarels vv_softc[ifp->if_unit].vs_host) 1009*36085Skarels error = EADDRNOTAVAIL; 1010*36085Skarels break; 1011*36085Skarels } 101221779Skarels } 101313057Ssam break; 101413057Ssam 101513057Ssam default: 101613057Ssam error = EINVAL; 101713057Ssam } 101813057Ssam splx(s); 101921779Skarels return (error); 102013057Ssam } 102125190Skarels 102225190Skarels /* 102325190Skarels * vvprt_hdr(s, v) print the local net header in "v" 102425190Skarels * with title is "s" 102525190Skarels */ 102625190Skarels vvprt_hdr(s, v) 102725190Skarels char *s; 102825190Skarels register struct vv_header *v; 102925190Skarels { 103025190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 103125190Skarels s, 103225190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 103325190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 103425190Skarels 0xffff & (int)(v->vh_info)); 103525190Skarels } 103626903Sjas #endif NVV 1037