?? if_il.c
字號:
is->is_if.if_flags |= IFF_ALLMULTI; goto too_many_multis; } }#endif MULTI /* * Set board online. * Hang receive buffer and start any pending * writes by faking a transmit complete. * Receive bcr is not a multiple of 8 so buffer * chaining can't happen. */ addr->il_csr = ILC_ONLINE; while ((addr->il_csr & IL_CDONE) == 0) ; addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; while ((addr->il_csr & IL_CDONE) == 0) ; is->is_if.if_flags |= IFF_RUNNING | IFF_OACTIVE; is->is_flags |= ILF_RUNNING; is->is_lastcmd = 0; ilcint(unit); splx(s);}/* * Start output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. */ilstart(ifp) register struct ifnet *ifp;{ int unit = ifp->if_unit, len; struct uba_device *ui = ilinfo[unit]; register struct il_softc *is = &il_softc[unit]; register struct ildevice *addr; struct mbuf *m; short csr; IF_DEQUEUE(&is->is_if.if_snd, m); addr = (struct ildevice *)ui->ui_addr; if (m == 0) { if ((is->is_flags & ILF_STATPENDING) == 0) return (0); addr->il_bar = is->is_ubaddr & 0xffff; addr->il_bcr = sizeof (struct il_stats); csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; is->is_flags &= ~ILF_STATPENDING; goto startcmd; } len = if_wubaput(&is->is_ifuba, m); /* * Ensure minimum packet length. * This makes the safe assumtion that there are no virtual holes * after the data. * For security, it might be wise to zero out the added bytes, * but we're mainly interested in speed at the moment. */ if (len - sizeof(struct ether_header) < ETHERMIN) len = ETHERMIN + sizeof(struct ether_header); if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; addr->il_bcr = len; csr = ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;startcmd: is->is_lastcmd = csr & IL_CMD; addr->il_csr = csr; is->is_if.if_flags |= IFF_OACTIVE; return (0);}/* * Command done interrupt. */ilcint(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; struct uba_device *ui = ilinfo[unit]; register struct ildevice *addr = (struct ildevice *)ui->ui_addr; short csr; if ((is->is_if.if_flags & IFF_OACTIVE) == 0) { printf("il%d: stray xmit interrupt, csr=%b\n", unit, addr->il_csr, IL_BITS); return; } csr = addr->il_csr; /* * Hang receive buffer if it couldn't * be done earlier (in ilrint). */ if (is->is_flags & ILF_RCVPENDING) { int s; addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; s = splhigh(); while ((addr->il_csr & IL_CDONE) == 0) ; splx(s); is->is_flags &= ~ILF_RCVPENDING; } is->is_if.if_flags &= ~IFF_OACTIVE; csr &= IL_STATUS; switch (is->is_lastcmd) { case ILC_XMIT: is->is_if.if_opackets++; if (csr > ILERR_RETRIES) is->is_if.if_oerrors++; break; case ILC_STAT: if (csr == ILERR_SUCCESS) iltotal(is); break; } if (is->is_ifuba.ifu_xtofree) { m_freem(is->is_ifuba.ifu_xtofree); is->is_ifuba.ifu_xtofree = 0; } (void) ilstart(&is->is_if);}/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Otherwise purge input buffered data path and examine * packet to determine type. If can't determine length * from type, then have to drop packet. Othewise decapsulate * packet based on type and pass to type specific higher-level * input routine. */ilrint(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; register struct il_rheader *il; struct mbuf *m; int len, off, resid, s; register struct ifqueue *inq; is->is_if.if_ipackets++; if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); len = il->ilr_length - sizeof(struct il_rheader); if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || len > ETHERMTU) { is->is_if.if_ierrors++;#ifdef notdef if (is->is_if.if_ierrors % 100 == 0) printf("il%d: += 100 input errors\n", unit);#endif goto setup; } /* * 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. */ il->ilr_type = ntohs((u_short)il->ilr_type);#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) if (il->ilr_type >= ETHERTYPE_TRAIL && il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) goto setup; /* sanity */ il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); resid = ntohs(*(ildataaddr(il, off+2, u_short *))); if (off + resid > len) goto setup; /* sanity */ len = off + resid; } else off = 0; if (len == 0) goto setup; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; ilget 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 = if_rubaget(&is->is_ifuba, len, off, &is->is_if); if (m) ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m);setup: /* * Reset for next packet if possible. * If waiting for transmit command completion, set flag * and wait until command completes. */ if (is->is_if.if_flags & IFF_OACTIVE) { is->is_flags |= ILF_RCVPENDING; return; } addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; s = splhigh(); while ((addr->il_csr & IL_CDONE) == 0) ; splx(s);}/* * Watchdog routine, request statistics from board. */ilwatch(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; register struct ifnet *ifp = &is->is_if; int s; if (is->is_flags & ILF_STATPENDING) { ifp->if_timer = is->is_scaninterval; return; } s = splimp(); is->is_flags |= ILF_STATPENDING; if ((is->is_if.if_flags & IFF_OACTIVE) == 0) (void) ilstart(ifp); splx(s); ifp->if_timer = is->is_scaninterval;}/* * Total up the on-board statistics. */iltotal(is) register struct il_softc *is;{ register u_short *interval, *sum, *end; interval = &is->is_stats.ils_frames; sum = &is->is_sum.ils_frames; end = is->is_sum.ils_fill2; while (sum < end) *sum++ += *interval++; is->is_if.if_collisions = is->is_sum.ils_collis; if ((is->is_flags & ILF_SETADDR) && (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, sizeof (is->is_addr)) != 0)) { log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit); is->is_flags &= ~ILF_RUNNING; ilinit(is->is_if.if_unit); }}/* * Process an ioctl request. */ilioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct il_softc *is = &il_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ilinit(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 *) (il_softc[ifp->if_unit].is_addr); } else { il_setaddr(ina->x_host.c_host, ifp->if_unit); return (0); } break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && is->is_flags & ILF_RUNNING) { ((struct ildevice *) (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; is->is_flags &= ~ILF_RUNNING; } else if (ifp->if_flags & IFF_UP && (is->is_flags & ILF_RUNNING) == 0) ilinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */il_setaddr(physaddr, unit)u_char *physaddr;int unit;{ register struct il_softc *is = &il_softc[unit]; if (! (is->is_flags & ILF_RUNNING)) return; bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); is->is_flags &= ~ILF_RUNNING; is->is_flags |= ILF_SETADDR; ilinit(unit);}#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -