Return to BSD News archive
Newsgroups: comp.os.386bsd.bugs Path: sserve!newshost.anu.edu.au!munnari.oz.au!hp9000.csc.cuhk.hk!saimiri.primate.wisc.edu!zaphod.mps.ohio-state.edu!cs.utexas.edu!uunet!email!mbirgmei From: mbirgmei@email.tuwien.ac.at (Martin BIRGMEIER) Subject: Patches for if_ec.* to work with BPF Message-ID: <1993Apr26.071622.3817@email.tuwien.ac.at> Organization: Technical University of Vienna Date: Mon, 26 Apr 1993 07:16:22 GMT Lines: 907 Below are the patches I hacked up to get my 3c503 card to work with the Berkeley Packet Filter. I have been using them for a while now (since well before pk 0.2 came along) and they seem to be running fine. To arrive at them, I simply diffed the old and new versions of if_we*, and manually applied the resulting changes to if_ec.* (these interfaces are the same for all practical purposes, the chip being the same as I understood from the comments in if_ec.c). So basically if_ec.* should now offer all of the functionality of if_we* (I hope :-)). Enjoy, Martin P.S. One more thing - cut out that silly printf() statement in if_ec.c - this should have made it into the patchkit a long time ago. I let it follow as my first diff, thereafter the BPF diff stuff. ============================== cut here ============================== *** /usr/src/sys.386bsd/i386/isa/if_ec.c.ECINIT_ORIG Sun May 31 00:09:06 1992 --- /usr/src/sys.386bsd/i386/isa/if_ec.c Tue Jan 26 10:15:44 1993 *************** *** 261,267 **** u_short ax, cx; Bdry=0; - printf("ecinit"); /* * Address not known. */ --- 261,266 ---- ============================== cut here ============================== *** /usr/src/sys.386bsd/i386/isa/if_ec.h.BPF_ORIG Mon May 25 12:18:40 1992 --- /usr/src/sys.386bsd/i386/isa/if_ec.h Wed Mar 24 10:12:58 1993 *************** *** 169,177 **** */ #define ENRXCR_MON 0x20 /* Monitor mode (no packets rcvd) */ #define ENRXCR_PROMP 0x10 /* Promiscuous phys addresses. */ ! #define ENRXCR_MULTI 0x8 /* Multicast (if pass filter) */ ! #define ENRXCR_BCST 0x4 /* Accept broadcasts */ ! #define ENRXCR_BAD 0x3 /* Accept runts and bad CRC frames */ /* * Commands for TX control reg */ --- 169,179 ---- */ #define ENRXCR_MON 0x20 /* Monitor mode (no packets rcvd) */ #define ENRXCR_PROMP 0x10 /* Promiscuous phys addresses. */ ! #define ENRXCR_MULTI 0x08 /* Multicast (if pass filter) */ ! #define ENRXCR_BCST 0x04 /* Accept broadcasts */ ! #define ENRXCR_RUNT 0x02 /* Accept runts */ ! #define ENRXCR_CRC 0x01 /* Accept bad CRC frames */ ! #define ENRXCR_BAD (ENRXCR_RUNT | ENRXCR_CRC) /* * Commands for TX control reg */ *** /usr/src/sys.386bsd/i386/isa/if_ec.c.BPF_ORIG Mon Mar 22 15:08:26 1993 --- /usr/src/sys.386bsd/i386/isa/if_ec.c Wed Mar 24 10:12:57 1993 *************** *** 64,69 **** --- 64,73 ---- * repairs this bit after obtaining it's information since I didn't know * what else within the depths of the kernel would freak out if I left it. */ + /* + * BPF filter support added by MB 03/16/93, modeled after the changes + * made to if_we.c by Marc Frajola and David Greenman + */ #include "param.h" #include "mbuf.h" #include "socket.h" *************** *** 71,76 **** --- 75,82 ---- #include "errno.h" #include "syslog.h" #include "net/if.h" + #include "net/if_types.h" + #include "net/if_dl.h" #include "net/netisr.h" #ifdef INET #include "netinet/in.h" *************** *** 85,90 **** --- 91,103 ---- #endif #include "i386/isa/isa_device.h" #include "i386/isa/if_ec.h" + #include "bpfilter.h" + #if NBPFILTER > 0 + #include "net/bpf.h" + #include "net/bpfdesc.h" + #endif /* NBPFILTER > 0 */ + + static inline caddr_t ec_ring_copy(); /* * Ethernet software status per interface. *************** *** 101,106 **** --- 114,122 ---- u_char ec_flags; /* software state */ #define EC_RUNNING 0x01 #define EC_TXBUSY 0x02 + #if NBPFILTER > 0 + #define EC_ATTACHED 0x80 + #endif u_char ec_type; /* interface type code */ u_short ec_vector; /* interrupt vector */ *************** *** 111,122 **** caddr_t ec_vmem_addr; /* card RAM virtual memory base */ u_long ec_vmem_size; /* card RAM bytes */ caddr_t ec_vmem_ring; /* receive ring RAM vaddress */ ! caddr_t ec_vmem_end; /* receive ring RAM end */ } ec_softc[NEC]; ! #define PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0); ! #define PAGE1 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1); ! static Bdry; int ether_output(), ecprobe(), --- 127,141 ---- caddr_t ec_vmem_addr; /* card RAM virtual memory base */ u_long ec_vmem_size; /* card RAM bytes */ caddr_t ec_vmem_ring; /* receive ring RAM vaddress */ ! caddr_t ec_vmem_end; /* receive ring RAM end */ ! #if NBPFILTER > 0 ! caddr_t ec_bpf; /* Magic Cookie for BPF */ ! #endif } ec_softc[NEC]; ! #define PAGE0 { outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0); } ! #define PAGE1 { outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1); } ! static Bdry[NEC]; int ether_output(), ecprobe(), *************** *** 166,172 **** * Stop the chip just in case. */ DELAY(1000); ! PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); DELAY(1000); --- 185,191 ---- * Stop the chip just in case. */ DELAY(1000); ! PAGE0; outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); DELAY(1000); *************** *** 198,203 **** --- 217,224 ---- { register struct ec_softc *sc = &ec_softc[is->id_unit]; register struct ifnet *ifp = &sc->ec_if; + struct ifaddr *ifa; + struct sockaddr_dl *sdl; /** ** Initialize the ASIC in same order as Clarkson driver. *************** *** 247,252 **** --- 268,293 ---- */ if_attach(ifp); /* + * Search down the ifa address list looking for the AF_LINK type entry + */ + ifa = ifp->if_addrlist; + while ((ifa != 0) && (ifa->ifa_addr != 0) && + (ifa->ifa_addr->sa_family != AF_LINK)) + ifa = ifa->ifa_next; + /* + * If we found an AF_LINK type entry, we fill in the hardware (link level) addr + */ + if ((ifa != 0) && (ifa->ifa_addr != 0)) { + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ETHER_ADDR_LEN; + sdl->sdl_slen = 0; + bcopy(sc->ec_addr, LLADDR(sdl), ETHER_ADDR_LEN); + } + #if NBPFILTER > 0 + sc->ec_flags &= ~EC_ATTACHED; /* Make sure BPF attach flag clear */ + #endif + /* * Weeee.. We get to tell people we exist... */ printf(" address %s", ether_sprintf(sc->ec_addr)); *************** *** 260,266 **** int i, s; u_short ax, cx; ! Bdry=0; /* * Address not known. */ --- 301,316 ---- int i, s; u_short ax, cx; ! Bdry[unit] = 0; ! ! #if NBPFILTER > 0 ! if ((sc->ec_flags & EC_ATTACHED) == 0) { ! bpfattach(&sc->ec_bpf, ifp, DLT_EN10MB, ! sizeof(struct ether_header)); ! sc->ec_flags |= EC_ATTACHED; ! } ! #endif /* NBPFILTER > 0 */ ! /* * Address not known. */ *************** *** 281,287 **** * (Use sequence recommended by 3Com. ) */ s=splhigh(); ! PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP); outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8); outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0); --- 331,337 ---- * (Use sequence recommended by 3Com. ) */ s=splhigh(); ! PAGE0; outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP); outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8); outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0); *************** *** 297,303 **** /* * Copy Ethernet address from SA_PROM into 8390 chip registers. */ ! PAGE1 for(i=0;i<6;i++) outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]); /* --- 347,353 ---- /* * Copy Ethernet address from SA_PROM into 8390 chip registers. */ ! PAGE1; for(i=0;i<6;i++) outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]); /* *************** *** 317,322 **** --- 367,378 ---- outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA); outb(sc->ec_io_nic_addr + EN0_ISR, 0xff); outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0); + #if NBPFILTER > 0 + if (sc->ec_if.if_flags & IFF_PROMISC) + outb(sc->ec_io_nic_addr + EN0_RXCR, + ENRXCR_BAD | ENRXCR_PROMP | ENRXCR_BCST); + else + #endif outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST); /* * Take interface out of reset, program the vector, *************** *** 357,362 **** --- 413,481 ---- sc->ec_flags |= EC_TXBUSY; (void) splx(s); + #if NBPFILTER > 0 + if (sc->ec_bpf) { + u_short etype; + int off, datasize, resid; + struct ether_header *eh; + struct trailer_header { + u_short ether_type; + u_short ether_residual; + } trailer_header; + char ether_packet[ETHERMTU+100]; + char *ep; + + ep = ether_packet; + + /* + * 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. + */ + /* copy ether header */ + 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); + + /* copy residual data */ + m_copydata(m, off+sizeof(struct trailer_header), + resid = ntohs(trailer_header.ether_residual) - + sizeof(struct trailer_header), ep); + ep += resid; + + /* copy data */ + m_copydata(m, sizeof(struct ether_header), datasize, ep); + ep += datasize; + + /* restore original ether packet type */ + eh->ether_type = trailer_header.ether_type; + + bpf_tap(sc->ec_bpf, ether_packet, ep - ether_packet); + } else + bpf_mtap(sc->ec_bpf, m); + } + #endif /* NBPFILTER > 0 */ + /* * Copy the mbuf chain into the transmit buffer */ *************** *** 375,385 **** */ s=splhigh(); len = MAX(len, ETHER_MIN_LEN); ! PAGE0 outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff); outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8); ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS); (void) splx(s); } --- 494,505 ---- */ s=splhigh(); len = MAX(len, ETHER_MIN_LEN); ! PAGE0; outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff); outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8); ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS); + sc->ec_if.if_timer = 3; (void) splx(s); } *************** *** 399,405 **** * Turn off interrupts while we take care of things. */ ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); ! PAGE0 ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR); outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); loop: --- 519,525 ---- * Turn off interrupts while we take care of things. */ ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); ! PAGE0; ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR); outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); loop: *************** *** 445,451 **** /* * Reenable onboard interrupts. */ ! /*PAGE0*/ outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg); outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f); if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR)) --- 565,571 ---- /* * Reenable onboard interrupts. */ ! /*PAGE0;*/ outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg); outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f); if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR)) *************** *** 462,468 **** /* * Do some statistics. */ ! PAGE0 sc->ec_flags &= ~EC_TXBUSY; sc->ec_if.if_timer = 0; ++sc->ec_if.if_opackets; --- 582,588 ---- /* * Do some statistics. */ ! PAGE0; sc->ec_flags &= ~EC_TXBUSY; sc->ec_if.if_timer = 0; ++sc->ec_if.if_opackets; *************** *** 485,496 **** * Traverse the receive ring looking for packets to pass back. * The search is complete when we find a descriptor not in use. */ ! PAGE0 bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY); ! PAGE1 curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); ! if(Bdry) ! bnry =Bdry; while (bnry != curr) { --- 605,616 ---- * Traverse the receive ring looking for packets to pass back. * The search is complete when we find a descriptor not in use. */ ! PAGE0; bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY); ! PAGE1; curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); ! if(Bdry[unit]) ! bnry = Bdry[unit]; while (bnry != curr) { *************** *** 499,509 **** /* count includes CRC */ len = ecr->ec_count - 4; ! /*if (len > 30 && len <= ETHERMTU+100) */ ecread(sc, (caddr_t)(ecr + 1), len); ! /*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/ outofbufs: ! PAGE0 /* advance on chip Boundry register */ if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) { bnry = EC_RXBUF_OFFSET; --- 619,630 ---- /* count includes CRC */ len = ecr->ec_count - 4; ! if (len > 30 && len <= ETHERMTU+100) ecread(sc, (caddr_t)(ecr + 1), len); ! else ! printf("ec%d: reject - bad length %d\n", unit, len); outofbufs: ! PAGE0; /* advance on chip Boundry register */ if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) { bnry = EC_RXBUF_OFFSET; *************** *** 524,541 **** } /* refresh our copy of CURR */ ! PAGE1 curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); } ! Bdry = bnry; ! PAGE0 } ! #define ecdataaddr(sc, eh, off, type) \ ! ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \ ! (((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \ + (sc)->ec_vmem_ring: \ ! ((caddr_t)((eh)+1)+(off))) ecread(sc, buf, len) register struct ec_softc *sc; --- 645,662 ---- } /* refresh our copy of CURR */ ! PAGE1; curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); } ! Bdry[unit] = bnry; ! PAGE0; } ! #define ringoffset(sc, eh, off, type) \ ! ((type) (((caddr_t)(eh)+(off) >= (sc)->ec_vmem_end) ? \ ! (((caddr_t)(eh)+(off))) - (sc)->ec_vmem_end \ + (sc)->ec_vmem_ring: \ ! ((caddr_t)(eh)+(off)))) ecread(sc, buf, len) register struct ec_softc *sc; *************** *** 542,581 **** char *buf; int len; { ! register struct ether_header *eh; ! struct mbuf *m, *ecget(); int off, resid; ! /* ! * Deal with trailer protocol: if type is trailer type ! * get true type from first 16-bit word past data. ! * Remember that type was trailer by setting off. ! */ eh = (struct ether_header *)buf; ! eh->ether_type = ntohs((u_short)eh->ether_type); ! if (eh->ether_type >= ETHERTYPE_TRAIL && ! eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; ! if (off >= ETHERMTU) return; /* sanity */ ! eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *)); ! resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *))); ! if (off + resid > len) return; /* sanity */ ! len = off + resid; ! } else off = 0; len -= sizeof(struct ether_header); ! if (len <= 0) return; /* ! * Pull packet off interface. Off is nonzero if packet ! * has trailing header; neget will then force this header ! * information to be at the front, but we still have to drop ! * the type and length which are at the front of any trailer data. */ ! m = ecget(buf, len, off, &sc->ec_if, sc); ! if (m == 0) return; ! ether_input(&sc->ec_if, eh, m); } ec_ioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; --- 663,791 ---- char *buf; int len; { ! struct ether_header *eh; ! struct mbuf *m, *head, *ec_ring_to_mbuf(); int off, resid; + u_short etype; + struct trailer_header { + u_short trail_type; + u_short trail_residual; + } trailer_header; ! ++sc->ec_if.if_ipackets; ! ! /* Allocate a header mbuf */ ! MGETHDR(m, M_DONTWAIT, MT_DATA); ! if (m == 0) ! goto bad; ! m->m_pkthdr.rcvif = &sc->ec_if; ! m->m_pkthdr.len = len; ! m->m_len = 0; ! head = m; ! 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 + */ + head->m_data += EOFF; + 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 ! * trailer header. ! * 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) ! goto bad; /* insanity */ ! ! 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 = ec_ring_to_mbuf(sc, ! ringoffset(sc, buf, off+4, char *), head, resid); ! if (m == 0) ! goto bad; ! ! len = off; ! 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 = ec_ring_to_mbuf(sc, buf, m, len); ! if (m == 0) ! goto bad; ! ! #if NBPFILTER > 0 ! /* ! * Check if there's a bpf filter listening on this interface. ! * If so, hand off the raw packet to bpf. ! */ ! if (sc->ec_bpf) { ! bpf_mtap(sc->ec_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->ec_if.if_flags & IFF_PROMISC) && ! bcmp(eh->ether_dhost, sc->ec_addr, sizeof(eh->ether_dhost)) != 0 && ! bcmp(eh->ether_dhost, etherbroadcastaddr, ! sizeof(eh->ether_dhost)) != 0) { ! m_freem(head); ! return; ! } ! #endif ! ! /* ! * 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->ec_if, eh, head); ! return; ! ! bad: ! if (head) ! m_freem(head); ! return; } + ec_ioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; *************** *** 632,637 **** --- 842,854 ---- } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) ec_init(ifp->if_unit); + #if NBPFILTER > 0 + if (sc->ec_if.if_flags & IFF_PROMISC) + outb(sc->ec_io_nic_addr + EN0_RXCR, + ENRXCR_BAD | ENRXCR_PROMP | ENRXCR_BCST); + else + #endif /* NBPFILTER > 0 */ + outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST); break; #ifdef notdef *************** *** 660,668 **** --- 877,889 ---- ec_watchdog(unit) int unit; { + #if 1 + ecintr(unit); + #else log(LOG_WARNING, "ec%d: soft reset\n", unit); ec_stop(unit); ec_init(unit); + #endif } ec_stop(unit) *************** *** 672,678 **** int s; s=splimp(); ! PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); sc->ec_flags &= ~EC_RUNNING; --- 893,899 ---- int s; s=splimp(); ! PAGE0; outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); sc->ec_flags &= ~EC_RUNNING; *************** *** 683,776 **** } /* ! * Pull read data off a interface. ! * Len is length of data, with local net header stripped. ! * Off is non-zero if a trailer protocol was used, and ! * gives the offset of the trailer information. ! * We copy the trailer information and then all the normal ! * data into mbufs. When full cluster sized units are present ! * we copy into clusters. */ struct mbuf * ! ecget(buf, totlen, off0, ifp, sc) ! caddr_t buf; ! int totlen, off0; ! struct ifnet *ifp; struct ec_softc *sc; { ! struct mbuf *top, **mp, *m, *p; ! int off = off0, len; ! register caddr_t cp = buf; ! char *epkt; ! int tc =totlen; ! buf += sizeof(struct ether_header); ! cp = buf; ! epkt = cp + totlen; ! ! if (off) { ! cp += off + 2 * sizeof(u_short); ! totlen -= 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 = ⊤ ! while (totlen > 0) { ! if (top) { 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; - } ! totlen -= len; ! /* only do up to end of buffer */ ! if (cp+len > sc->ec_vmem_end) { ! unsigned toend = sc->ec_vmem_end - cp; ! ! bcopy(cp, mtod(m, caddr_t), toend); ! cp = sc->ec_vmem_ring; ! bcopy(cp, mtod(m, caddr_t)+toend, len - toend); ! cp += len - toend; ! epkt = cp + totlen; ! } else { ! bcopy(cp, mtod(m, caddr_t), (unsigned)len); ! cp += len; } ! *mp = m; ! mp = &m->m_next; ! if (cp == epkt) { ! cp = buf; ! epkt = cp + tc; } } ! return (top); } #endif /* NEC > 0 */ --- 904,978 ---- } /* ! * Copy data from receive buffer to end of mbuf chain ! * allocate additional mbufs as needed. return pointer ! * to last mbuf in chain. ! * sc = ec info ! * src = pointer in ec ring buffer ! * dst = pointer to last mbuf in mbuf chain to copy to ! * amount = amount of data to copy */ struct mbuf * ! ec_ring_to_mbuf(sc,src,dst,total_len) struct ec_softc *sc; + char *src; + struct mbuf *dst; + int total_len; { ! register struct mbuf *m = dst; ! while (total_len > 0) { ! 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 ! * will do. ! */ ! dst = m; MGET(m, M_DONTWAIT, MT_DATA); ! if (m == 0) return (0); ! ! if (total_len >= MINCLSIZE) MCLGET(m, M_DONTWAIT); ! m->m_len = 0; ! dst->m_next = m; ! amount = min(total_len, M_TRAILINGSPACE(m)); } ! ! src = ec_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount); ! ! m->m_len += amount; ! total_len -= amount; ! } + return (m); + } + + static inline char * + ec_ring_copy(sc,src,dst,amount) + struct ec_softc *sc; + char *src; + char *dst; + int amount; + { + int tmp_amount; + + /* does copy wrap to lower addr in ring buffer? */ + if (src + amount > sc->ec_vmem_end) { + tmp_amount = sc->ec_vmem_end - src; + bcopy(src,dst,tmp_amount); /* copy amount up to end */ + amount -= tmp_amount; + src = sc->ec_vmem_ring; + dst += tmp_amount; } ! ! bcopy(src, dst, amount); ! ! return(src + amount); } #endif /* NEC > 0 */ + ============================== cut here ==============================