📄 if_xna.c
字号:
* the port. Wakeup anyone waiting for command completions. */ for (index = ((sc->tlast+1)%nNXNACMD), tp = &sc->tring[index]; (sc->nxmit > 0 && (tp->status & ST_TOWN)); index = ++index % nNXNACMD, tp = &sc->tring[index]) { /* * Process cmd/xmit descriptor */ mp = tp->mbuf_tofree; tp->mbuf_tofree = 0; if (tp->status & ST_CMD) { /* Command */ struct xnacmd_buf *xcmd; /* * Grab command buffer address from mbuf wrapper. * Process which posted command will free both the * wrapper and the command buffer. */ xcmd = mtod(mp, struct xnacmd_buf *); switch (xcmd->opcode) { case CMD_RCCNTR: if (!(tp->status & ST_TERR)) { bzero(&sc->ctrblk, sizeof(struct xnacmd_buf)); sc->ztime = time.tv_sec; } case CMD_RDCNTR: /* * Make certain we don't attempt to * free the ctrblk region of the softc */ mp->m_off = MMINOFF; mp->m_len = MLEN; m_freem(mp); break; case CMD_NOP: /* * XNATIMEOUT timer went off before this * command was processed; simply free * the mbuf, since the person who * issued this command has gone away. */ printf ("xna%d: command timed out\n"); m_freem(mp); break; case CMD_PARAM: case CMD_SYSID: case CMD_USTART: case CMD_UCHANGE: case CMD_USTOP: /* * On command failure, alert caller * by invalidating the command opcode. */ if (tp->status & ST_TERR) { printf ("xna%d: command failed, error code: 0x%x\n", unit, tp->error); xcmd->opcode = CMD_INVAL; } else xcmd->opcode = CMD_COMPLETE; break; default: xcmd->opcode = CMD_INVAL; break; } } else { /* Transmit */ if (tp->status & ST_TERR) { sc->is_if.if_oerrors++; m_freem(mp); } else { sc->is_if.if_opackets++; /* * Loop back any broadcasts we send */ if ((!(bcmp(mtod(mp, caddr_t), etherbroadcastaddr, 6))) || (sc->is_if.if_flags & IFF_PFCOPYALL)) { struct mbuf *m0 = mp; int len = 0; while (m0) { len += m0->m_len; m0 = m0->m_next; } xnaread(sc, 0, len, mp); } else { m_freem(mp); } } } sc->tlast = index; /* Last cmd/xmit processed */ sc->nxmit--; sc->nproc++; } } /* * Dequeue next transmit request if interface is no longer busy. */ if (sc->nxmit <= 0) { sc->is_if.if_flags &= ~IFF_OACTIVE; xnastart( unit ); } /* * Ring Release function. Tell port how many ring entries we've * processed. Drop softc lock and return from interrupt. */ addr->xnapd2 = sc->nproc; smp_unlock(&sc->lk_xna_softc); splx(s);}/* * XNA read routine. Pass input packets up to higher levels. */xnaread (sc, m, len, swloop) register struct xna_softc *sc; struct mbuf *m; register int len; struct mbuf *swloop;{ register struct ether_header *eptr; register int off, resid; struct mbuf *swloop_tmp1; struct ether_header eh; struct protosw *pr; struct ifqueue *inq; /* * Deal with trailer protocol: if type is INET trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ if (swloop) {#ifdef mips /* * Architectures which place the adapter in physical * addressing mode must data copy mbuf chains into a * cluster. (Which is known to be physically contig.) * This cluster will be tagged to the end of the actual * chain and must be freed before we continue. */ for (swloop_tmp1 = swloop; swloop_tmp1->m_next->m_next; swloop_tmp1 = swloop_tmp1->m_next); m_freem(swloop_tmp1->m_next); swloop_tmp1->m_next = 0;#endif mips eptr = mtod(swloop, struct ether_header *); eh = *eptr; eptr = &eh; if ( swloop->m_len > sizeof(struct ether_header)) m_adj(swloop, sizeof(struct ether_header)); else { MFREE(swloop, swloop_tmp1); if ( ! swloop_tmp1 ) return; else swloop = swloop_tmp1; } } else { m->m_len = len -= 4; /* subtract 4 bytes CRC */ eptr = mtod(m, struct ether_header *); eh = *eptr; eptr = &eh; } eptr->ether_type = ntohs((u_short)eptr->ether_type); if ((eptr->ether_type >= ETHERTYPE_TRAIL && eptr->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER)) { off = (eptr->ether_type - ETHERTYPE_TRAIL) * 512 + sizeof(struct ether_header); if (off >= ETHERMTU) return; /* sanity */ if (swloop) { struct mbuf *mprev, *m0 = swloop;/* need to check this against off */ mprev = m0; while (swloop->m_next){/*real header at end of chain*/ mprev = swloop; swloop = swloop->m_next; } /* move to beginning of chain */ mprev->m_next = 0; swloop->m_next = m0; eptr->ether_type = ntohs( *mtod(swloop, u_short *)); } else { eptr->ether_type = ntohs(*(short *)(mtod(m, caddr_t) + off)); resid = ntohs(*(short *)(mtod(m, caddr_t) + off +2)); if (off + resid > m->m_len) return; /* sanity */ } } else { off = 0; } /* * Pull packet off interface. (In the case of the XNA, only need * to shuffle trailer data around, then hand up the address of the * mbuf we had tied to the receive descriptor.) Off is nonzero if * packet has trailing header; need to 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. */ if (swloop) { m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); if (m == 0) return; } else { struct mbuf *m0 = m; if (off) { int nbytes; int cnt = resid; struct mbuf *n; struct mbuf **mp = &m; while (cnt > 0) { MGET(n, M_DONTWAIT, MT_DATA); if (n == 0) { m_freem(m); return; } nbytes = MIN(MLEN, cnt); bcopy((mtod(m, caddr_t) + off), mtod(n, caddr_t), nbytes); n->m_len = nbytes; off += nbytes; cnt -= nbytes; *mp = n; mp = &n->m_next; } /* * Done hoisting trailer data; tie m0 onto the * end of the chain, and drop trailer data length */ *mp = m0; m0->m_len -= resid; /* * Adjust head of chain for trailer header */ m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } /* * Trim off ethernet header */ m0->m_off += sizeof (struct ether_header); m0->m_len -= sizeof (struct ether_header); } /* * Subtract length of header from len */ len -= sizeof (struct ether_header); /* Dispatch this packet */ net_read(&(sc->is_ed), eptr, m, len, (swloop != NULL), (off != 0));}/* * Process an ioctl request. */xnaioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct xna_softc *sc = &xna_softc[ifp->if_unit]; register struct xnadevice *addr = &sc->xregs; register struct xnacmd_buf *xcmd; struct protosw *pr; struct mbuf *m; struct ifreq *ifr = (struct ifreq *)data; struct ifdevea *ifd = (struct ifdevea *)data; register struct ifaddr *ifa = (struct ifaddr *)data; struct ctrreq *ctr = (struct ctrreq *)data; int s, error = 0; switch (cmd) { case SIOCENABLBACK: case SIOCDISABLBACK: if (cmd == SIOCENABLBACK) ifp->if_flags |= IFF_LOOPBACK; else ifp->if_flags &= ~IFF_LOOPBACK; if (ifp->if_flags & IFF_RUNNING) { /* * Lock softc. Same comments as for "xnainit()" */ s = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); if (m = xnamkparam(sc, ifp)) { xnacmd(sc, m); smp_unlock(&sc->lk_xna_softc); splx(s); xcmd = mtod(m, struct xnacmd_buf *); XNATIMEOUT(xcmd, CMD_PARAM); /* Wait */ switch (xcmd->opcode) { case CMD_COMPLETE: m_freem(m); break; case CMD_INVAL: m_freem(m); case CMD_NOP: default: error = EINVAL; break; } } else { smp_unlock(&sc->lk_xna_softc); error = ENOBUFS; splx(s); } } break; case SIOCRPHYSADDR: /* * read default hardware address. Lock softc while accessing * per-unit physical address info. */ s = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); bcopy(sc->is_dpaddr, ifd->default_pa, 6); bcopy(sc->is_addr, ifd->current_pa, 6); smp_unlock(&sc->lk_xna_softc); splx(s); break; case SIOCSPHYSADDR: /* * Set physaddr. Lock softc while updating per-unit physical * address, and for command processing as in "xnainit()". */ s = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); bcopy(ifr->ifr_addr.sa_data, sc->is_addr, 6);#if NPACKETFILTER > 0 pfilt_newaddress(sc->is_ed.ess_enetunit, sc->is_addr);#endif NPACKETFILTER if (ifp->if_flags & IFF_RUNNING) { if (m = xnamkparam(sc, ifp)) { xnacmd(sc, m); smp_unlock(&sc->lk_xna_softc); splx(s); xcmd = mtod(m, struct xnacmd_buf *); XNATIMEOUT(xcmd, CMD_PARAM); /* Wait */ switch (xcmd->opcode) { case CMD_COMPLETE: m_freem(m); break; case CMD_INVAL: m_freem(m); case CMD_NOP: default: error = EINVAL; break; } } else { smp_unlock(&sc->lk_xna_softc); error = ENOBUFS; splx(s); } } else { smp_unlock(&sc->lk_xna_softc); splx(s); xnainit(ifp->if_unit); } break; case SIOCDELMULTI: case SIOCADDMULTI: /* * Lock softc while updating per-unit multicast address * list and for command processing as in "xnainit()". */ s = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); if (cmd == SIOCDELMULTI) { /* * If we're deleting a multicast address, decrement * the is_muse count and invalidate the address if * count goes to zero. */ int i; for (i = 0; i < NMULTI; i++) { if (bcmp(sc->is_multi[i], ifr->ifr_addr.sa_data,6) == 0) break; } if ((i < NMULTI) && (--sc->is_muse[i] == 0)) bcopy(etherbroadcastaddr,sc->is_multi[i],6); else { smp_unlock(&sc->lk_xna_softc); splx(s); goto done; } } else { /* * If we're adding a multicat address, increment the * is_muse count if it's already in our table, and * return. Otherwise, add it to the table or return * ENOBUFS if we're out of entries. */ int i, j = -1; for (i = 0; i < NMULTI; i++) { if (bcmp(sc->is_multi[i], ifr->ifr_addr.sa_data,6) == 0) { sc->is_muse[i]++; smp_unlock(&sc->lk_xna_softc); splx(s); goto done; } if ((j < 0) && (bcmp(sc->is_multi[i], etherbroadcastaddr,6) == 0)) j = i; } if (j < 0) { printf("xna%d: addmulti failed, multicast list full: %d\n", ifp->if_unit, NMULTI); smp_unlock(&sc->lk_xna_softc); error = ENOBUFS; splx(s); goto done; } else { bcopy(ifr->ifr_addr.sa_data, sc->is_multi[j], 6); sc->is_muse[j]++; } } if (ifp->if_flags & IFF_RUNNING) { /* * If we've successfully init'ed the interface, * issue a UCHANGE command to update the ethernet * user's multicast address list. Otherwise, the * list will be initialized upon the first call * to "xnainit()". */ if (m = xnamkuser(sc, XNA_ETHERU, CMD_UCHANGE)) { xnacmd(sc, m); smp_unlock(&sc->lk_xna_softc); splx(s); xcmd = mtod(m, struct xnacmd_buf *); XNATIMEOUT(xcmd, CMD_UCHANGE); /* Wait */ switch (xcmd->opcode) { case CMD_COMPLETE: m_freem(m); break; case CMD_INVAL: m_freem(m); case CMD_NOP: default: error = EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -