Changes from DG to deal with some old chips that corrupt the packet length.

This commit is contained in:
mycroft 1994-10-12 13:42:00 +00:00
parent 8f5b447fb2
commit 7c01f7ce51
2 changed files with 100 additions and 68 deletions

View File

@ -14,7 +14,7 @@
* Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of * Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of
* similar clones. * similar clones.
* *
* $Id: if_ed.c,v 1.51 1994/10/01 07:19:32 mycroft Exp $ * $Id: if_ed.c,v 1.52 1994/10/12 13:42:00 mycroft Exp $
*/ */
#include "bpfilter.h" #include "bpfilter.h"
@ -1273,7 +1273,7 @@ ed_init(sc)
* Set promiscuous mode. Multicast filter was set earlier so * Set promiscuous mode. Multicast filter was set earlier so
* that we should receive all multicast packets. * that we should receive all multicast packets.
*/ */
i |= ED_RCR_PRO; i |= ED_RCR_PRO | ED_RCR_AR | ED_RCR_SEP;
} }
outb(sc->nic_addr + ED_P0_RCR, i); outb(sc->nic_addr + ED_P0_RCR, i);
@ -1423,10 +1423,7 @@ outloop:
break; break;
/* /*
* Enable 16bit access to shared memory on WD/SMC * Enable 16bit access to shared memory on WD/SMC
* boards don't update wd_laar_proto because we want to * boards.
* restore the previous state (because an arp reply in
* the input code may cause a call-back to ed_start).
* XXX - the call-back to 'start' is a bug, IMHO.
*/ */
case ED_VENDOR_WD_SMC: case ED_VENDOR_WD_SMC:
if (sc->isa16bit) if (sc->isa16bit)
@ -1476,7 +1473,7 @@ outloop:
ed_xmit(sc); ed_xmit(sc);
#if NBPFILTER > 0 #if NBPFILTER > 0
/* If there is BPF support in the configuration, tap off here. */ /* Tap off here if there is a BPF listener. */
if (sc->sc_arpcom.ac_if.if_bpf) if (sc->sc_arpcom.ac_if.if_bpf)
bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0); bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0);
#endif #endif
@ -1525,18 +1522,42 @@ ed_rint(sc)
ed_pio_readmem(sc, (u_short)packet_ptr, ed_pio_readmem(sc, (u_short)packet_ptr,
(caddr_t) &packet_hdr, sizeof(packet_hdr)); (caddr_t) &packet_hdr, sizeof(packet_hdr));
len = packet_hdr.count; len = packet_hdr.count;
if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) { if (len > ETHER_MAX_LEN) {
/*
* Length is a wild value. There's a good chance that
* this was caused by the NIC being old and buggy.
* The bug is that the length low byte is duplicated in
* the high byte. Try to recalculate the length based
* on the pointer to the next packet.
*
* NOTE: sc->next_packet is pointing at the current
* packet.
*/
len &= ED_PAGE_SIZE - 1;
if (packet_hdr.next_packet >= sc->next_packet) {
len += (packet_hdr.next_packet - sc->next_packet) * ED_PAGE_SIZE;
} else {
len += ((packet_hdr.next_packet - sc->rec_page_start) +
(sc->rec_page_stop - sc->next_packet)) * ED_PAGE_SIZE;
}
}
/*
* Be fairly liberal about what we allow as a "reasonable"
* length so that a [crufty] packet will make it to BPF (and
* can thus be analyzed). Note that all that is really
* important is that we have a length that will fit into one
* mbuf cluster or less; the upper layer protocols can then
* figure out the length from their own length field(s).
*/
if (len <= MCLBYTES &&
packet_hdr.next_packet >= sc->rec_page_start &&
packet_hdr.next_packet < sc->rec_page_stop) {
/* Go get packet. */ /* Go get packet. */
ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring), ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring),
len - sizeof(struct ed_ring)); len - sizeof(struct ed_ring));
++sc->sc_arpcom.ac_if.if_ipackets; ++sc->sc_arpcom.ac_if.if_ipackets;
} else { } else {
/* /* Really BAD. The ring pointers are corrupted. */
* Really BAD...probably indicates that the ring
* pointers are corrupted. Also seen on early rev
* chips under high load - the byte order of the length
* gets switched.
*/
log(LOG_ERR, log(LOG_ERR,
"%s: NIC memory corrupt - invalid packet length %d\n", "%s: NIC memory corrupt - invalid packet length %d\n",
sc->sc_dev.dv_xname, len); sc->sc_dev.dv_xname, len);
@ -1892,16 +1913,15 @@ ed_get_packet(sc, buf, len)
u_short len; u_short len;
{ {
struct ether_header *eh; struct ether_header *eh;
struct mbuf *m, *head = 0, *ed_ring_to_mbuf(); struct mbuf *m, *ed_ring_to_mbuf();
/* Allocate a header mbuf. */ /* Allocate a header mbuf. */
MGETHDR(m, M_DONTWAIT, MT_DATA); MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0) if (m == 0)
goto bad; return;
m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if; m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
m->m_pkthdr.len = len; m->m_pkthdr.len = len;
m->m_len = 0; m->m_len = 0;
head = m;
/* The following silliness is to make NFS happy. */ /* The following silliness is to make NFS happy. */
#define EROUND ((sizeof(struct ether_header) + 3) & ~3) #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
@ -1911,22 +1931,23 @@ ed_get_packet(sc, buf, len)
* The following assumes there is room for the ether header in the * The following assumes there is room for the ether header in the
* header mbuf. * header mbuf.
*/ */
head->m_data += EOFF; m->m_data += EOFF;
eh = mtod(head, struct ether_header *); eh = mtod(m, struct ether_header *);
if (sc->mem_shared) if (sc->mem_shared)
bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header)); bcopy(buf, mtod(m, caddr_t), sizeof(struct ether_header));
else else
ed_pio_readmem(sc, (u_short)buf, mtod(head, caddr_t), ed_pio_readmem(sc, (u_short)buf, mtod(m, caddr_t),
sizeof(struct ether_header)); sizeof(struct ether_header));
buf += sizeof(struct ether_header); buf += sizeof(struct ether_header);
head->m_len += sizeof(struct ether_header); m->m_len += sizeof(struct ether_header);
len -= sizeof(struct ether_header); len -= sizeof(struct ether_header);
/* Pull packet off interface. */ /* Pull packet off interface. */
m = ed_ring_to_mbuf(sc, buf, m, len); if (ed_ring_to_mbuf(sc, buf, m, len) == 0) {
if (m == 0) m_freem(m);
goto bad; return;
}
#if NBPFILTER > 0 #if NBPFILTER > 0
/* /*
@ -1934,7 +1955,7 @@ ed_get_packet(sc, buf, len)
* the raw packet to bpf. * the raw packet to bpf.
*/ */
if (sc->sc_arpcom.ac_if.if_bpf) { if (sc->sc_arpcom.ac_if.if_bpf) {
bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, head); bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m);
/* /*
* Note that the interface cannot be in promiscuous mode if * Note that the interface cannot be in promiscuous mode if
@ -1945,20 +1966,15 @@ ed_get_packet(sc, buf, len)
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
sizeof(eh->ether_dhost)) != 0) { sizeof(eh->ether_dhost)) != 0) {
m_freem(head); m_freem(m);
return; return;
} }
} }
#endif #endif
/* Fix up data start offset in mbuf to point past ether header. */ /* Fix up data start offset in mbuf to point past ether header. */
m_adj(head, sizeof(struct ether_header)); m_adj(m, sizeof(struct ether_header));
ether_input(&sc->sc_arpcom.ac_if, eh, head); ether_input(&sc->sc_arpcom.ac_if, eh, m);
return;
bad: if (head)
m_freem(head);
return;
} }
/* /*

View File

@ -14,7 +14,7 @@
* Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of * Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of
* similar clones. * similar clones.
* *
* $Id: if_ed.c,v 1.51 1994/10/01 07:19:32 mycroft Exp $ * $Id: if_ed.c,v 1.52 1994/10/12 13:42:00 mycroft Exp $
*/ */
#include "bpfilter.h" #include "bpfilter.h"
@ -1273,7 +1273,7 @@ ed_init(sc)
* Set promiscuous mode. Multicast filter was set earlier so * Set promiscuous mode. Multicast filter was set earlier so
* that we should receive all multicast packets. * that we should receive all multicast packets.
*/ */
i |= ED_RCR_PRO; i |= ED_RCR_PRO | ED_RCR_AR | ED_RCR_SEP;
} }
outb(sc->nic_addr + ED_P0_RCR, i); outb(sc->nic_addr + ED_P0_RCR, i);
@ -1423,10 +1423,7 @@ outloop:
break; break;
/* /*
* Enable 16bit access to shared memory on WD/SMC * Enable 16bit access to shared memory on WD/SMC
* boards don't update wd_laar_proto because we want to * boards.
* restore the previous state (because an arp reply in
* the input code may cause a call-back to ed_start).
* XXX - the call-back to 'start' is a bug, IMHO.
*/ */
case ED_VENDOR_WD_SMC: case ED_VENDOR_WD_SMC:
if (sc->isa16bit) if (sc->isa16bit)
@ -1476,7 +1473,7 @@ outloop:
ed_xmit(sc); ed_xmit(sc);
#if NBPFILTER > 0 #if NBPFILTER > 0
/* If there is BPF support in the configuration, tap off here. */ /* Tap off here if there is a BPF listener. */
if (sc->sc_arpcom.ac_if.if_bpf) if (sc->sc_arpcom.ac_if.if_bpf)
bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0); bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0);
#endif #endif
@ -1525,18 +1522,42 @@ ed_rint(sc)
ed_pio_readmem(sc, (u_short)packet_ptr, ed_pio_readmem(sc, (u_short)packet_ptr,
(caddr_t) &packet_hdr, sizeof(packet_hdr)); (caddr_t) &packet_hdr, sizeof(packet_hdr));
len = packet_hdr.count; len = packet_hdr.count;
if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) { if (len > ETHER_MAX_LEN) {
/*
* Length is a wild value. There's a good chance that
* this was caused by the NIC being old and buggy.
* The bug is that the length low byte is duplicated in
* the high byte. Try to recalculate the length based
* on the pointer to the next packet.
*
* NOTE: sc->next_packet is pointing at the current
* packet.
*/
len &= ED_PAGE_SIZE - 1;
if (packet_hdr.next_packet >= sc->next_packet) {
len += (packet_hdr.next_packet - sc->next_packet) * ED_PAGE_SIZE;
} else {
len += ((packet_hdr.next_packet - sc->rec_page_start) +
(sc->rec_page_stop - sc->next_packet)) * ED_PAGE_SIZE;
}
}
/*
* Be fairly liberal about what we allow as a "reasonable"
* length so that a [crufty] packet will make it to BPF (and
* can thus be analyzed). Note that all that is really
* important is that we have a length that will fit into one
* mbuf cluster or less; the upper layer protocols can then
* figure out the length from their own length field(s).
*/
if (len <= MCLBYTES &&
packet_hdr.next_packet >= sc->rec_page_start &&
packet_hdr.next_packet < sc->rec_page_stop) {
/* Go get packet. */ /* Go get packet. */
ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring), ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring),
len - sizeof(struct ed_ring)); len - sizeof(struct ed_ring));
++sc->sc_arpcom.ac_if.if_ipackets; ++sc->sc_arpcom.ac_if.if_ipackets;
} else { } else {
/* /* Really BAD. The ring pointers are corrupted. */
* Really BAD...probably indicates that the ring
* pointers are corrupted. Also seen on early rev
* chips under high load - the byte order of the length
* gets switched.
*/
log(LOG_ERR, log(LOG_ERR,
"%s: NIC memory corrupt - invalid packet length %d\n", "%s: NIC memory corrupt - invalid packet length %d\n",
sc->sc_dev.dv_xname, len); sc->sc_dev.dv_xname, len);
@ -1892,16 +1913,15 @@ ed_get_packet(sc, buf, len)
u_short len; u_short len;
{ {
struct ether_header *eh; struct ether_header *eh;
struct mbuf *m, *head = 0, *ed_ring_to_mbuf(); struct mbuf *m, *ed_ring_to_mbuf();
/* Allocate a header mbuf. */ /* Allocate a header mbuf. */
MGETHDR(m, M_DONTWAIT, MT_DATA); MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0) if (m == 0)
goto bad; return;
m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if; m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
m->m_pkthdr.len = len; m->m_pkthdr.len = len;
m->m_len = 0; m->m_len = 0;
head = m;
/* The following silliness is to make NFS happy. */ /* The following silliness is to make NFS happy. */
#define EROUND ((sizeof(struct ether_header) + 3) & ~3) #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
@ -1911,22 +1931,23 @@ ed_get_packet(sc, buf, len)
* The following assumes there is room for the ether header in the * The following assumes there is room for the ether header in the
* header mbuf. * header mbuf.
*/ */
head->m_data += EOFF; m->m_data += EOFF;
eh = mtod(head, struct ether_header *); eh = mtod(m, struct ether_header *);
if (sc->mem_shared) if (sc->mem_shared)
bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header)); bcopy(buf, mtod(m, caddr_t), sizeof(struct ether_header));
else else
ed_pio_readmem(sc, (u_short)buf, mtod(head, caddr_t), ed_pio_readmem(sc, (u_short)buf, mtod(m, caddr_t),
sizeof(struct ether_header)); sizeof(struct ether_header));
buf += sizeof(struct ether_header); buf += sizeof(struct ether_header);
head->m_len += sizeof(struct ether_header); m->m_len += sizeof(struct ether_header);
len -= sizeof(struct ether_header); len -= sizeof(struct ether_header);
/* Pull packet off interface. */ /* Pull packet off interface. */
m = ed_ring_to_mbuf(sc, buf, m, len); if (ed_ring_to_mbuf(sc, buf, m, len) == 0) {
if (m == 0) m_freem(m);
goto bad; return;
}
#if NBPFILTER > 0 #if NBPFILTER > 0
/* /*
@ -1934,7 +1955,7 @@ ed_get_packet(sc, buf, len)
* the raw packet to bpf. * the raw packet to bpf.
*/ */
if (sc->sc_arpcom.ac_if.if_bpf) { if (sc->sc_arpcom.ac_if.if_bpf) {
bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, head); bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m);
/* /*
* Note that the interface cannot be in promiscuous mode if * Note that the interface cannot be in promiscuous mode if
@ -1945,20 +1966,15 @@ ed_get_packet(sc, buf, len)
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
sizeof(eh->ether_dhost)) != 0) { sizeof(eh->ether_dhost)) != 0) {
m_freem(head); m_freem(m);
return; return;
} }
} }
#endif #endif
/* Fix up data start offset in mbuf to point past ether header. */ /* Fix up data start offset in mbuf to point past ether header. */
m_adj(head, sizeof(struct ether_header)); m_adj(m, sizeof(struct ether_header));
ether_input(&sc->sc_arpcom.ac_if, eh, head); ether_input(&sc->sc_arpcom.ac_if, eh, m);
return;
bad: if (head)
m_freem(head);
return;
} }
/* /*