📄 if_ln.c
字号:
} while (totlen > 0) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); m_freem(tp); return (0); } len = totlen; if (len >= 512) { struct mbuf *p; MCLGET(m, p); if (p == 0) goto nopage; m->m_len = len; goto copy; }nopage: m->m_len = MIN(MLEN, len); m->m_off = MMINOFF;copy: lrbptr = lnsw->ln_cpyinb(sc, lrbptr, mtod(m, caddr_t),(unsigned)m->m_len, 0);next_m: *mp = m; mp = &m->m_next; totlen -= m->m_len; } *mp = tp; #ifdef mips wbflush();#endif return (top);}/* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */lnread(sc, rlbuf, len, swloop, index) register struct ln_softc *sc; register char *rlbuf; int len,index; struct mbuf *swloop;{ register struct ether_header *eptr, eh; register struct lnsw *lnsw = sc->lnsw; /* ptr to switch struct */ struct mbuf *m, *swloop_tmp1; struct protosw *pr; int off, resid; 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) { 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 { if ( lnsw->ln_dodma && (m= sc->rmbuf[index]) &&sc->dma[index] ) { eptr = mtod(m, struct ether_header *); m->m_off += sizeof( struct ether_header ); } else { if ( lnsw->ln_dodma && !m ) /* Couldn't get an mbuf */ return; eptr = &eh; rlbuf = lnsw->ln_cpyinb(sc, rlbuf, eptr, sizeof(struct ether_header), 0); } /* * Done with ether_header; drop len */ len -= sizeof(struct ether_header); } if (!(sc->is_if.if_flags & IFF_PROMISC) ) { /* * Make sure our multicast address filter doesn't hand us * up something that doesn't belong to us! */ if ((eptr->ether_dhost[0] & 1) && (bcmp ((caddr_t)eptr->ether_dhost, (caddr_t)etherbroadcastaddr,MULTISIZE))) { int i; for (i = 0; i < sc->nmulti; i++) { if (sc->muse[i] && !(bcmp (&sc->multi[i],eptr->ether_dhost,MULTISIZE))) break; } if (i == sc->nmulti ) { if ( lnsw->ln_dodma ) m_freem(sc->rmbuf[index]); return; } } } sc->is_if.if_ipackets++; 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; if (off >= ETHERMTU) { if ( lnsw->ln_dodma ) m_freem(sc->rmbuf[index]); return; /* sanity */ } if (swloop) { struct mbuf *mprev, *m0 = swloop; 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 *)); m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); } else { if(m = lnsw->lnget(sc, rlbuf, len, off, index)) { eptr->ether_type = ntohs( *mtod(m, u_short *)); resid = ntohs( *(mtod(m, u_short *)+1)); if (off + resid > len) { if ( lnsw->ln_dodma ) m_freem(sc->rmbuf[index]); return; /* sanity */ } len = off + resid; } else /* can't get mbuf */ return; } } else { off = 0; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; lnget 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. */ if (swloop) { m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); } else { if(lnsw->ln_dodma && sc->dma[index]) m->m_len = len; else m = lnsw->lnget(sc, rlbuf, len, off, index); } } if (m == 0) { return; } if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } /* * Bump up DECnet counters. Input packets for "netstat" include * ALL directed, multicast, and error inputs. For DECnet, only * error-free input packets are counted. See the DEUNA User's * Guide for a breakdown of the counters. */ sc->ctrblk.est_bytercvd += len ; if (sc->ctrblk.est_blokrcvd != (unsigned) 0xffffffff) sc->ctrblk.est_blokrcvd++; if( eptr->ether_dhost[0] & 1 ) { sc->ctrblk.est_mbytercvd += len ; if (sc->ctrblk.est_mblokrcvd != (unsigned) 0xffffffff) sc->ctrblk.est_mblokrcvd++; } /* Dispatch this packet */ /* is_ed really is ifp alias arpcom alias ether_driver... */ net_read(&(sc->is_ed), eptr, m, len, (swloop != NULL), (off != 0));}/* * lntint hasn't been called in a while, so restart chip, * and reset timer. */lnwatch(unit)int unit;{ register struct ln_softc *sc = ln_softc[unit]; register struct ifnet *ifp = &sc->is_if; int s; s=splimp(); smp_lock(&sc->lk_ln_softc, LK_RETRY); ifp->if_timer = 0; sc->ln_debug.trfull++; smp_unlock(&sc->lk_ln_softc); lnrestart(ifp); lninit(ifp->if_unit); splx(s);}/* * Allocate a chunk of local RAM buffer. Since we never * give Local RAM buffer memory back, we'll just step up the * byte-count on a per-unit basis. (16 bits on 32 bit boundary) */caddr_tln_alloc16 (sc, size, align) register struct ln_softc *sc; int size; int align;{ register int tmpoff = sc->lrb_offset; register int tmpoff1; /* * Start out on the first "align" boundary */ if (align) { tmpoff1 = svtolance16(sc->ln_lrb) + tmpoff; while ((tmpoff1&((align*2))) && tmpoff < LN_LRB_SIZE) { tmpoff += ((tmpoff1&0x01) ? 3 : 1); tmpoff1 += ((tmpoff1&0x01) ? 3 : 1); } } if ((int)LRBADDR(tmpoff,size) < LN_LRB_SIZE) { sc->lrb_offset = (int)LRBADDR(tmpoff,size); return ((caddr_t)((int)sc->ln_lrb + tmpoff)); } else return (0);}/* * Allocate a chunk of local RAM buffer. Since we never * give Local RAM buffer memory back, we'll just step up the * byte-count on a per-unit basis. (32 bits wide) */caddr_tln_alloc32 (sc, size, align) register struct ln_softc *sc; int size; int align;{ register int tmpoff = sc->lrb_offset; register int tmpoff1 ; /* * Start out on the first "align" boundary */ if (align) { tmpoff1 = svtolance32(sc->ln_lrb) + tmpoff ; while ((tmpoff1&(align)) && tmpoff < LN_LRB_SIZE) { tmpoff++; tmpoff1++ ; } } if ((int)(tmpoff+size) < LN_LRB_SIZE) { sc->lrb_offset = (int)(tmpoff+size); return ((caddr_t)((int)sc->ln_lrb + tmpoff)); } else return (0);}caddr_tln_alloc4x4 (sc, size, align) register struct ln_softc *sc; int size; int align;{ register int tmpoff = sc->lrb_offset; register int tmpoff1 ; /* Alloc routine for buffers only. Each buffer has 4 good words * followed by 4 unused words, then 4 good, etc. To save space, * use the 4 unused words for the next buffer to be alloc'd, thus * they will be alternating. */ if (sc->rring[0] == NULL) /* allocing the 1st one */ align = LN_OCTA_ALIGN; /* * Start out on the first octaword aligned boundary */ if (align) { tmpoff1 = sc->lnsw->ln_svtolance(sc->ln_lrb) +tmpoff ; while ((tmpoff1&(align)) && tmpoff < LN_LRB_SIZE) { tmpoff++; tmpoff1++ ; } } if (((int)sc->ln_lrb + tmpoff) & 0x10) /* 5th bit set */ sc->lrb_offset = (int)(tmpoff+16);/* next time use altrn space */ else if ((int)(tmpoff+(size * 2)) < LN_LRB_SIZE) sc->lrb_offset = (int)(tmpoff + (size * 2) - 16); else return (0); return ((caddr_t)((int)sc->ln_lrb + tmpoff));}/* * Zero "len" bytes of Local RAM buffer */ln_bzero16 (addr, len) register char *addr; register int len;{ register int i; register caddr_t lrbptr = addr; if (len) { if ((u_long)lrbptr & 0x01) { *(u_long *)(lrbptr - 1) &= (u_short)0xff; lrbptr +=3; len--; } for (i = 0; i < (len - 1); i += sizeof(u_short)) { *(u_long *)lrbptr = (u_short)0; lrbptr += sizeof(u_long); } if (i != len) *(u_long *)lrbptr &= (u_short)0xff00; }}/* * Zero "len" bytes of Local RAM buffer */ln_bzero32 (addr, len) register char *addr; register int len;{ if (len) bzero(addr, len);}ln_bzero4x4 (addr, len ) register char *addr; register int len;{ register tmp1; register caddr_t lrbptr = addr; register end4word; int i; /* bzero routine for ring buffers only */ if ((u_long) lrbptr & 0xf) { /* start on a 4 word boundary */ end4word = (0x10 - ((u_long)lrbptr & 0xf)); tmp1 = ((len > end4word) ? end4word : len); bzero(lrbptr, tmp1); len -= tmp1; lrbptr += tmp1; if (((u_long)lrbptr & 0xf) == 0) lrbptr += 0x10; } /* bzero in 4 word boundaries, skipping every 4 words */ tmp1 = (len >> 4); for (i=0; i < tmp1; i++) { bzero(lrbptr,16); lrbptr += 32; } len -= (tmp1 << 4); /* now the left over */ if (len) bzero(lrbptr, len);}/* * Convert a system virtual address to the appropriate addressing * scheme as seen by the LANCE chip for a 32 bit wide buffer. */svtolance32 (virt) caddr_t virt;{ register int off, phy,base ; phy = (int)(svtophy(virt)); off = phy & (LN_LRB_SIZE-1); /* Byte offset from base of LRB */ base = ((phy & ~(LN_LRB_SIZE-1)) & 0xffffff); /* LRB base addr. */ return (off+base);}/* * Convert a system virtual address to the appropriate addressing * scheme as seen by the LANCE chip for a 16 bit wide buffer. */svtolance16 (virt) caddr_t virt;{ register int off, phy, tmp; phy = (int)(svtophy(virt)); off = phy & (LN_LRB_SIZE-1); /* Byte offset from base of LRB */ tmp = off/2; return ((off == tmp*2) ? tmp : tmp+1);}/* * Specialized "bcopy" to move len bytes from * 16-bit wide by 32-bit aligned local RAM buffer. * Loop does up to 32 short-word moves in a single * shot until the buffer is depleted. Off is non-zero * if we wish to begin copying off-many bytes beyond * "from". */caddr_tln_cpyin16(sc,from,to,len,off)struct ln_softc *sc;caddr_t from;caddr_t to;int len, off;{ register caddr_t lrbptr = LRBADDR(from, off); register caddr_t dp = to; register int tmp0, tmp1; tmp0 = (unsigned)len; if (sc->lnsw->ln_dma) /* no read thru caching */ clean_dcache(PHYS_TO_K0(svtophy(lrbptr)),len*2); if ((u_long)lrbptr & 0x01) { /* Start LRB on even short-word boundary */ *dp++ = *lrbptr; lrbptr += 3; tmp0--; } while (tmp0) { switch (tmp1 = (tmp0 >> 1)) { default: case 32: tmp1 = 32; *(u_short *)(dp+62) = *(u_long *)(lrbptr+124); case 31: *(u_short *)(dp+60) = *(u_long *)(lrbptr+120); case 30: *(u_short *)(dp+58) = *(u_long *)(lrbptr+116); case 29: *(u_short *)(dp+56) = *(u_long
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -