📄 if_ln.c
字号:
lninit(ifp->if_unit); return; } /* * Find the index of the last descriptor in this * packet (LN_OWN clear and LN_ENP set). If cannot * find it then Lance is still working. */ ring_cnt=1; while (((rp->ln_flag & (LN_RT_ERR|LN_OWN|LN_ENP)) == 0) && (ring_cnt++ <= nLNNRCV)) { index = ++index % nLNNRCV; lnsw->ln_cpyin(sc, sc->rring[index],&rp->ln_flag, sizeof(u_char),(u_long)&rp->ln_flag - (u_long)rp); } /* * more than one; re-init the descriptors involved and * ignore this packet. (May have to bump up DECnet counters). */ if (ring_cnt > 1) { /* * Went all the way around, wait */ if (ring_cnt > nLNNRCV) { if (lndebug) mprintf("ln%d: recv ring_cnt exceeded\n",unit); break; } /* * "free" up the descriptors, but really just use * them over again. Give them back to the Lance * using the same local RAM buffers. IF ERROR INFO. * IS SET, WAIT! */ if (!(rp->ln_flag & LN_RT_ERR)) { lnsw->ln_setflag(sc->rring[first], LN_OWN); while ( first != index ) { first = ++first % nLNNRCV; lnsw->ln_setflag(sc->rring[first], LN_OWN); } if (lndebug) mprintf("ln%d: chained receive packet dropped\n",unit); continue; } } /* * Is it a valid descriptor, ie. * we own the descriptor (LN_OWN==0), * and end of packet (ENP) set? */ if ( (rp->ln_flag & ~LN_STP) == LN_ENP) { lnsw->ln_cpyin(sc, sc->rring[index],&rp->ln_flag2, sizeof(u_short),(u_long)&rp->ln_flag2 - (u_long)rp); /* len here includes the 4 CRC bytes */ len = (rp->ln_flag2 & LN_MCNT); lnread(sc, sc->rlbuf[index], len-4, 0, index); /* * If we're on an architecture which provides DMA, * re-initialize the descriptor to get a new buf. */ if (lnsw->ln_dodma) lnsw->lninitdesc (sc, sc->rring[index], &sc->rlbuf[index], LNNOALLOC,index); /* * "free" up the descriptors. Turn ownership back * back to LANCE. */ lnsw->ln_setflag(sc->rring[first], LN_OWN); /* * else Not a good packet sequence, check for receiver errors */ } else if ((flag = rp->ln_flag) & LN_RT_ERR){ sc->is_if.if_ierrors++; if (flag & (LN_OFLO | LN_CRC | LN_FRAM | LN_RBUFF)) { if (lndebug) mprintf("ln%d: recv err %02x\n",unit, flag&0xff); if (sc->ctrblk.est_recvfail != 0xffff) { sc->ctrblk.est_recvfail++; if (flag & LN_OFLO) { sc->ctrblk.est_recvfail_bm |= 4;#if NPACKETFILTER > 0 sc->is_ed.ess_missed++;#endif NPACKETFILTER > 0 } if (flag & LN_CRC) { sc->ctrblk.est_recvfail_bm |= 1; } if (flag & LN_FRAM) { sc->ctrblk.est_recvfail_bm |= 2; } if (flag & LN_RBUFF) { ; /* causes LN_OFLO to be set */ } } } else { if (lndebug) mprintf("ln%d: stray recv err %02x\n",unit,flag&0xff); } /* * "free" up the descriptors, but really just use * them over again. Give them back to the Lance * using the same pre-allocated mbufs. */ lnsw->ln_setflag(sc->rring[first], LN_OWN); while ( first != index ) { first = ++first % nLNNRCV; /* give away */ lnsw->ln_setflag(sc->rring[first], LN_OWN); } } else { /* else: * - not a good packet, * - not an error situation, * * This can happen if we beat the Lance to the * end of a valid list of receive buffers -- the * Lance hasn't relinquished the last buffer (one * with ENP set) or we just found a buffer still * owned by Lance, without finding the ENP bit. * In either case, just return. We can pick up * the unfinished chain on the next interrupt. */ smp_unlock(&sc->lk_ln_softc); return; } } smp_unlock(&sc->lk_ln_softc);}/* * Start output on interface. * *//* SMP - call with device lock already set. us. */lnstart(unit)int unit;{ register struct ln_softc *sc = ln_softc[unit]; register struct mbuf *m; register int dp; /* data buffer pointer */ register struct ln_ring *rp = &sc->ln_ring; register struct lnsw *lnsw = sc->lnsw; int tlen; int index; register struct ifnet *ifp = &sc->is_if; /* s = splimp(); */ /* SMP */ for (index = sc->tindex; sc->nxmit < (nLNNXMT - 1); sc->tindex = index = ++index % nLNNXMT) { /* * Dequeue the transmit request, if any. */ IF_DEQUEUE(&sc->is_if.if_snd, m); if (m == 0) { return; /* Nothing on the queue */ } /* * "lnput" pads out anything less than "MINDATA" with NULL's */ tlen = lnput(sc, index, m); dp = lnsw->ln_svtolance(sc->tlbuf[index]); rp->ln_buf_len = -(tlen) | 0xf000; rp->ln_addr_lo = (short)dp & 0xffff; rp->ln_addr_hi = (short)(((int)dp >> 16) & 0xff); rp->ln_flag = ( LN_STP | LN_OWN | LN_ENP); lnsw->ln_cpyout(rp,sc->tring[index],sizeof(struct ln_ring),0); sc->ln_rap = LN_CSR0; sc->ln_rdp = ( LN_TDMD | LN_INEA ); sc->nxmit++; ifp->if_flags |= IFF_OACTIVE; /* * Accumulate statistics for DECnet */ if ((sc->ctrblk.est_bytesent + tlen) > sc->ctrblk.est_bytesent) sc->ctrblk.est_bytesent += tlen; if (sc->ctrblk.est_bloksent != (unsigned)0xffffffff) sc->ctrblk.est_bloksent++; sc->is_if.if_timer = 5; }}/* * Process an ioctl request. */lnioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ln_softc *sc = ln_softc[ifp->if_unit]; register struct ln_initb *initb = &sc->ln_initb; register int i; struct ifreq *ifr = (struct ifreq *)data; struct ifdevea *ifd = (struct ifdevea *)data; struct ctrreq *ctr = (struct ctrreq *)data; struct protosw *pr; struct ifaddr *ifa = (struct ifaddr *)data; int bitpos; /* top 6 bits of crc = bit in multicast mask */ u_short newmask[4]; /* new value of multicast address mask */ int j = -1, s, error=0; s = splimp(); switch (cmd) { case SIOCENABLBACK: if (lndebug>1) printf("SIOCENABLBACK "); printf("ln: internal loopback requested\n"); smp_lock(&sc->lk_ln_softc, LK_RETRY); /* set external loopback */ initb->ln_mode &= ~LN_INTL; initb->ln_mode |= LN_LOOP; smp_unlock(&sc->lk_ln_softc); lnrestart( ifp ); ifp->if_flags |= IFF_LOOPBACK; lninit( ifp->if_unit ); break; case SIOCDISABLBACK: if (lndebug>1) printf("SIOCDISABLBACK "); printf("ln: internal loopback disable requested\n"); smp_lock(&sc->lk_ln_softc, LK_RETRY); /* disable external loopback */ initb->ln_mode &= ~LN_INTL; initb->ln_mode &= ~LN_LOOP; smp_unlock(&sc->lk_ln_softc); lnrestart( ifp ); ifp->if_flags &= ~IFF_LOOPBACK; lninit( ifp->if_unit ); break; case SIOCRPHYSADDR: /* * read default hardware address. */ if (lndebug>1) printf("SIOCRPHYSADDR "); smp_lock(&sc->lk_ln_softc, LK_RETRY); bcopy(sc->is_addr, ifd->current_pa, 6); for ( i=0 ; i<6 ; i++ ) { ifd->default_pa[i] = (u_char)((sc->ln_narom[i]>>sc->lnsw->ln_na_align)&0xff); } smp_unlock(&sc->lk_ln_softc); break; case SIOCSPHYSADDR: if (lndebug>1) printf("SIOCSPHYSADDR "); smp_lock(&sc->lk_ln_softc, LK_RETRY); bcopy(ifr->ifr_addr.sa_data, sc->is_addr, 6);#ifdef NPACKETFILTER > 0 pfilt_newaddress(sc->is_ed.ess_enetunit, sc->is_addr);#endif NPACKETFILTER > 0 /* * fill in the initb station address, and restart. */ for (i=j=0; i < 3; i++, j += 2) { initb->ln_sta_addr[i] = (short)(sc->is_addr[j]&0xff); initb->ln_sta_addr[i] |= (short)((sc->is_addr[j+1]&0xff)<<8); } smp_unlock(&sc->lk_ln_softc); if (ifp->if_flags & IFF_RUNNING) { lnrestart(ifp); lninit(ifp->if_unit); } else { lnrestart(ifp); } break; case SIOCDELMULTI: case SIOCADDMULTI: smp_lock(&sc->lk_ln_softc, LK_RETRY); if (cmd == SIOCDELMULTI) { if (lndebug>1) printf("SIOCDELMULTI "); for (i = 0; i < sc->nmulti; i++) if (bcmp(&sc->multi[i],ifr->ifr_addr.sa_data,MULTISIZE) == 0) { if (--sc->muse[i] == 0) { bcopy(ln_sunused_multi,&sc->multi[i],MULTISIZE); } if (lnshowmulti) printf("%d deleted.\n",i); } } else { if (lndebug>1) printf("SIOCADDMULTI "); for (i = 0; i < sc->nmulti; i++) { if (bcmp(&sc->multi[i],ifr->ifr_addr.sa_data,MULTISIZE) == 0) { sc->muse[i]++; if (lnshowmulti) printf("already using index %d\n", i); smp_unlock(&sc->lk_ln_softc); goto done; } if (bcmp(&sc->multi[i],ln_sunused_multi,MULTISIZE) == 0) j = i; } /* * j is initialized to -1; if j > 0, then * represents the last valid unused location * in the multicast table. */ if (j == -1) { if (sc->nmulti == nLNMULTI) { printf("ln: SIOCADDMULTI failed, multicast list full: %d\n",nLNMULTI); error = ENOBUFS; smp_unlock(&sc->lk_ln_softc); goto done; } else { j = sc->nmulti++; } } bcopy(ifr->ifr_addr.sa_data, &sc->multi[j], MULTISIZE); sc->muse[j]++; if (lnshowmulti) printf("added index %d.\n", j); } /* * Recalculate all current multimask crc/bits * and reload multimask info. * * For each currently used multicast address, * calculate CRC, save top 6 bits, load * appropriate mask bit into newmask[i] */ for (i=0; i<4; i++) newmask[i] = 0x0000; for (i=0; i<sc->nmulti; i++) { if (sc->muse[i] == 0) continue; /* returns 32-bit crc in global variable _ln_crc */ ln_docrc(&sc->multi[i], 0, sc); bitpos = ((unsigned int)sc->ln_crc >> 26) & 0x3f; if (lnshowmulti) printf("crc=%x, bit=%d.\n",sc->ln_crc,bitpos); /* 0-15 */ if (bitpos >= 0 && bitpos < 16) newmask[0] |= (1 << (bitpos - 0)); /* 16-31 */ else if (bitpos < 32) newmask[1] |= (1 << (bitpos - 16)); /* 32-47 */ else if (bitpos < 48) newmask[2] |= (1 << (bitpos - 32)); /* 48-63 */ else if (bitpos < 64) newmask[3] |= (1 << (bitpos - 48)); else { if (lndebug || lnshowmulti) printf("ln: bad crc, bitpos=%d.\n", bitpos); } } i = 0; for (i = 0; i < 4; i++) initb->ln_multi_mask[i] = newmask[i] & 0xffff; if (lnshowmulti) { printf("new 64-bit multimask= %04x %04x %04x %04x\n", newmask[0], newmask[1], newmask[2], newmask[3]); } smp_unlock(&sc->lk_ln_softc); if (ifp->if_flags & IFF_RUNNING) { lnrestart(ifp); lninit(ifp->if_unit); } else { lnrestart(ifp); } break; case SIOCRDCTRS: case SIOCRDZCTRS: if (lndebug>1) printf("SIOCRDCTRS "); ctr->ctr_ether = sc->ctrblk; ctr->ctr_type = CTR_ETHER; ctr->ctr_ether.est_seconds = (time.tv_sec - sc->ztime) > 0xfffe ? 0xffff : (time.tv_sec - sc->ztime); if (cmd == SIOCRDZCTRS) { if (lndebug>1) printf("SIOCRDZCTRS "); smp_lock(&sc->lk_ln_softc, LK_RETRY); sc->ztime = time.tv_sec; bzero(&sc->ctrblk, sizeof(struct estat)); smp_unlock(&sc->lk_ln_softc); } break; case SIOCSIFADDR: if (lndebug>1) printf("SIOCSIFADDR "); if (!(ifp->if_flags & IFF_RUNNING)) { lninit(ifp->if_unit); ifp->if_flags |= IFF_UP; } switch(ifa->ifa_addr.sa_family) {#ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; /* * DISABLE */ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif default: if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) { error = (*pr->pr_ifioctl)(ifp, cmd, data); } break; } break; case SIOCSIFFLAGS: if (lndebug > 1) printf("SIOCSIFFLAGS "); /* * If promisuous mode is enabled/disabled restart * to change LANCE mode */ smp_lock(&sc->lk_ln_softc, LK_RETRY); if ((ifp->if_flags & IFF_PROMISC) && !(initb->ln_mode & LN_PROM)) { /* should be in promiscuous mode */ initb->ln_mode |= LN_PROM; } else if (!(ifp->if_flags & IFF_PROMISC)) { /* should not be in promiscuous mode */ initb->ln_mode &= ~LN_PROM; } smp_unlock(&sc->lk_ln_softc); if (ifp->if_flags & IFF_RUNNING) { lnrestart(ifp); lninit(ifp->if_unit); } else { lnrestart(ifp); } break; default: error = EINVAL; }done: splx(s); return (error);}/* * Calculate 32-bit CRC (AUTODIN-II) for the given 48-bit * multicast address. The CRC table must first be initialized * for the vax crc instruction to work. The crc is returned in * variable ln_crc. */ln_docrc(addr, flag, sc) struct ln_multi *addr; int flag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -