home *** CD-ROM | disk | FTP | other *** search
- /*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Tim L. Tucker.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)if_we.c 7.3 (Berkeley) 5/21/91
- */
-
- /*
- * Modification history
- *
- * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
- */
-
- #include "we.h"
- #if NWE > 0
- /*
- * Western Digital 8003 ethernet/starlan adapter
- *
- * Supports the following interface cards:
- * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT
- *
- * The Western Digital card is one of many AT/MCA ethernet interfaces
- * based on the National DS8390 Network Interface chip set.
- */
- #include "param.h"
- #include "mbuf.h"
- #include "socket.h"
- #include "ioctl.h"
- #include "errno.h"
- #include "syslog.h"
-
- #include "net/if.h"
- #include "net/netisr.h"
-
- #ifdef INET
- #include "netinet/in.h"
- #include "netinet/in_systm.h"
- #include "netinet/in_var.h"
- #include "netinet/ip.h"
- #include "netinet/if_ether.h"
- #endif
-
- #ifdef NS
- #include "netns/ns.h"
- #include "netns/ns_if.h"
- #endif
-
- #include "i386/isa/if_wereg.h"
- #include "i386/isa/isa_device.h"
-
- /*
- * This constant should really be 60 because the we adds 4 bytes of crc.
- * However when set to 60 our packets are ignored by deuna's , 3coms are
- * okay ??????????????????????????????????????????
- */
- #define ETHER_MIN_LEN 64
- #define ETHER_ADDR_LEN 6
- #define ETHER_HDR_SIZE 14
-
- /*
- * Ethernet software status per interface.
- *
- * Each interface is referenced by a network interface structure,
- * qe_if, which the routing code uses to locate the interface.
- * This structure contains the output queue for the interface, its address, ...
- */
- struct we_softc {
- struct arpcom we_ac; /* Ethernet common part */
- #define we_if we_ac.ac_if /* network-visible interface */
- #define we_addr we_ac.ac_enaddr /* hardware Ethernet address */
-
- u_char we_flags; /* software state */
- #define WDF_RUNNING 0x01
- #define WDF_TXBUSY 0x02
-
- u_char we_type; /* interface type code */
- u_short we_vector; /* interrupt vector */
- short we_io_ctl_addr; /* i/o bus address, control */
- short we_io_nic_addr; /* i/o bus address, DS8390 */
-
- caddr_t we_vmem_addr; /* card RAM virtual memory base */
- u_long we_vmem_size; /* card RAM bytes */
- caddr_t we_vmem_ring; /* receive ring RAM vaddress */
- caddr_t we_vmem_end; /* receive ring RAM end */
- } we_softc[NWE];
-
- int weprobe(), weattach(), weintr(), westart();
- int weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
-
- struct isa_driver wedriver = {
- weprobe, weattach, "we",
- };
-
- /*
- * Probe the WD8003 to see if it's there
- */
- weprobe(is)
- struct isa_device *is;
- {
- register int i;
- register struct we_softc *sc = &we_softc[is->id_unit];
- union we_mem_sel wem;
- u_char sum;
-
- /*
- * Here we check the card ROM, if the checksum passes, and the
- * type code and ethernet address check out, then we know we have
- * a wd8003 card.
- *
- * Autoconfiguration: No warning message is printed on error.
- */
- for (sum = 0, i = 0; i < 8; ++i)
- sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
- if (sum != WD_CHECKSUM)
- return (0);
- sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
- if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN)
- && (sc->we_type != WD_ETHER2))
- return (0);
-
- /*
- * Setup card RAM area and i/o addresses
- * Kernel Virtual to segment C0000-DFFFF?????
- */
- sc->we_io_ctl_addr = is->id_iobase;
- sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
- sc->we_vector = is->id_irq;
- sc->we_vmem_addr = (caddr_t)is->id_maddr;
- sc->we_vmem_size = is->id_msize;
- sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
- sc->we_vmem_end = sc->we_vmem_addr + is->id_msize;
-
- /*
- * Save board ROM station address
- */
- for (i = 0; i < ETHER_ADDR_LEN; ++i)
- sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
-
- /*
- * Mapin interface memory, setup memory select register
- */
- /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */
- wem.ms_addr = (u_long)(0xd0000)>> 13;
- wem.ms_enable = 1;
- wem.ms_reset = 0;
- outb(sc->we_io_ctl_addr, wem.ms_byte);
-
- /*
- * clear interface memory, then sum to make sure its valid
- */
- for (i = 0; i < sc->we_vmem_size; ++i)
- sc->we_vmem_addr[i] = 0x0;
- for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
- sum += sc->we_vmem_addr[i];
- if (sum != 0x0) {
- printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
- return (0);
- }
-
- return (WD_IO_PORTS);
- }
-
- /*
- * Interface exists: make available by filling in network interface
- * record. System will initialize the interface when it is ready
- * to accept packets.
- */
- weattach(is)
- struct isa_device *is;
- {
- register struct we_softc *sc = &we_softc[is->id_unit];
- register struct ifnet *ifp = &sc->we_if;
- union we_command wecmd;
-
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_stp = 1;
- wecmd.cs_sta = 0;
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- /*
- * Initialize ifnet structure
- */
- ifp->if_unit = is->id_unit;
- ifp->if_name = "we" ;
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ;
- ifp->if_init = weinit;
- ifp->if_output = ether_output;
- ifp->if_start = westart;
- ifp->if_ioctl = weioctl;
- ifp->if_reset = wereset;
- ifp->if_watchdog = wewatchdog;
- if_attach(ifp);
-
- /*
- * Banner...
- */
- printf(" %s address %s",
- ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"),
- ether_sprintf(sc->we_addr));
- }
-
- /*
- * Reset of interface.
- */
- wereset(unit, uban)
- int unit, uban;
- {
- if (unit >= NWE)
- return;
- printf("we%d: reset\n", unit);
- /* we_softc[unit].we_flags &= ~WDF_RUNNING; */
- weinit(unit);
- }
-
- /*
- * Take interface offline.
- */
- westop(unit)
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
- union we_command wecmd;
- int s;
-
- /*
- * Shutdown DS8390
- */
- s = splimp();
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_stp = 1;
- wecmd.cs_sta = 0;
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- (void) splx(s);
- }
-
- wewatchdog(unit) {
-
- log(LOG_WARNING,"we%d: soft reset\n", unit);
- westop(unit);
- weinit(unit);
- }
-
- static Bdry;
- /*
- * Initialization of interface (really just DS8390).
- */
- weinit(unit)
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
- register struct ifnet *ifp = &sc->we_if;
- union we_command wecmd;
- int i, s;
-
- /* address not known */
- if (ifp->if_addrlist == (struct ifaddr *)0)
- return;
-
- /* already running */
- /*if (ifp->if_flags & IFF_RUNNING) return; */
-
- /*
- * Initialize DS8390 in order given in NSC NIC manual.
- * this is stock code...please see the National manual for details.
- */
- s = splhigh();
- Bdry = 0;
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_stp = 1;
- wecmd.cs_sta = 0;
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
- outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
- outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
- outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
- outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
- outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
- outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
- outb(sc->we_io_nic_addr + WD_P0_PSTOP,
- sc->we_vmem_size / WD_PAGE_SIZE);
- outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
- outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
- outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
- wecmd.cs_ps = 1;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- for (i = 0; i < ETHER_ADDR_LEN; ++i)
- outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
- for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
- outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
- outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
- wecmd.cs_ps = 0;
- wecmd.cs_stp = 0;
- wecmd.cs_sta = 1;
- wecmd.cs_rd = 0x4;
- outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
- outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
-
- /*
- * Take the interface out of reset, program the vector,
- * enable interrupts, and tell the world we are up.
- */
- ifp->if_flags |= IFF_RUNNING;
- sc->we_flags &= ~WDF_TXBUSY;
- (void) splx(s);
- westart(ifp);
- }
-
- /*
- * Start output on interface.
- */
- westart(ifp)
- struct ifnet *ifp;
- {
- register struct we_softc *sc = &we_softc[ifp->if_unit];
- struct mbuf *m0, *m;
- register caddr_t buffer;
- int len, s;
- union we_command wecmd;
-
- /*
- * The DS8390 has only one transmit buffer, if it is busy we
- * must wait until the transmit interrupt completes.
- */
- s = splhigh();
- if (sc->we_flags & WDF_TXBUSY) {
- (void) splx(s);
- return;
- }
- IF_DEQUEUE(&sc->we_if.if_snd, m);
- if (m == 0) {
- (void) splx(s);
- return;
- }
- sc->we_flags |= WDF_TXBUSY;
- (void) splx(s);
-
- /*
- * Copy the mbuf chain into the transmit buffer
- */
- buffer = sc->we_vmem_addr;
- len = 0;
- for (m0 = m; m != 0; m = m->m_next) {
- bcopy(mtod(m, caddr_t), buffer, m->m_len);
- buffer += m->m_len;
- len += m->m_len;
- }
-
- m_freem(m0);
-
- /*
- * Init transmit length registers, and set transmit start flag.
- */
- s = splhigh();
- len = MAX(len, ETHER_MIN_LEN);
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
- outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
- wecmd.cs_txp = 1;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- (void) splx(s);
- }
-
- /*
- * Ethernet interface interrupt processor
- */
- weintr(unit)
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
- union we_command wecmd;
- union we_interrupt weisr;
-
- unit =0;
-
- /* disable onboard interrupts, then get interrupt status */
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
- loop:
- outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
-
- /* transmit error */
- if (weisr.is_txe) {
- /* need to read these registers to clear status */
- sc->we_if.if_collisions +=
- inb(sc->we_io_nic_addr + WD_P0_TBCR0);
- ++sc->we_if.if_oerrors;
- }
-
- /* receiver error */
- if (weisr.is_rxe) {
- /* need to read these registers to clear status */
- (void) inb(sc->we_io_nic_addr + 0xD);
- (void) inb(sc->we_io_nic_addr + 0xE);
- (void) inb(sc->we_io_nic_addr + 0xF);
- ++sc->we_if.if_ierrors;
- }
-
- /* normal transmit complete */
- if (weisr.is_ptx || weisr.is_txe)
- wetint (unit);
-
- /* normal receive notification */
- if (weisr.is_prx || weisr.is_rxe)
- werint (unit);
-
- /* try to start transmit */
- westart(&sc->we_if);
-
- /* re-enable onboard interrupts */
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
- weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
- if (weisr.is_byte) goto loop;
- }
-
- /*
- * Ethernet interface transmit interrupt.
- */
- wetint(unit)
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
-
- /*
- * Do some statistics (assume page zero of NIC mapped in)
- */
- sc->we_flags &= ~WDF_TXBUSY;
- sc->we_if.if_timer = 0;
- ++sc->we_if.if_opackets;
- sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
- }
-
- /*
- * Ethernet interface receiver interrupt.
- */
- werint(unit)
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
- u_char bnry, curr;
- long len;
- union we_command wecmd;
- struct we_ring *wer;
-
- /*
- * Traverse the receive ring looking for packets to pass back.
- * The search is complete when we find a descriptor not in use.
- */
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
- wecmd.cs_ps = 1;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
- if(Bdry)
- bnry =Bdry;
-
- while (bnry != curr)
- {
- /* get pointer to this buffer header structure */
- wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
-
- /* count includes CRC */
- len = wer->we_count - 4;
- if (len > 30 && len <= ETHERMTU+100
- /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/)
- weread(sc, (caddr_t)(wer + 1), len);
- else printf("reject %d", len);
-
- outofbufs:
- wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
- wecmd.cs_ps = 0;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
-
- /* advance on chip Boundry register */
- if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
- bnry = WD_TXBUF_SIZE;
- outb(sc->we_io_nic_addr + WD_P0_BNRY,
- sc->we_vmem_size / WD_PAGE_SIZE-1);
-
- } else {
- if (len > 30 && len <= ETHERMTU+100)
- bnry = wer->we_next_packet;
- else bnry = curr;
-
- /* watch out for NIC overflow, reset Boundry if invalid */
- if ((bnry - 1) < WD_TXBUF_SIZE) {
- outb(sc->we_io_nic_addr + WD_P0_BNRY,
- (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
- bnry = WD_TXBUF_SIZE;
- } else
- outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
- }
-
- /* refresh our copy of CURR */
- wecmd.cs_ps = 1;
- outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
- curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
- }
- Bdry = bnry;
- }
-
- #ifdef shit
- /*
- * Process an ioctl request.
- */
- weioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- int cmd;
- caddr_t data;
- {
- struct we_softc *sc = &we_softc[ifp->if_unit];
- struct ifaddr *ifa = (struct ifaddr *)data;
- int s = splimp(), error = 0;
-
- switch (cmd) {
-
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- weinit(ifp->if_unit);
- switch(ifa->ifa_addr->sa_family) {
- #ifdef INET
- case AF_INET:
- ((struct arpcom *)ifp)->ac_ipaddr =
- IA_SIN(ifa)->sin_addr;
- arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
- break;
- #endif
- #ifdef NS
- case AF_NS:
- {
- register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
-
- if (ns_nullhost(*ina))
- ina->x_host = *(union ns_host *)(sc->we_addr);
- else
- wesetaddr(ina->x_host.c_host, ifp->if_unit);
- break;
- }
- #endif
- }
- break;
-
- case SIOCSIFFLAGS:
- if (((ifp->if_flags & IFF_UP) == 0) &&
- (sc->we_flags & WDF_RUNNING)) {
- westop(ifp->if_unit);
- } else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
- ((sc->we_flags & WDF_RUNNING) == 0))
- weinit(ifp->if_unit);
- break;
-
- default:
- error = EINVAL;
-
- }
- (void) splx(s);
- return (error);
- }
- #endif
-
- /*
- * Process an ioctl request.
- */
- weioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- int cmd;
- caddr_t data;
- {
- register struct ifaddr *ifa = (struct ifaddr *)data;
- struct we_softc *sc = &we_softc[ifp->if_unit];
- struct ifreq *ifr = (struct ifreq *)data;
- int s = splimp(), error = 0;
-
-
- switch (cmd) {
-
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
-
- switch (ifa->ifa_addr->sa_family) {
- #ifdef INET
- case AF_INET:
- weinit(ifp->if_unit); /* before arpwhohas */
- ((struct arpcom *)ifp)->ac_ipaddr =
- IA_SIN(ifa)->sin_addr;
- arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
- break;
- #endif
- #ifdef NS
- case AF_NS:
- {
- register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
-
- if (ns_nullhost(*ina))
- ina->x_host = *(union ns_host *)(sc->ns_addr);
- else {
- /*
- * The manual says we can't change the address
- * while the receiver is armed,
- * so reset everything
- */
- ifp->if_flags &= ~IFF_RUNNING;
- bcopy((caddr_t)ina->x_host.c_host,
- (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
- }
- weinit(ifp->if_unit); /* does ne_setaddr() */
- break;
- }
- #endif
- default:
- weinit(ifp->if_unit);
- break;
- }
- break;
-
- case SIOCSIFFLAGS:
- if ((ifp->if_flags & IFF_UP) == 0 &&
- ifp->if_flags & IFF_RUNNING) {
- ifp->if_flags &= ~IFF_RUNNING;
- westop(ifp->if_unit);
- } else if (ifp->if_flags & IFF_UP &&
- (ifp->if_flags & IFF_RUNNING) == 0)
- weinit(ifp->if_unit);
- break;
-
- #ifdef notdef
- case SIOCGHWADDR:
- bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
- sizeof(sc->sc_addr));
- break;
- #endif
-
- default:
- error = EINVAL;
- }
- splx(s);
- return (error);
- }
- /*
- * set ethernet address for unit
- */
- wesetaddr(physaddr, unit)
- u_char *physaddr;
- int unit;
- {
- register struct we_softc *sc = &we_softc[unit];
- register int i;
-
- /*
- * Rewrite ethernet address, and then force restart of NIC
- */
- for (i = 0; i < ETHER_ADDR_LEN; i++)
- sc->we_addr[i] = physaddr[i];
- sc->we_flags &= ~WDF_RUNNING;
- weinit(unit);
- }
-
- #define wedataaddr(sc, eh, off, type) \
- ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \
- (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \
- + (sc)->we_vmem_ring: \
- ((caddr_t)((eh)+1)+(off)))
- /*
- * Pass a packet to the higher levels.
- * We deal with the trailer protocol here.
- */
- weread(sc, buf, len)
- register struct we_softc *sc;
- char *buf;
- int len;
- {
- register struct ether_header *eh;
- struct mbuf *m, *weget();
- int off, resid;
-
- /*
- * Deal with trailer protocol: if type is trailer type
- * get true type from first 16-bit word past data.
- * Remember that type was trailer by setting off.
- */
- eh = (struct ether_header *)buf;
- eh->ether_type = ntohs((u_short)eh->ether_type);
- if (eh->ether_type >= ETHERTYPE_TRAIL &&
- eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
- off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
- if (off >= ETHERMTU) return; /* sanity */
- eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *));
- resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *)));
- if (off + resid > len) return; /* sanity */
- len = off + resid;
- } else off = 0;
-
- len -= sizeof(struct ether_header);
- if (len <= 0) return;
-
- /*
- * Pull packet off interface. Off is nonzero if packet
- * has trailing header; neget will then force this header
- * information to be at the front, but we still have to drop
- * the type and length which are at the front of any trailer data.
- */
- m = weget(buf, len, off, &sc->we_if, sc);
- if (m == 0) return;
- ether_input(&sc->we_if, eh, m);
- }
-
- /*
- * Supporting routines
- */
-
- /*
- * Pull read data off a interface.
- * Len is length of data, with local net header stripped.
- * Off is non-zero if a trailer protocol was used, and
- * gives the offset of the trailer information.
- * We copy the trailer information and then all the normal
- * data into mbufs. When full cluster sized units are present
- * we copy into clusters.
- */
- struct mbuf *
- weget(buf, totlen, off0, ifp, sc)
- caddr_t buf;
- int totlen, off0;
- struct ifnet *ifp;
- struct we_softc *sc;
- {
- struct mbuf *top, **mp, *m, *p;
- int off = off0, len;
- register caddr_t cp = buf;
- char *epkt;
- int tc =totlen;
-
- buf += sizeof(struct ether_header);
- cp = buf;
- epkt = cp + totlen;
-
- if (off) {
- cp += off + 2 * sizeof(u_short);
- totlen -= 2 * sizeof(u_short);
- }
-
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == 0)
- return (0);
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = totlen;
- m->m_len = MHLEN;
-
- top = 0;
- mp = ⊤
- while (totlen > 0) {
- if (top) {
- MGET(m, M_DONTWAIT, MT_DATA);
- if (m == 0) {
- m_freem(top);
- return (0);
- }
- m->m_len = MLEN;
- }
- len = min(totlen, epkt - cp);
- if (len >= MINCLSIZE) {
- MCLGET(m, M_DONTWAIT);
- if (m->m_flags & M_EXT)
- m->m_len = len = min(len, MCLBYTES);
- else
- len = m->m_len;
- } else {
- /*
- * Place initial small packet/header at end of mbuf.
- */
- if (len < m->m_len) {
- if (top == 0 && len + max_linkhdr <= m->m_len)
- m->m_data += max_linkhdr;
- m->m_len = len;
- } else
- len = m->m_len;
- }
-
- totlen -= len;
- /* only do up to end of buffer */
- if (cp+len > sc->we_vmem_end) {
- unsigned toend = sc->we_vmem_end - cp;
-
- bcopy(cp, mtod(m, caddr_t), toend);
- cp = sc->we_vmem_ring;
- bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
- cp += len - toend;
- epkt = cp + totlen;
- } else {
- bcopy(cp, mtod(m, caddr_t), (unsigned)len);
- cp += len;
- }
- *mp = m;
- mp = &m->m_next;
- if (cp == epkt) {
- cp = buf;
- epkt = cp + tc;
- }
- }
- return (top);
- }
- #endif
-