📄 if_le.c
字号:
/* * Copyright (c) 1982, 1990, 1993 * The Regents of the University of California. All rights reserved. * * 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_le.c 8.1 (Berkeley) 6/10/93 */#include "le.h"#if NLE > 0#include "bpfilter.h"/* * AMD 7990 LANCE * * This driver will accept tailer encapsulated packets even * though it buys us nothing. The motivation was to avoid incompatibilities * with VAXen, SUNs, and others that handle and benefit from them. * This reasoning is dubious. */#include <sys/param.h>#include <sys/proc.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/syslog.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <net/if.h>#include <net/netisr.h>#include <net/route.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#if defined (CCITT) && defined (LLC)#include <sys/socketvar.h>#include <netccitt/x25.h>extern llc_ctlinput(), cons_rtrequest();#endif#include <machine/cpu.h>#include <hp300/hp300/isr.h>#include <machine/mtpr.h>#include <hp/dev/device.h>#include <hp300/dev/if_lereg.h>#ifdef USELEDS#include <hp300/hp300/led.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif/* offsets for: ID, REGS, MEM, NVRAM */int lestd[] = { 0, 0x4000, 0x8000, 0xC008 };int leattach();struct driver ledriver = { leattach, "le",};struct isr le_isr[NLE];int ledebug = 0; /* console error messages */int leintr(), leinit(), leioctl(), lestart(), ether_output(), lereset();struct mbuf *m_devget();extern struct ifnet loif;/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * le_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct le_softc { struct arpcom sc_ac; /* common Ethernet structures */#define sc_if sc_ac.ac_if /* network-visible interface */#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ struct lereg0 *sc_r0; /* DIO registers */ struct lereg1 *sc_r1; /* LANCE registers */ struct lereg2 *sc_r2; /* dual-port RAM */ int sc_rmd; /* predicted next rmd to process */ int sc_tmd; /* next available tmd */ int sc_txcnt; /* # of transmit buffers in use */ /* stats */ int sc_runt; int sc_jab; int sc_merr; int sc_babl; int sc_cerr; int sc_miss; int sc_rown; int sc_xown; int sc_xown2; int sc_uflo; int sc_rxlen; int sc_rxoff; int sc_txoff; int sc_busy; short sc_iflags;} le_softc[NLE];/* access LANCE registers */#define LERDWR(cntl, src, dst) \ do { \ (dst) = (src); \ } while (((cntl)->ler0_status & LE_ACK) == 0);/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */leattach(hd) struct hp_device *hd;{ register struct lereg0 *ler0; register struct lereg2 *ler2; struct lereg2 *lemem = 0; struct le_softc *le = &le_softc[hd->hp_unit]; struct ifnet *ifp = &le->sc_if; char *cp; int i; ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); if (ler0->ler0_id != LEID) return(0); le_isr[hd->hp_unit].isr_intr = leintr; hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); le_isr[hd->hp_unit].isr_arg = hd->hp_unit; ler0->ler0_id = 0xFF; DELAY(100); /* * Read the ethernet address off the board, one nibble at a time. */ cp = (char *)(lestd[3] + (int)hd->hp_addr); for (i = 0; i < sizeof(le->sc_addr); i++) { le->sc_addr[i] = (*++cp & 0xF) << 4; cp++; le->sc_addr[i] |= *++cp & 0xF; cp++; } printf("le%d: hardware address %s\n", hd->hp_unit, ether_sprintf(le->sc_addr)); /* * Setup for transmit/receive */ ler2->ler2_mode = LE_MODE; ler2->ler2_ladrf[0] = 0; ler2->ler2_ladrf[1] = 0; ler2->ler2_rlen = LE_RLEN; ler2->ler2_rdra = (int)lemem->ler2_rmd; ler2->ler2_tlen = LE_TLEN; ler2->ler2_tdra = (int)lemem->ler2_tmd; isrlink(&le_isr[hd->hp_unit]); ler0->ler0_status = LE_IE; ifp->if_unit = hd->hp_unit; ifp->if_name = "le"; ifp->if_mtu = ETHERMTU; ifp->if_init = leinit; ifp->if_reset = lereset; ifp->if_ioctl = leioctl; ifp->if_output = ether_output; ifp->if_start = lestart;#ifdef MULTICAST ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;#else ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;#endif#if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif if_attach(ifp); return (1);}#ifdef MULTICAST/* * Setup the logical address filter */voidlesetladrf(sc) register struct le_softc *sc;{ register volatile struct lereg2 *ler2 = sc->sc_r2; register struct ifnet *ifp = &sc->sc_if; register struct ether_multi *enm; register u_char *cp; register u_long crc; register u_long c; register int i, len; struct ether_multistep step; /* * Set up multicast address filter by passing all multicast * addresses through a crc generator, and then using the high * order 6 bits as a index into the 64 bit logical address * filter. The high order two bits select the word, while the * rest of the bits select the bit within the word. */ ler2->ler2_ladrf[0] = 0; ler2->ler2_ladrf[1] = 0; ifp->if_flags &= ~IFF_ALLMULTI; ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); while (enm != NULL) { if (bcmp((caddr_t)&enm->enm_addrlo, (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) { /* * We must listen to a range of multicast * addresses. For now, just accept all * multicasts, rather than trying to set only * those filter bits needed to match the range. * (At this time, the only use of address * ranges is for IP multicast routing, for * which the range is big enough to require all * bits set.) */ ler2->ler2_ladrf[0] = 0xffffffff; ler2->ler2_ladrf[1] = 0xffffffff; ifp->if_flags |= IFF_ALLMULTI; return; } cp = (unsigned char *)&enm->enm_addrlo; c = *cp; crc = 0xffffffff; len = 6; while (len-- > 0) { c = *cp; for (i = 0; i < 8; i++) { if ((c & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ 0xedb88320; } else crc >>= 1; c >>= 1; } cp++; } /* Just want the 6 most significant bits. */ crc = crc >> 26; /* Turn on the corresponding bit in the filter. */ ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f); ETHER_NEXT_MULTI(step, enm); }}#endifledrinit(ler2, le) register struct lereg2 *ler2; register struct le_softc *le;{ register struct lereg2 *lemem = 0; register int i; ler2->ler2_padr[0] = le->sc_addr[1]; ler2->ler2_padr[1] = le->sc_addr[0]; ler2->ler2_padr[2] = le->sc_addr[3]; ler2->ler2_padr[3] = le->sc_addr[2]; ler2->ler2_padr[4] = le->sc_addr[5]; ler2->ler2_padr[5] = le->sc_addr[4]; for (i = 0; i < LERBUF; i++) { ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; ler2->ler2_rmd[i].rmd1 = LE_OWN; ler2->ler2_rmd[i].rmd2 = -LEMTU; ler2->ler2_rmd[i].rmd3 = 0; } for (i = 0; i < LETBUF; i++) { ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; ler2->ler2_tmd[i].tmd1 = 0; ler2->ler2_tmd[i].tmd2 = 0; ler2->ler2_tmd[i].tmd3 = 0; } /* Setup the logical address filter */#ifdef MULTICAST lesetladrf(le);#else ler2->ler2_ladrf[0] = 0; ler2->ler2_ladrf[1] = 0;#endif}lereset(unit) register int unit;{ register struct le_softc *le = &le_softc[unit]; register struct lereg0 *ler0 = le->sc_r0; register struct lereg1 *ler1 = le->sc_r1; register struct lereg2 *lemem = 0; register int timo = 100000; register int stat;#ifdef lint stat = unit;#endif#if NBPFILTER > 0 if (le->sc_if.if_flags & IFF_PROMISC) /* set the promiscuous bit */ le->sc_r2->ler2_mode = LE_MODE|0x8000; else le->sc_r2->ler2_mode = LE_MODE;#endif LERDWR(ler0, LE_CSR0, ler1->ler1_rap); LERDWR(ler0, LE_STOP, ler1->ler1_rdp); ledrinit(le->sc_r2, le); le->sc_rmd = le->sc_tmd = 0; LERDWR(ler0, LE_CSR1, ler1->ler1_rap); LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); LERDWR(ler0, LE_CSR2, ler1->ler1_rap); LERDWR(ler0, 0, ler1->ler1_rdp); LERDWR(ler0, LE_CSR0, ler1->ler1_rap); LERDWR(ler0, LE_INIT, ler1->ler1_rdp); do { if (--timo == 0) { printf("le%d: init timeout, stat = 0x%x\n", unit, stat); break; } LERDWR(ler0, ler1->ler1_rdp, stat); } while ((stat & LE_IDON) == 0); LERDWR(ler0, LE_STOP, ler1->ler1_rdp); LERDWR(ler0, LE_CSR3, ler1->ler1_rap); LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); LERDWR(ler0, LE_CSR0, ler1->ler1_rap); LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); le->sc_if.if_flags &= ~IFF_OACTIVE; le->sc_txcnt = 0;}/* * Initialization of interface */leinit(unit) int unit;{ register struct ifnet *ifp = &le_softc[unit].sc_if; register struct ifaddr *ifa; int s; /* not yet, if address still unknown */ for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) if (ifa == 0) return; else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) break; if ((ifp->if_flags & IFF_RUNNING) == 0) { s = splimp(); ifp->if_flags |= IFF_RUNNING; lereset(unit); (void) lestart(ifp); splx(s); }}/* * Start output on interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */lestart(ifp) struct ifnet *ifp;{ register struct le_softc *le = &le_softc[ifp->if_unit]; register struct letmd *tmd; register struct mbuf *m; int len; if ((le->sc_if.if_flags & IFF_RUNNING) == 0) return (0); tmd = &le->sc_r2->ler2_tmd[le->sc_tmd]; do { if (tmd->tmd1 & LE_OWN) { le->sc_xown2++; return (0); } IF_DEQUEUE(&le->sc_if.if_snd, m); if (m == 0) return (0); len = leput(le->sc_r2->ler2_tbuf[le->sc_tmd], m);#if NBPFILTER > 0 /* * If bpf is listening on this interface, let it * see the packet before we commit it to the wire. */ if (ifp->if_bpf) bpf_tap(ifp->if_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd], len);#endif tmd->tmd3 = 0; tmd->tmd2 = -len; tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; if (++le->sc_tmd == LETBUF) { le->sc_tmd = 0; tmd = le->sc_r2->ler2_tmd; } else tmd++; } while (++le->sc_txcnt < LETBUF); le->sc_if.if_flags |= IFF_OACTIVE; return (0);}leintr(unit) register int unit;{ register struct le_softc *le = &le_softc[unit]; register struct lereg0 *ler0 = le->sc_r0; register struct lereg1 *ler1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -