--- Net2/arch/i386/isa/if_ne.c 2018/04/24 18:11:54 1.1.1.3 +++ Net2/arch/i386/isa/if_ne.c 2018/04/24 18:19:53 1.1.1.4 @@ -31,14 +31,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)if_ne.c 7.4 (Berkeley) 5/21/91 + * from: @(#)if_ne.c 7.4 (Berkeley) 5/21/91 + * if_ne.c,v 1.9 1993/07/17 16:41:27 mycroft Exp */ /* - * NE2000 Ethernet driver + * NE2000/NE1000 Ethernet driver * * Parts inspired from Tim Tucker's if_wd driver for the wd8003, * insight on the ne2000 gained from Robert Clements PC/FTP driver. + * + * Corrected for NE1000 by Andrew A. Chernov */ #include "ne.h" @@ -71,6 +74,13 @@ #include "netns/ns_if.h" #endif +#include "bpfilter.h" +#if NBPFILTER > 0 +#include "sys/select.h" +#include "net/bpf.h" +#include "net/bpfdesc.h" +#endif + #include "i386/isa/isa_device.h" #include "i386/isa/if_nereg.h" #include "i386/isa/icu.h" @@ -108,10 +118,10 @@ struct ne_softc { struct ether_header ns_eh; /* header of incoming packet */ u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/]; short ns_txstart; /* transmitter buffer start */ - short ns_rxend; /* recevier buffer end */ - short ns_rxbndry; /* recevier buffer boundary */ + u_short ns_rxend; /* recevier buffer end */ short ns_port; /* i/o port base */ short ns_mode; /* word/byte mode */ + caddr_t ns_bpf; /* BPF frob */ } ne_softc[NNE] ; #define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN) @@ -229,7 +239,7 @@ word: for(i=0; i < 6; i++) ns->ns_addrp[i] = boarddata[i]; splx(s); - return (1); + return (16); } /* @@ -333,7 +343,9 @@ neattach(dvp) ifp->if_unit = unit; ifp->if_name = nedriver.name ; ifp->if_mtu = ETHERMTU; - printf (" ethernet address %s", ether_sprintf(ns->ns_addrp)) ; + printf ("ne%d: ne%s ethernet address %s\n", unit, + (ns->ns_mode & DSDC_WTS) ? "2000" : "1000", + ether_sprintf(ns->ns_addrp)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; ifp->if_init = neinit; ifp->if_output = ether_output; @@ -342,6 +354,11 @@ neattach(dvp) ifp->if_reset = nereset; ifp->if_watchdog = 0; if_attach(ifp); + +#if NBPFILTER > 0 + bpfattach(&ns->ns_bpf, ifp, DLT_EN10MB, + sizeof(struct ether_header)); +#endif } /* @@ -389,7 +406,12 @@ neinit(unit) outb(nec+ds1_curr, (ns->ns_txstart+PKTSZ)/DS_PGSIZE); ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE; outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); - outb (nec+ds0_rcr, DSRC_AB); +#if NBPFILTER > 0 + if (ns->ns_if.if_flags & IFF_PROMISC) + outb (nec+ds0_rcr, DSRC_AB | DSRC_PRO | DSRC_AR | DSRC_SEP); + else +#endif + outb (nec+ds0_rcr, DSRC_AB); outb(nec+ds0_dcr, ns->ns_mode); outb (nec+ds0_imr, 0xff); @@ -405,15 +427,24 @@ neinit(unit) * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. * called only at splimp or interrupt level. + * XXX: Needs BPF hook. */ nestart(ifp) struct ifnet *ifp; { register struct ne_softc *ns = &ne_softc[ifp->if_unit]; struct mbuf *m0, *m; - int buffer; - int len = 0, i, total,t; + int len, i, total,t; register nec = ns->ns_port; + u_char cmd; + u_short word; + int counter; + + if (ns->ns_flags & DSF_LOCK) + return; + + if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) + return; /* * The DS8390 has only one transmit buffer, if it is busy we @@ -421,50 +452,79 @@ nestart(ifp) */ outb(nec+ds_cmd,DSCM_NODMA|DSCM_START); - if (ns->ns_flags & DSF_LOCK) - return; - if (inb(nec+ds_cmd) & DSCM_TRANS) return; - if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) - return; - IF_DEQUEUE(&ns->ns_if.if_snd, m); if (m == 0) return; + ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */ + /* * Copy the mbuf chain into the transmit buffer */ - ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */ - buffer = ns->ns_txstart; len = i = 0; + len = i = 0; t = 0; for (m0 = m; m != 0; m = m->m_next) t += m->m_len; - m = m0; - total = t; - for (m0 = m; m != 0; ) { + /* next code derived from neput() */ - if (m->m_len&1 && t > m->m_len) { - neput(ns, mtod(m, caddr_t), buffer, m->m_len - 1); - t -= m->m_len - 1; - buffer += m->m_len - 1; - m->m_data += m->m_len - 1; - m->m_len = 1; - m = m_pullup(m, 2); - } else { - neput(ns, mtod(m, caddr_t), buffer, m->m_len); - buffer += m->m_len; - t -= m->m_len; - MFREE(m, m0); + if ((ns->ns_mode & DSDC_WTS) && t&1) + t++; /* roundup to words */ + + cmd = inb(nec+ds_cmd); + outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); + + /* Setup for remote dma */ + outb (nec+ds0_isr, DSIS_RDC); + + outb (nec+ds0_rbcr0, t); + outb (nec+ds0_rbcr1, t>>8); + outb (nec+ds0_rsar0, ns->ns_txstart); + outb (nec+ds0_rsar1, ns->ns_txstart>>8); + + /* Execute & stuff to card */ + outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START); + m = m0; + total = t; + if (ns->ns_mode & DSDC_WTS) { /* Word Mode */ + while (m != 0) { + if (m->m_len > 1) + outsw(nec+ne_data, m->m_data, m->m_len / 2); + if (m->m_len & 1) { + word = (u_char) *(mtod(m, caddr_t) + m->m_len - 1); + if ((m = m->m_next) != 0) { + word |= *mtod(m, caddr_t) << 8; + m->m_len--; + m->m_data++; + } + outsw(nec+ne_data, (caddr_t)&word, 1); + } else + m = m->m_next; + } + } + else { /* Byte Mode */ + while (m != 0) { + if (m->m_len > 0) + outsb(nec+ne_data, mtod(m, caddr_t), m->m_len); + m = m->m_next; } } + m_freem(m0); + + counter = 100000; + /* Wait till done, then shutdown feature */ + while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0) + ; + outb (nec+ds0_isr, DSIS_RDC); + outb (nec+ds_cmd, cmd); + /* * Init transmit length registers, and set transmit start flag. */ @@ -629,20 +689,22 @@ nerecv(ns) int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ; u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph)); - if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46; + if (++ns->ns_cur >= ns->ns_rxend/DS_PGSIZE) + ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE; b = ns->ns_cur*DS_PGSIZE; while (l >= DS_PGSIZE) { nefetch(ns, p, b, DS_PGSIZE); p += DS_PGSIZE; l -= DS_PGSIZE; - if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46; + if (++ns->ns_cur >= ns->ns_rxend/DS_PGSIZE) + ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE; b = ns->ns_cur*DS_PGSIZE; } if (l > 0) nefetch(ns, p, b, l); } /* don't forget checksum! */ - len -= sizeof(struct ether_header) + sizeof(long); + len -= sizeof(long) + sizeof(struct ether_header); neread(ns,(caddr_t)(ns->ns_pb), len); } @@ -660,6 +722,7 @@ neread(ns, buf, len) struct mbuf *m; int off, resid; register struct ifqueue *inq; + u_short etype; /* * Deal with trailer protocol: if type is trailer type @@ -667,19 +730,19 @@ neread(ns, buf, len) * Remember that type was trailer by setting off. */ eh = (struct ether_header *)buf; - eh->ether_type = ntohs((u_short)eh->ether_type); + etype = ntohs((u_short)eh->ether_type); #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) - if (eh->ether_type >= ETHERTYPE_TRAIL && - eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { - off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; + if (etype >= ETHERTYPE_TRAIL && + etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { + off = (etype - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ - eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); - resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); + eh->ether_type = *nedataaddr(eh, off, u_short *); + resid = ntohs(*nedataaddr(eh, off+2, u_short *)); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; - if (len == 0) return; + if (len <= 0) return; /* * Pull packet off interface. Off is nonzero if packet @@ -690,6 +753,41 @@ neread(ns, buf, len) m = neget(buf, len, off, &ns->ns_if); if (m == 0) return; +#if NBPFILTER > 0 + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to bpf. + */ + if (ns->ns_bpf) { + bpf_mtap(ns->ns_bpf, m); + } + + /* + * 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 ((ns->ns_if.if_flags & IFF_PROMISC) && + bcmp(eh->ether_dhost, ns->ns_addrp, + sizeof(eh->ether_dhost)) != 0 && + bcmp(eh->ether_dhost, etherbroadcastaddr, + sizeof(eh->ether_dhost)) != 0) { + + m_freem(m); + return; + } +#endif + + /* + * Drop packet header and save fixed up ether_type. + */ +#if NBPFILTER > 0 + m_adj(m, sizeof(struct ether_header)); +#endif + eh->ether_type = ntohs(eh->ether_type); + ether_input(&ns->ns_if, eh, m); } @@ -707,70 +805,81 @@ neread(ns, buf, len) * we copy into clusters. */ struct mbuf * -neget(buf, totlen, off0, ifp) +neget(buf, totlen, off, ifp) caddr_t buf; - int totlen, off0; + int totlen, off; struct ifnet *ifp; { - struct mbuf *top, **mp, *m, *p; - int off = off0, len; - register caddr_t cp = buf; - char *epkt; + struct mbuf *top, *last, *m; + int len; + register caddr_t cp; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + top = last = m; + +#if NBPFILTER > 0 + /* + * Copy the ethernet header first. + * XXX: This assumes that ether_header fits inside the mbuf. + */ + /* + * XXX: This line is to avoid `nfs_rcv odd length!' spewage. + */ + m->m_data += (MHLEN - sizeof(struct ether_header)) & 3; + bcopy(buf, mtod(m, caddr_t), sizeof(struct ether_header)); + m->m_len = sizeof(struct ether_header); + m->m_pkthdr.len = totlen + sizeof(struct ether_header); +#else + m->m_len = 0; + m->m_pkthdr.len = totlen; +#endif + m->m_pkthdr.rcvif = ifp; buf += sizeof(struct ether_header); cp = buf; - epkt = cp + totlen; - if (off) { cp += off + 2 * sizeof(u_short); - totlen -= 2 * sizeof(u_short); + totlen -= off + 2 * sizeof(u_short); } - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - return (0); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - m->m_len = MHLEN; - - top = 0; - mp = ⊤ + copy: while (totlen > 0) { - if (top) { + len = min(totlen, M_TRAILINGSPACE(m)); + if (!len) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return (0); } - m->m_len = MLEN; - } - len = min(totlen, epkt - cp); - if (len >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) - m->m_len = len = min(len, MCLBYTES); - else - len = m->m_len; - } else { - /* - * Place initial small packet/header at end of mbuf. - */ - if (len < m->m_len) { - if (top == 0 && len + max_linkhdr <= m->m_len) - m->m_data += max_linkhdr; - m->m_len = len; - } else - len = m->m_len; + if (totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m == 0) { + m_freem(top); + return (0); + } + } + m->m_len = 0; + last->m_next = m; + last = m; + len = min(totlen, M_TRAILINGSPACE(m)); } - bcopy(cp, mtod(m, caddr_t), (unsigned)len); - cp += len; - *mp = m; - mp = &m->m_next; + + bcopy(cp, mtod(m, caddr_t) + m->m_len, len); + m->m_len += len; totlen -= len; - if (cp == epkt) - cp = buf; + cp += len; + } + + if (off) { + totlen = off; + cp = buf; + off = 0; + goto copy; } + return (top); } @@ -835,8 +944,17 @@ neioctl(ifp, cmd, data) ifp->if_flags &= ~IFF_RUNNING; outb(ns->ns_port + ds_cmd, DSCM_STOP|DSCM_NODMA); } else if (ifp->if_flags & IFF_UP && - (ifp->if_flags & IFF_RUNNING) == 0) + (ifp->if_flags & IFF_RUNNING) == 0) { neinit(ifp->if_unit); + break; + } +#if NBPFILTER > 0 + if (ns->ns_if.if_flags & IFF_PROMISC) + outb (ns->ns_port+ds0_rcr, DSRC_AB | DSRC_PRO | + DSRC_AR | DSRC_SEP); + else +#endif + outb (ns->ns_port+ds0_rcr, DSRC_AB); break; #ifdef notdef