📄 if_we.c
字号:
/* 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->we_if.if_ierrors; } /* normal transmit complete */ if (weisr.is_ptx || weisr.is_txe) wetint (unit); /* normal receive notification */ if (weisr.is_prx || weisr.is_rxe) werint (unit); /* try to start transmit */ westart(&sc->we_if); /* re-enable onboard interrupts */ wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_ps = 0; 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) { /* * I caught it looping forever here a couple of times, * but I haven't had time to figure out why. Just * returning seems to be safe, and it does not appear * to interfere with future packets. - Pace 5/19/92 */ if (--nloops <= 0) { printf ("we0: weintr is looping\n"); return; } goto loop; }} /* * Ethernet interface transmit interrupt. */wetint(unit) int unit;{ register struct we_softc *sc = &we_softc[unit]; /* * Do some statistics (assume page zero of NIC mapped in) */ sc->we_flags &= ~WDF_TXBUSY; sc->we_if.if_timer = 0; ++sc->we_if.if_opackets; sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);} /* * Ethernet interface receiver interrupt. */werint(unit) int unit;{ register struct we_softc *sc = &we_softc[unit]; u_char bnry, curr; long len; union we_command wecmd; struct we_ring *wer; /* * 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); wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY); wecmd.cs_ps = 1; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); curr = inb(sc->we_io_nic_addr + WD_P1_CURR);if(Bdry) bnry =Bdry; while (bnry != curr) { /* get pointer to this buffer header structure */ wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8)); /* count includes CRC */ len = wer->we_count - 4; if (len > 30 && len <= ETHERMTU+100 /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/) weread(sc, (caddr_t)(wer + 1), len); else printf("reject %d", len);outofbufs: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_ps = 0; 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) { bnry = WD_TXBUF_SIZE; outb(sc->we_io_nic_addr + WD_P0_BNRY, sc->we_vmem_size / WD_PAGE_SIZE-1); } else { if (len > 30 && len <= ETHERMTU+100) bnry = wer->we_next_packet; else bnry = curr; /* 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); bnry = WD_TXBUF_SIZE; } else outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1); } /* refresh our copy of CURR */ wecmd.cs_ps = 1; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); curr = inb(sc->we_io_nic_addr + WD_P1_CURR); }Bdry = bnry;}#ifdef shit/* * Process an ioctl request. */weioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ struct we_softc *sc = &we_softc[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *)data; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; weinit(ifp->if_unit); switch(ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(sc->we_addr); else wesetaddr(ina->x_host.c_host, ifp->if_unit); break; }#endif } break; case SIOCSIFFLAGS: if (((ifp->if_flags & IFF_UP) == 0) && (sc->we_flags & WDF_RUNNING)) { westop(ifp->if_unit); } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && ((sc->we_flags & WDF_RUNNING) == 0)) weinit(ifp->if_unit); break; default: error = EINVAL; } (void) splx(s); return (error);}#endif /* * Process an ioctl request. */weioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ 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 (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: weinit(ifp->if_unit); /* before arpwhohas */ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(sc->ns_addr); else { /* * The manual says we can't change the address * while the receiver is armed, * so reset everything */ ifp->if_flags &= ~IFF_RUNNING; bcopy((caddr_t)ina->x_host.c_host, (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); } weinit(ifp->if_unit); /* does ne_setaddr() */ break; }#endif default: weinit(ifp->if_unit); break; } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~IFF_RUNNING; westop(ifp->if_unit); } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) weinit(ifp->if_unit); break;#ifdef notdef case SIOCGHWADDR: bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr)); break;#endif default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */wesetaddr(physaddr, unit) u_char *physaddr; int unit;{ register struct we_softc *sc = &we_softc[unit]; register int i; /* * Rewrite ethernet address, and then force restart of NIC */ for (i = 0; i < ETHER_ADDR_LEN; i++) sc->we_addr[i] = physaddr[i]; sc->we_flags &= ~WDF_RUNNING; weinit(unit);} #define wedataaddr(sc, eh, off, type) \ ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \ (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \ + (sc)->we_vmem_ring: \ ((caddr_t)((eh)+1)+(off)))/* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */weread(sc, buf, len) register struct we_softc *sc; char *buf; int len;{ register struct ether_header *eh; struct mbuf *m, *weget(); 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(*wedataaddr(sc, eh, off, u_short *)); resid = ntohs(*(wedataaddr(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 = weget(buf, len, off, &sc->we_if, sc); if (m == 0) return; ether_input(&sc->we_if, eh, m);}/* * Supporting routines *//* * 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 *weget(buf, totlen, off0, ifp, sc) caddr_t buf; int totlen, off0; struct ifnet *ifp; struct we_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->we_vmem_end) { unsigned toend = sc->we_vmem_end - cp; bcopy(cp, mtod(m, caddr_t), toend); cp = sc->we_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -