From 7c01f7ce51c19b3df01263c228312b9bc58219eb Mon Sep 17 00:00:00 2001 From: mycroft Date: Wed, 12 Oct 1994 13:42:00 +0000 Subject: [PATCH] Changes from DG to deal with some old chips that corrupt the packet length. --- sys/arch/i386/isa/if_ed.c | 84 +++++++++++++++++++++++---------------- sys/dev/isa/if_ed.c | 84 +++++++++++++++++++++++---------------- 2 files changed, 100 insertions(+), 68 deletions(-) diff --git a/sys/arch/i386/isa/if_ed.c b/sys/arch/i386/isa/if_ed.c index 7d08d7b16c5b..62a0d8cbe7d0 100644 --- a/sys/arch/i386/isa/if_ed.c +++ b/sys/arch/i386/isa/if_ed.c @@ -14,7 +14,7 @@ * Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of * 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" @@ -1273,7 +1273,7 @@ ed_init(sc) * Set promiscuous mode. Multicast filter was set earlier so * 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); @@ -1423,10 +1423,7 @@ outloop: break; /* * Enable 16bit access to shared memory on WD/SMC - * boards don't update wd_laar_proto because we want to - * 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. + * boards. */ case ED_VENDOR_WD_SMC: if (sc->isa16bit) @@ -1476,7 +1473,7 @@ outloop: ed_xmit(sc); #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) bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0); #endif @@ -1525,18 +1522,42 @@ ed_rint(sc) ed_pio_readmem(sc, (u_short)packet_ptr, (caddr_t) &packet_hdr, sizeof(packet_hdr)); 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. */ ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring), len - sizeof(struct ed_ring)); ++sc->sc_arpcom.ac_if.if_ipackets; } else { - /* - * 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. - */ + /* Really BAD. The ring pointers are corrupted. */ log(LOG_ERR, "%s: NIC memory corrupt - invalid packet length %d\n", sc->sc_dev.dv_xname, len); @@ -1892,16 +1913,15 @@ ed_get_packet(sc, buf, len) u_short len; { struct ether_header *eh; - struct mbuf *m, *head = 0, *ed_ring_to_mbuf(); + struct mbuf *m, *ed_ring_to_mbuf(); /* Allocate a header mbuf. */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) - goto bad; + return; m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if; m->m_pkthdr.len = len; m->m_len = 0; - head = m; /* The following silliness is to make NFS happy. */ #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 * header mbuf. */ - head->m_data += EOFF; - eh = mtod(head, struct ether_header *); + m->m_data += EOFF; + eh = mtod(m, struct ether_header *); 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 - 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)); buf += sizeof(struct ether_header); - head->m_len += sizeof(struct ether_header); + m->m_len += sizeof(struct ether_header); len -= sizeof(struct ether_header); /* Pull packet off interface. */ - m = ed_ring_to_mbuf(sc, buf, m, len); - if (m == 0) - goto bad; + if (ed_ring_to_mbuf(sc, buf, m, len) == 0) { + m_freem(m); + return; + } #if NBPFILTER > 0 /* @@ -1934,7 +1955,7 @@ ed_get_packet(sc, buf, len) * the raw packet to 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 @@ -1945,20 +1966,15 @@ ed_get_packet(sc, buf, len) (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0) { - m_freem(head); + m_freem(m); return; } } #endif /* Fix up data start offset in mbuf to point past ether header. */ - m_adj(head, sizeof(struct ether_header)); - ether_input(&sc->sc_arpcom.ac_if, eh, head); - return; - -bad: if (head) - m_freem(head); - return; + m_adj(m, sizeof(struct ether_header)); + ether_input(&sc->sc_arpcom.ac_if, eh, m); } /* diff --git a/sys/dev/isa/if_ed.c b/sys/dev/isa/if_ed.c index 7d08d7b16c5b..62a0d8cbe7d0 100644 --- a/sys/dev/isa/if_ed.c +++ b/sys/dev/isa/if_ed.c @@ -14,7 +14,7 @@ * Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, and a variety of * 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" @@ -1273,7 +1273,7 @@ ed_init(sc) * Set promiscuous mode. Multicast filter was set earlier so * 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); @@ -1423,10 +1423,7 @@ outloop: break; /* * Enable 16bit access to shared memory on WD/SMC - * boards don't update wd_laar_proto because we want to - * 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. + * boards. */ case ED_VENDOR_WD_SMC: if (sc->isa16bit) @@ -1476,7 +1473,7 @@ outloop: ed_xmit(sc); #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) bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0); #endif @@ -1525,18 +1522,42 @@ ed_rint(sc) ed_pio_readmem(sc, (u_short)packet_ptr, (caddr_t) &packet_hdr, sizeof(packet_hdr)); 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. */ ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring), len - sizeof(struct ed_ring)); ++sc->sc_arpcom.ac_if.if_ipackets; } else { - /* - * 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. - */ + /* Really BAD. The ring pointers are corrupted. */ log(LOG_ERR, "%s: NIC memory corrupt - invalid packet length %d\n", sc->sc_dev.dv_xname, len); @@ -1892,16 +1913,15 @@ ed_get_packet(sc, buf, len) u_short len; { struct ether_header *eh; - struct mbuf *m, *head = 0, *ed_ring_to_mbuf(); + struct mbuf *m, *ed_ring_to_mbuf(); /* Allocate a header mbuf. */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) - goto bad; + return; m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if; m->m_pkthdr.len = len; m->m_len = 0; - head = m; /* The following silliness is to make NFS happy. */ #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 * header mbuf. */ - head->m_data += EOFF; - eh = mtod(head, struct ether_header *); + m->m_data += EOFF; + eh = mtod(m, struct ether_header *); 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 - 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)); buf += sizeof(struct ether_header); - head->m_len += sizeof(struct ether_header); + m->m_len += sizeof(struct ether_header); len -= sizeof(struct ether_header); /* Pull packet off interface. */ - m = ed_ring_to_mbuf(sc, buf, m, len); - if (m == 0) - goto bad; + if (ed_ring_to_mbuf(sc, buf, m, len) == 0) { + m_freem(m); + return; + } #if NBPFILTER > 0 /* @@ -1934,7 +1955,7 @@ ed_get_packet(sc, buf, len) * the raw packet to 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 @@ -1945,20 +1966,15 @@ ed_get_packet(sc, buf, len) (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0) { - m_freem(head); + m_freem(m); return; } } #endif /* Fix up data start offset in mbuf to point past ether header. */ - m_adj(head, sizeof(struct ether_header)); - ether_input(&sc->sc_arpcom.ac_if, eh, head); - return; - -bad: if (head) - m_freem(head); - return; + m_adj(m, sizeof(struct ether_header)); + ether_input(&sc->sc_arpcom.ac_if, eh, m); } /*