📄 if_ix.c
字号:
if (ix_DoReq(mp, rp, IXC_GSTAT, /* Get Stats */ (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, rpb, 0)) return; bcopy((caddr_t) &ix->ix_stats, (caddr_t) ix->ix_addr, 6); } ix->ix_if.if_flags |= IFF_RUNNING; ix->ix_flags |= IXF_RUNNING; ifp->if_watchdog = ixwatch; ifp->if_timer = ix->ix_scaninterval = IXWATCHINTERVAL; ixrint(mp, 0);}/* * Start output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. */ixstart(ifp)struct ifnet *ifp;{ int len = 0; int unit = ifp->if_unit; register struct ix_softc *ix = &ix_softc[unit]; register struct mbuf *n; struct mbuf *m; int s, error = 0; struct npmaster *mp = ix->ix_mp; struct npreq *rp = ix->ix_wrp; struct CQE *ep; u_short rpb[8]; IF_DEQUEUE(&ix->ix_if.if_snd, m); if (m == 0) { if (ix->ix_flags & IXF_STATPENDING) { ix->ix_flags &= ~IXF_STATPENDING; ix->ix_if.if_flags |= IFF_OACTIVE; rpb[0] = 2; rpb[1] = ix->ix_aid; rpb[2] = 0; /* get all stats */ ix_DoReq(mp, rp, IXC_GSTAT, /* general Stats */ (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, rpb, ixcint); } return (0); } /* * 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. */ len = if_wubaput(&ix->ix_ifuba, m); if (len - sizeof(struct ether_header) < ETHERMIN) len = ETHERMIN + sizeof(struct ether_header); ix->ix_if.if_flags |= IFF_OACTIVE; /* Now setup to call np driver */ rpb[0] = 8; rpb[1] = ix->ix_aid; ix_DoReq(mp, rp, IXC_XMIT, /* send frame */ ix->ix_ifuba.ifu_w.ifrw_info, len, rpb, ixcint); return (0);}/* * Command done interrupt. (almost) */ixcint(mp, rp) struct npmaster *mp; struct npreq *rp;{ struct CQE *ep; register struct ix_softc *ix; int s = splimp(); ep = rp->element; ix = (struct ix_softc *)ep->cqe_famid; ix->ix_flags &= ~IXF_OWATCH; if ((ix->ix_if.if_flags & IFF_OACTIVE) == 0) { printf("ix%d: stray xmit interrupt, npreq=%x\n", ix->ix_if.if_unit, rp); } ix->ix_if.if_flags &= ~IFF_OACTIVE; if (rp->flags & IOABORT || ep->cqe_sts != NPDONE || ep->cqe_ust0 != NPDONE || ep->cqe_ust1 != NPOK) { if (ep->cqe_ust1 == 0x48) ix->ix_if.if_oerrors++; else { struct ix_softc *ix = (struct ix_softc *)ep->cqe_famid; printf( "ix%d: ixcint failed, cmd %x, stat %x, flags %x, ", ix->ix_if.if_unit, rp->user, ep->cqe_sts, rp->flags); printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); if (++ix->ix_badcqe > 65) { ix->ix_badcqe = 0; printf("ixcint: shutting down unix dla\n"); ix->ix_if.if_flags &= ~IFF_UP; } } } else switch (ep->cqe_func) { case IXC_XMIT: ix->ix_if.if_opackets++; break; case IXC_GSTAT: ix->ix_if.if_collisions += ix->ix_stats.ixg.macg_xrty; }done: if (ix->ix_ifuba.ifu_xtofree) { m_freem(ix->ix_ifuba.ifu_xtofree); ix->ix_ifuba.ifu_xtofree = 0; } if ((ix->ix_if.if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) (void) ixstart(&ix->ix_if); splx(s);}/* * 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. */ixrint(mp, rp) struct npmaster *mp; struct npreq *rp;{ struct CQE *ep; register struct ix_softc *ix = ix_softc + mp->unit; register struct ether_header *il; struct mbuf *m; int len, off, resid, s; register struct ifqueue *inq; if ((ix->ix_flags & IXF_RUNNING) == 0) return; if (rp == 0) goto setup; ix->ix_flags &= ~(IXF_RCVPENDING|IXF_RWATCH); ep = rp->element; ix->ix_if.if_ipackets++; if (ix->ix_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(ix->ix_ifuba.ifu_uba, ix->ix_ifuba.ifu_r.ifrw_bdp); il = (struct ether_header *)(ix->ix_ifuba.ifu_r.ifrw_addr); len = ep->cqe_bcnt - sizeof (struct ether_header); if (ep->cqe_sts != NPDONE || rp->flags & IOABORT || ep->cqe_ust0 != NPDONE || ep->cqe_ust1 != NPOK) { printf("ix%drint: cqe error, cmd %x, stat %x, flags %x, ", ix->ix_if.if_unit, rp->user, ep->cqe_sts, rp->flags); printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); if (++ix->ix_badcqe > 50) { ix->ix_badcqe = 0; printf("ixrint: shutting down unix dla\n"); ix->ix_if.if_flags &= ~IFF_UP; return; } goto setup; } if ( len < 46 || len > ETHERMTU) { ix->ix_if.if_ierrors++;#ifdef notdef if (ix->ix_if.if_ierrors % 100 == 0) printf("ix%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->ether_type = ntohs((u_short)il->ether_type);#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) if (il->ether_type >= ETHERTYPE_TRAIL && il->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (il->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) goto setup; /* sanity */ il->ether_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(&ix->ix_ifuba, len, off, &ix->ix_if); if (m) ether_input(&ix->ix_if, il, m);setup: /* * Reset for next packet if possible. * If waiting for transmit command completion, set flag * and wait until command completes. */ if (rp == 0) { rp = ix->ix_rrp; rp->intr = ixrint; ep = rp->element; } len = ETHERMTU + sizeof(struct ether_header); /* Now setup to call np driver */ /* Initializations of request structure */ ep->cqe_func = IXC_RECV; /* get frame */ ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status */ ep->cqe_bcnt = len; /* Byte count */ ep->cqe_lenrpb = 10; /* RPB length */ ep->rpb1 = ix->ix_aid; /* which channel */ ep->rpb2 = 65535; /* Timeout */ ix->ix_flags |= IXF_RCVPENDING; s = spl5(); NpAddCQE(ep, &mp->shmemp->devcq, mp); /* Add CQE to device's queue */ splx(s);}long ixwatchcount;/* * Watchdog routine, request statistics from board. */ixwatch(unit) int unit;{ register struct ix_softc *ix = &ix_softc[unit]; register struct ifnet *ifp = &ix->ix_if; int s; ixwatchcount++; if (ix->ix_badcqe > 1) { ix->ix_badcqe--; /* If errors aren't happening too fast, give the board a reprieve */ } s = splimp(); if (ix->ix_flags & IXF_STATPENDING) { ifp->if_timer = ix->ix_scaninterval; ix->ix_flags |= IXF_OWATCH; splx(s); return; } ix->ix_flags |= IXF_STATPENDING; if ((ix->ix_if.if_flags & IFF_OACTIVE) == 0) (void) ixstart(ifp); else ix->ix_flags |= IXF_OWATCH; if (ix->ix_flags & IXF_RCVPENDING) ix->ix_flags |= IXF_RWATCH; splx(s); ifp->if_timer = ix->ix_scaninterval;}/* * Process an ioctl request. */ixioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct ix_softc *ix = &ix_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ixinit(ifp->if_unit); if ((ifp->if_flags & IFF_UP) == 0) return (EBUSY); 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 *) (ix_softc[ifp->if_unit].ix_addr); } else { return ix_setaddr(ina->x_host.c_host, ifp->if_unit); } break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ix->ix_flags & IXF_RUNNING) { ix->ix_flags &= ~IXF_RUNNING; NpReset(ix->ix_mp, 0); } else if (ifp->if_flags & IFF_UP && (ix->ix_flags & IXF_RUNNING) == 0) ixinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */ix_setaddr(physaddr, unit)u_char *physaddr;int unit;{ register struct ix_softc *ix = &ix_softc[unit]; if (! (ix->ix_flags & IXF_RUNNING)) return (EBUSY); /* The following is a big cop out due to the fact that Changing the ethernet address resets the dla module, so must re-open the channel, anyway. */ bcopy((caddr_t)physaddr, (caddr_t)ix->ix_addr, sizeof ix->ix_addr); ix->ix_flags &= ~IXF_RUNNING; ix->ix_flags |= IXF_SETADDR; ixinit(unit); NpKill(ix->ix_mp, ix->ix_rrp);}static showme() { return ((int) &(ix_softc->ix_badcqe));}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -