📄 if_en.c
字号:
/* * Copyright (c) 1982, 1986 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_en.c 7.7 (Berkeley) 12/16/90 */#include "en.h"#if NEN > 0/* * Xerox prototype (3 Mb) Ethernet interface driver. */#include "../include/pte.h"#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/buf.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/vmmac.h"#include "sys/errno.h"#include "sys/ioctl.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"#endif#ifdef PUP#include "netpup/pup.h"#include "netpup/ether.h"#endif#ifdef NS#include "netns/ns.h"#include "netns/ns_if.h"#endif#include "../include/cpu.h"#include "../include/mtpr.h"#include "if_en.h"#include "if_enreg.h"#include "if_uba.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"#define ENMTU (1024+512)#define ENMRU (1024+512+16) /* 16 is enough to receive trailer */int enprobe(), enattach(), enrint(), enxint(), encollide();struct uba_device *eninfo[NEN];u_short enstd[] = { 0 };struct uba_driver endriver = { enprobe, 0, enattach, 0, enstd, "en", eninfo };#define ENUNIT(x) minor(x)int eninit(),oldenoutput(),enreset(),enioctl(), enstart();#ifdef notdef/* * If you need to byte swap IP's in the system, define * this and do a SIOCSIFFLAGS at boot time. */#define ENF_SWABIPS 0x1000#endif/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * es_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... * We also have, for each interface, a UBA interface structure, which * contains information about the UNIBUS resources held by the interface: * map registers, buffered data paths, etc. Information is cached in this * structure for use by the if_uba.c routines in running the interface * efficiently. */struct en_softc { struct ifnet es_if; /* network-visible interface */ struct ifuba es_ifuba; /* UNIBUS resources */ short es_host; /* hardware host number */ short es_delay; /* current output delay */ short es_mask; /* mask for current output delay */ short es_lastx; /* host last transmitted to */ short es_oactive; /* is output active? */ short es_olen; /* length of last output */ short es_nsactive; /* is interface enabled for ns? */} en_softc[NEN];/* * Do output DMA to determine interface presence and * interrupt vector. DMA is too short to disturb other hosts. */enprobe(reg) caddr_t reg;{ register int br, cvec; /* r11, r10 value-result */ register struct endevice *addr = (struct endevice *)reg;#ifdef lint br = 0; cvec = br; br = cvec; enrint(0); enxint(0); encollide(0);#endif addr->en_istat = 0; addr->en_owc = -1; addr->en_oba = 0; addr->en_ostat = EN_IEN|EN_GO; DELAY(100000); addr->en_ostat = 0; return (1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */enattach(ui) struct uba_device *ui;{ register struct en_softc *es = &en_softc[ui->ui_unit]; es->es_if.if_unit = ui->ui_unit; es->es_if.if_name = "en"; es->es_if.if_mtu = ENMTU; es->es_if.if_flags = IFF_BROADCAST; es->es_if.if_init = eninit; es->es_if.if_output = oldenoutput; es->es_if.if_start = enstart; es->es_if.if_ioctl = enioctl; es->es_if.if_reset = enreset; es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;#if defined(VAX750) /* don't chew up 750 bdp's */ if (cpu == VAX_750 && ui->ui_unit > 0) es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;#endif if_attach(&es->es_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */enreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" en%d", unit); eninit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */eninit(unit) int unit;{ register struct en_softc *es = &en_softc[unit]; register struct uba_device *ui = eninfo[unit]; register struct endevice *addr; int s; if (es->es_if.if_addrlist == (struct ifaddr *)0) return; if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { printf("en%d: can't initialize\n", unit); es->es_if.if_flags &= ~IFF_UP; return; } addr = (struct endevice *)ui->ui_addr; addr->en_istat = addr->en_ostat = 0; /* * Hang a receive and start any * pending writes by faking a transmit complete. */ s = splimp(); addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; addr->en_istat = EN_IEN|EN_GO; es->es_oactive = 1; es->es_if.if_flags |= IFF_RUNNING; enxint(unit); splx(s);}int enalldelay = 0;int enlastdel = 50;int enlastmask = (~0) << 5;/* * Start or restart output on interface. * If interface is already active, then this is a retransmit * after a collision, and just restuff registers and delay. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. */enstart(dev) dev_t dev;{ int unit = ENUNIT(dev); struct uba_device *ui = eninfo[unit]; register struct en_softc *es = &en_softc[unit]; register struct endevice *addr; register struct en_header *en; struct mbuf *m; int dest; if (es->es_oactive) goto restart; /* * Not already active: dequeue another request * and map it to the UNIBUS. If no more requests, * just return. */ IF_DEQUEUE(&es->es_if.if_snd, m); if (m == 0) { es->es_oactive = 0; return; } en = mtod(m, struct en_header *); dest = en->en_dhost; en->en_shost = es->es_host; es->es_olen = if_wubaput(&es->es_ifuba, m);#ifdef ENF_SWABIPS /* * The Xerox interface does word at a time DMA, so * someone must do byte swapping of user data if high * and low ender machines are to communicate. It doesn't * belong here, but certain people depend on it, so... * * Should swab everybody, but this is a kludge anyway. */ if (es->es_if.if_flags & ENF_SWABIPS) { en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; if (en->en_type == ENTYPE_IP) enswab((caddr_t)(en + 1), (caddr_t)(en + 1), es->es_olen - sizeof (struct en_header) + 1); }#endif /* * Ethernet cannot take back-to-back packets (no * buffering in interface. To help avoid overrunning * receivers, enforce a small delay (about 1ms) in interface: * * between all packets when enalldelay * * whenever last packet was broadcast * * whenever this packet is to same host as last packet */ if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { es->es_delay = enlastdel; es->es_mask = enlastmask; } es->es_lastx = dest;restart: /* * Have request mapped to UNIBUS for transmission. * Purge any stale data from this BDP, and start the otput. */ if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); addr = (struct endevice *)ui->ui_addr; addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; addr->en_odelay = es->es_delay; addr->en_owc = -((es->es_olen + 1) >> 1); addr->en_ostat = EN_IEN|EN_GO; es->es_oactive = 1;}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */enxint(unit) int unit;{ register struct uba_device *ui = eninfo[unit]; register struct en_softc *es = &en_softc[unit]; register struct endevice *addr = (struct endevice *)ui->ui_addr; if (es->es_oactive == 0) return; if (es->es_mask && (addr->en_ostat&EN_OERROR)) { es->es_if.if_oerrors++; endocoll(unit); return; } es->es_if.if_opackets++; es->es_oactive = 0; es->es_delay = 0; es->es_mask = ~0; if (es->es_ifuba.ifu_xtofree) { m_freem(es->es_ifuba.ifu_xtofree); es->es_ifuba.ifu_xtofree = 0; } if (es->es_if.if_snd.ifq_head == 0) { es->es_lastx = 256; /* putatively illegal */ return; } enstart(unit);}/* * Collision on ethernet interface. Do exponential * backoff, and retransmit. If have backed off all * the way print warning diagnostic, and drop packet. */encollide(unit) int unit;{ struct en_softc *es = &en_softc[unit]; es->es_if.if_collisions++; if (es->es_oactive == 0) return; endocoll(unit);}endocoll(unit) int unit;{ register struct en_softc *es = &en_softc[unit]; /* * Es_mask is a 16 bit number with n low zero bits, with * n the number of backoffs. When es_mask is 0 we have
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -