* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* @(#)if_we.c 7.3 (Berkeley) 5/21/91
* PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
* -------------------- ----- ----------------------
* CURRENT PATCH LEVEL: 2 00112
* -------------------- ----- ----------------------
* 09 Sep 92 Mike Durkin Fix Danpex EW-2016 & other 8013 clones
* enable with "options WECOMPAT"
* 19 Sep 92 Michael Galassi Fixed multiboard routing
* 20 Sep 92 Barry Lustig WD8013 16 bit mode -- enable
* 14 Mar 93 Marc Frajola BPF packet filter support
* 14 Mar 93 David Greenman Input and other routines re-written
* 14 Mar 93 Rodney W. Grimes Added link level address to we_attach
* 8/28/89 - Initial version(if_wd.c), Tim L Tucker
* 92.09.19 - Changes to allow multiple we interfaces in one box.
* Allowed interupt handler to look at unit other than 0
* Bdry was static, made it into an array w/ one entry per
* interface. nerd@percival.rain.com (Michael Galassi)
* BPF Packet Filter Support added by Marc Frajola, 12/30/92
* Input & other routines re-written by David Greenman, 1/2/93
* BPF trailer support added by David Greenman, 1/7/93
* we_attach enhanced with link level address by Rodney W. Grimes, 1/30/93
* Revision 1.4 1993/08/24 00:15:31 rgrimes
* Fixed the printf's for ethernet address so that ALL ethernet drivers are
* consistent in the format of this.
* Revision 1.3 1993/08/22 22:54:56 ats
* Added a new-line in the output of the ethernet-address that it gets
* on it's line alone ( not mangled with the FPU detection ).
* Commented out a debug printf in if_ec.c ( printf("ecinit") ).
* Revision 1.2 1993/07/29 12:07:10 davidg
* Added include of systm.h to get min/max/bcmp etc...
* Revision 1.1.1.1 1993/06/12 14:58:01 rgrimes
* Initial import, 0.1 + pk 0.2.4-B1
* Revision 1.2 93/02/18 17:21:57 davidg
* Bugs in mbuf cluster allocation fixed
* Problem with nfs wanting mbufs aligned on longword boundries fixed
* 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 "net/if_types.h"
#include "netinet/in_systm.h"
#include "netinet/in_var.h"
#include "netinet/if_ether.h"
#include "i386/isa/isa.h"
#include "i386/isa/if_wereg.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/icu.h"
#include "i386/include/pio.h"
static inline char *we_ring_copy();
* This constant should really be 60 because the we adds 4 bytes of crc.
* However when set to 60 our packets are ignored by deunas , 3coms are
* okay ??????????????????????????????????????????
#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 arpcom arpcom
; /* Ethernet common part */
u_char we_flags
; /* software state */
#define WDF_ATTACHED 0x80
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 */
caddr_t we_bpf
; /* Magic Cookie for BPF */
int weprobe(), weattach(), weintr(), westart();
int weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
struct isa_driver wedriver
= {
static unsigned short wemask
[] =
{ IRQ9
, IRQ3
, IRQ5
, IRQ7
, IRQ10
, IRQ11
, IRQ15
, IRQ4
};
* Probe the WD8003 to see if its there
register struct we_softc
*sc
= &we_softc
[is
->id_unit
];
#ifdef WD8013 /* 20 Sep 92*/
wem
.ms_byte
= 0; /* 20 Sep 92*/
/* reset card to force it into a known state. */
outb(is
->id_iobase
, 0x80);
outb(is
->id_iobase
, 0x00);
/* wait in the case this card is reading it's EEROM */
#ifdef WD8013 /* 20 Sep 92*/
/* allow the NIC to access the shared RAM 16 bits at a time */
outb(is
->id_iobase
+5, laar
.laar_byte
); /* Write a 0xc1 */
* Here we check the card ROM, if the checksum passes, and the
* type code and ethernet address check out, then we know we have
* 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
) { /* 09 Sep 92*/
printf( "we%d: probe: checksum failed... installing anyway\n",
printf( "we%d: Danpex EW-2016 or other 8013 clone card?\n",
sc
->we_type
= inb(is
->id_iobase
+ WD_ROM_OFFSET
+ 6);
if ((sc
->we_type
& WD_REVMASK
) != 2 /* WD8003E or WD8003S */
&& (sc
->we_type
& WD_REVMASK
) != 4 /* WD8003EBT */
&& (sc
->we_type
& WD_REVMASK
) != 6) /* WD8003ELB? */
/*printf("type %x ", sc->we_type);*/
if (sc
->we_type
& WD_SOFTCONFIG
) {
int iv
= inb(is
->id_iobase
+ 1) & 4 |
((inb(is
->id_iobase
+4) & 0x60) >> 5);
/*printf("iv %d ", iv);*/
if (wemask
[iv
] != is
->id_irq
)
outb(is
->id_iobase
+4, inb(is
->id_iobase
+4) | 0x80);
* 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
->arpcom
.ac_enaddr
[i
] = inb(sc
->we_io_ctl_addr
+ WD_ROM_OFFSET
+ i
);
* Mapin interface memory, setup memory select register
wem
.ms_addr
= kvtop(sc
->we_vmem_addr
) >> 13;
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
];
printf("we%d: wd8003 dual port RAM address error\n", is
->id_unit
);
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct we_softc
*sc
= &we_softc
[is
->id_unit
];
register struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
* Initialize ifnet structure
ifp
->if_unit
= is
->id_unit
;
ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_NOTRAILERS
;
ifp
->if_output
= ether_output
;
ifp
->if_watchdog
= wewatchdog
;
/* Search down the ifa address list looking for the AF_LINK type entry */
(ifa
->ifa_addr
->sa_family
!= AF_LINK
))
/* If we find an AF_LINK type entry, we well fill in the hardware addr */
/* Fill in the link level address for this interface */
sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
sdl
->sdl_type
= IFT_ETHER
;
sdl
->sdl_alen
= ETHER_ADDR_LEN
;
bcopy(sc
->arpcom
.ac_enaddr
, LLADDR(sdl
), ETHER_ADDR_LEN
);
sc
->we_flags
&= ~WDF_ATTACHED
; /* Make sure BPF attach flag clear */
printf("we%d: %s address %s\n",
(sc
->we_type
& WD_ETHERNET
) ? "ethernet" : "starlan",
ether_sprintf(sc
->arpcom
.ac_enaddr
));
printf("we%d: reset\n", unit
);
/* we_softc[unit].we_flags &= ~WDF_RUNNING; */
* Take interface offline.
register struct we_softc
*sc
= &we_softc
[unit
];
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
/*log(LOG_WARNING,"we%d: soft reset\n", unit);
static Bdry
[NWE
]; /* 19 Sep 92*/
* Initialization of interface (really just DS8390).
register struct we_softc
*sc
= &we_softc
[unit
];
register struct ifnet
*ifp
= &sc
->arpcom
.ac_if
;
if ((sc
->we_flags
& WDF_ATTACHED
) == 0) {
bpfattach(&sc
->we_bpf
, ifp
, DLT_EN10MB
,
sizeof(struct ether_header
));
sc
->we_flags
|= WDF_ATTACHED
;
if (ifp
->if_addrlist
== (struct ifaddr
*)0)
/*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.
Bdry
[unit
] = 0; /* 19 Sep 92*/
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
#ifdef WD8013 /* 20 Sep 92*/
/* enable 16 bit access if 8013 card */
outb(sc
->we_io_nic_addr
+ WD_P0_DCR
, WD_D_CONFIG16
);
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
);
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
->arpcom
.ac_enaddr
[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
);
outb(sc
->we_io_nic_addr
+ WD_P1_COMMAND
, wecmd
.cs_byte
);
if (sc
->arpcom
.ac_if
.if_flags
& IFF_PROMISC
) {
outb(sc
->we_io_nic_addr
+ WD_P0_RCR
,
WD_R_PRO
| WD_R_SEP
| WD_R_AR
| WD_R_CONFIG
);
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
;
* Start output on interface.
register struct we_softc
*sc
= &we_softc
[ifp
->if_unit
];
* The DS8390 has only one transmit buffer, if it is busy we
* must wait until the transmit interrupt completes.
if (sc
->we_flags
& WDF_TXBUSY
) {
IF_DEQUEUE(&sc
->arpcom
.ac_if
.if_snd
, m
);
sc
->we_flags
|= WDF_TXBUSY
;
int off
, datasize
, resid
;
char ether_packet
[ETHERMTU
+100];
* We handle trailers below:
* Copy ether header first, then residual data,
* then data. Put all this in a temporary buffer
* 'ether_packet' and send off to bpf. Since the
* system has generated this packet, we assume
* that all of the offsets in the packet are
* correct; if they're not, the system will almost
* certainly crash in m_copydata.
* We make no assumptions about how the data is
* arranged in the mbuf chain (i.e. how much
* data is in each mbuf, if mbuf clusters are
* used, etc.), which is why we use m_copydata
* to get the ether header rather than assume
* that this is located in the first mbuf.
m_copydata(m
, 0, sizeof(struct ether_header
), ep
);
eh
= (struct ether_header
*) ep
;
ep
+= sizeof(struct ether_header
);
etype
= ntohs(eh
->ether_type
);
if (etype
>= ETHERTYPE_TRAIL
&&
etype
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
datasize
= ((etype
- ETHERTYPE_TRAIL
) << 9);
off
= datasize
+ sizeof(struct ether_header
);
/* copy trailer_header into a data structure */
m_copydata(m
, off
, sizeof(struct trailer_header
),
&trailer_header
.ether_type
);
m_copydata(m
, off
+sizeof(struct trailer_header
),
resid
= ntohs(trailer_header
.ether_residual
) -
sizeof(struct trailer_header
), ep
);
m_copydata(m
, sizeof(struct ether_header
), datasize
, ep
);
/* restore original ether packet type */
eh
->ether_type
= trailer_header
.ether_type
;
bpf_tap(sc
->we_bpf
, ether_packet
, ep
- ether_packet
);
* Copy the mbuf chain into the transmit buffer
buffer
= sc
->we_vmem_addr
;
for (m0
= m
; m
!= 0; m
= m
->m_next
) {
bcopy(mtod(m
, caddr_t
), buffer
, m
->m_len
);
* Init transmit length registers, and set transmit start flag.
len
= MAX(len
, ETHER_MIN_LEN
);
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
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);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
sc
->arpcom
.ac_if
.if_timer
= 3;
* Ethernet interface interrupt processor
register struct we_softc
*sc
= &we_softc
[unit
];
union we_interrupt weisr
;
/* disable onboard interrupts, then get interrupt status */
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
weisr
.is_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_ISR
);
outb(sc
->we_io_nic_addr
+ WD_P0_ISR
, weisr
.is_byte
);
/* need to read these registers to clear status */
sc
->arpcom
.ac_if
.if_collisions
+=
inb(sc
->we_io_nic_addr
+ WD_P0_TBCR0
);
++sc
->arpcom
.ac_if
.if_oerrors
;
/* 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
->arpcom
.ac_if
.if_ierrors
;
/* normal transmit complete */
if (weisr
.is_ptx
|| weisr
.is_txe
)
/* normal receive notification */
if (weisr
.is_prx
|| weisr
.is_rxe
)
/* try to start transmit */
westart(&sc
->arpcom
.ac_if
);
/* re-enable onboard interrupts */
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
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.
register struct we_softc
*sc
= &we_softc
[unit
];
* Do some statistics (assume page zero of NIC mapped in)
sc
->we_flags
&= ~WDF_TXBUSY
;
sc
->arpcom
.ac_if
.if_timer
= 0;
++sc
->arpcom
.ac_if
.if_opackets
;
sc
->arpcom
.ac_if
.if_collisions
+= inb(sc
->we_io_nic_addr
+ WD_P0_TBCR0
);
* Ethernet interface receiver interrupt.
register struct we_softc
*sc
= &we_softc
[unit
];
* 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
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
bnry
= inb(sc
->we_io_nic_addr
+ WD_P0_BNRY
);
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
curr
= inb(sc
->we_io_nic_addr
+ WD_P1_CURR
);
if(Bdry
[unit
]) /* 19 Sep 92*/
/* get pointer to this buffer header structure */
wer
= (struct we_ring
*)(sc
->we_vmem_addr
+ (bnry
<< 8));
if (len
> 30 && len
<= ETHERMTU
+100)
weread(sc
, (caddr_t
)(wer
+ 1), len
);
else printf("we%d: reject - bad length %d\n", unit
, len
);
wecmd
.cs_byte
= inb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
);
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
) {
outb(sc
->we_io_nic_addr
+ WD_P0_BNRY
,
sc
->we_vmem_size
/ WD_PAGE_SIZE
-1);
if (len
> 30 && len
<= ETHERMTU
+100)
bnry
= wer
->we_next_packet
;
/* 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);
outb(sc
->we_io_nic_addr
+ WD_P0_BNRY
, bnry
-1);
/* refresh our copy of CURR */
outb(sc
->we_io_nic_addr
+ WD_P0_COMMAND
, wecmd
.cs_byte
);
curr
= inb(sc
->we_io_nic_addr
+ WD_P1_CURR
);
Bdry
[unit
] = bnry
; /* 19 Sep 92*/
* Process an ioctl request.
register struct ifnet
*ifp
;
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 (ifa
->ifa_addr
->sa_family
) {
weinit(ifp
->if_unit
); /* before arpwhohas */
((struct arpcom
*)ifp
)->ac_ipaddr
=
arpwhohas((struct arpcom
*)ifp
, &IA_SIN(ifa
)->sin_addr
);
register struct ns_addr
*ina
= &(IA_SNS(ifa
)->sns_addr
);
*(union ns_host
*)(sc
->arpcom
.ac_enaddr
);
* The manual says we cant change the address
* while the receiver is armed,
ifp
->if_flags
&= ~IFF_RUNNING
;
bcopy((caddr_t
)ina
->x_host
.c_host
,
(caddr_t
)sc
->arpcom
.ac_enaddr
,
sizeof(sc
->arpcom
.ac_enaddr
));
weinit(ifp
->if_unit
); /* does ne_setaddr() */
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
ifp
->if_flags
& IFF_RUNNING
) {
ifp
->if_flags
&= ~IFF_RUNNING
;
} else if (ifp
->if_flags
& IFF_UP
&&
(ifp
->if_flags
& IFF_RUNNING
) == 0)
if (sc
->arpcom
.ac_if
.if_flags
& IFF_PROMISC
) {
outb(sc
->we_io_nic_addr
+ WD_P0_RCR
,
WD_R_PRO
| WD_R_SEP
| WD_R_AR
| WD_R_CONFIG
);
outb(sc
->we_io_nic_addr
+ WD_P0_RCR
, WD_R_CONFIG
);
bcopy((caddr_t
)sc
->sc_addr
, (caddr_t
) &ifr
->ifr_data
,
* set ethernet address for unit
wesetaddr(physaddr
, unit
)
register struct we_softc
*sc
= &we_softc
[unit
];
* Rewrite ethernet address, and then force restart of NIC
for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
sc
->arpcom
.ac_enaddr
[i
] = physaddr
[i
];
sc
->we_flags
&= ~WDF_RUNNING
;
#define ringoffset(sc, eh, off, type) \
((type)( ((caddr_t)(eh)+(off) >= (sc)->we_vmem_end) ? \
(((caddr_t)(eh)+(off))) - (sc)->we_vmem_end \
* Pass a packet to the higher levels.
* We deal with the trailer protocol here.
register struct we_softc
*sc
;
struct mbuf
*m
, *head
, *we_ring_to_mbuf();
++sc
->arpcom
.ac_if
.if_ipackets
;
/* Allocate a header mbuf */
MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
m
->m_pkthdr
.rcvif
= &sc
->arpcom
.ac_if
;
eh
= (struct ether_header
*)buf
;
#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
#define EOFF (EROUND - sizeof(struct ether_header))
* The following assumes there is room for
* the ether header in the header mbuf
bcopy(buf
, mtod(head
, caddr_t
), sizeof(struct ether_header
));
buf
+= sizeof(struct ether_header
);
head
->m_len
+= sizeof(struct ether_header
);
len
-= sizeof(struct ether_header
);
etype
= ntohs((u_short
)eh
->ether_type
);
* Deal with trailer protocol:
* If trailer protocol, calculate the datasize as 'off',
* which is also the offset to the trailer header.
* Set resid to the amount of packet data following the
* Finally, copy residual data into mbuf chain.
if (etype
>= ETHERTYPE_TRAIL
&&
etype
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
off
= (etype
- ETHERTYPE_TRAIL
) << 9;
if ((off
+ sizeof(struct trailer_header
)) > len
)
eh
->ether_type
= *ringoffset(sc
, buf
, off
, u_short
*);
resid
= ntohs(*ringoffset(sc
, buf
, off
+2, u_short
*));
if ((off
+ resid
) > len
) goto bad
; /* insanity */
resid
-= sizeof(struct trailer_header
);
if (resid
< 0) goto bad
; /* insanity */
m
= we_ring_to_mbuf(sc
, ringoffset(sc
, buf
, off
+4, char *), head
, resid
);
head
->m_pkthdr
.len
-= 4; /* subtract trailer header */
* Pull packet off interface. Or if this was a trailer packet,
* the data portion is appended.
m
= we_ring_to_mbuf(sc
, buf
, m
, len
);
* Check if there's a bpf filter listening on this interface.
* If so, hand off the raw packet to bpf.
bpf_mtap(sc
->we_bpf
, head
);
* Note that the interface cannot be in promiscuous mode if
* there are no bpf listeners. And if we are in promiscuous
* mode, we have to check if this packet is really ours.
* XXX This test does not support multicasts.
if ((sc
->arpcom
.ac_if
.if_flags
& IFF_PROMISC
) &&
bcmp(eh
->ether_dhost
, sc
->arpcom
.ac_enaddr
,
sizeof(eh
->ether_dhost
)) != 0 &&
bcmp(eh
->ether_dhost
, etherbroadcastaddr
,
sizeof(eh
->ether_dhost
)) != 0) {
* Fix up data start offset in mbuf to point past ether header
m_adj(head
, sizeof(struct ether_header
));
* silly ether_input routine needs 'type' in host byte order
eh
->ether_type
= ntohs(eh
->ether_type
);
ether_input(&sc
->arpcom
.ac_if
, eh
, head
);
* Copy data from receive buffer to end of mbuf chain
* allocate additional mbufs as needed. return pointer
* src = pointer in we ring buffer
* dst = pointer to last mbuf in mbuf chain to copy to
* amount = amount of data to copy
we_ring_to_mbuf(sc
,src
,dst
,total_len
)
register struct mbuf
*m
= dst
;
register int amount
= min(total_len
, M_TRAILINGSPACE(m
));
if (amount
== 0) { /* no more data in this mbuf, alloc another */
* if there is enough data for an mbuf cluster, attempt
* to allocate one of those, otherwise, a regular mbuf
MGET(m
, M_DONTWAIT
, MT_DATA
);
if (total_len
>= MINCLSIZE
)
amount
= min(total_len
, M_TRAILINGSPACE(m
));
src
= we_ring_copy(sc
, src
, mtod(m
, caddr_t
) + m
->m_len
, amount
);
we_ring_copy(sc
,src
,dst
,amount
)
/* does copy wrap to lower addr in ring buffer? */
if (src
+ amount
> sc
->we_vmem_end
) {
tmp_amount
= sc
->we_vmem_end
- src
;
bcopy(src
,dst
,tmp_amount
); /* copy amount up to end */