📄 if_ec.c
字号:
/* * Reset interface, then requeue rcv buffers. * Some incoming packets may be lost, but that * can't be helped. */ addr->ec_xcr = EC_UECLR;#ifdef MULTI if (es->es_if.if_flags & IFF_PROMISC) start_read = EC_PROMISC; else if (es->es_if.if_flags & IFF_MULTI) start_read = EC_MULTI; else#endif MULTI start_read = EC_READ; for (i=ECRHBF; i>=ECRLBF; i--) addr->ec_rcr = start_read|i; /* * Reset and transmit next packet (if any). */ es->es_if.if_flags &= ~IFF_OACTIVE; es->es_mask = ~0; if (es->es_if.if_snd.ifq_head) (void) ecstart(&es->es_if); return; } /* * Do exponential backoff. Compute delay based on low bits * of the interval timer (1 bit for each transmission attempt, * but at most 5 bits). Then delay for that number of * slot times. A slot time is 51.2 microseconds (rounded to 51). * This does not take into account the time already used to * process the interrupt. */ es->es_mask <<= 1; delay = mfpr(ICR) & 0x1f &~ es->es_mask; DELAY(delay * 51); /* * Clear the controller's collision flag, thus enabling retransmit. */ addr->ec_xcr = EC_CLEAR;}/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Otherwise 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. */ecrint(unit) int unit;{ struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; while (addr->ec_rcr & EC_RDONE) ecread(unit);}ecread(unit) int unit;{ register struct ec_softc *es = &ec_softc[unit]; struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; register struct ether_header *ec; struct mbuf *m; int len, off, resid, ecoff, rbuf; register struct ifqueue *inq; u_short start_read; u_char *ecbuf; es->es_if.if_ipackets++; rbuf = addr->ec_rcr & EC_RBN; if (rbuf < ECRLBF || rbuf > ECRHBF) panic("ecrint"); ecbuf = es->es_buf[rbuf]; ecoff = *(short *)ecbuf; if (ecoff <= ECRDOFF || ecoff > 2046) { es->es_if.if_ierrors++;#ifdef notdef if (es->es_if.if_ierrors % 100 == 0) printf("ec%d: += 100 input errors\n", unit);#endif goto setup; } /* * Get input data length. * Get pointer to ethernet header (in input buffer). * 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. */ len = ecoff - ECRDOFF - sizeof (struct ether_header); ec = (struct ether_header *)(ecbuf + ECRDOFF); ec->ether_type = ntohs((u_short)ec->ether_type);#define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) if (ec->ether_type >= ETHERTYPE_TRAIL && ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) goto setup; /* sanity */ ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); resid = ntohs(*(ecdataaddr(ec, 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; ecget 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 = ecget(ecbuf, len, off, &es->es_if); if (m) ether_input(&es->es_if, ec, m); /* * Reset for next packet. */setup:#ifdef MULTI if (es->es_if.if_flags & IFF_PROMISC) start_read = EC_PROMISC; else if (es->es_if.if_flags & IFF_MULTI) start_read = EC_MULTI; else#endif MULTI start_read = EC_READ; addr->ec_rcr = start_read|EC_RCLR|rbuf;}/* * Routine to copy from mbuf chain to transmit * buffer in UNIBUS memory. * If packet size is less than the minimum legal size, * the buffer is expanded. We probably should zero out the extra * bytes for security, but that would slow things down. */ecput(ecbuf, m) u_char *ecbuf; struct mbuf *m;{ register struct mbuf *mp; register int off; u_char *bp; for (off = 2048, mp = m; mp; mp = mp->m_next) off -= mp->m_len; if (2048 - off < ETHERMIN + sizeof (struct ether_header)) off = 2048 - ETHERMIN - sizeof (struct ether_header); *(u_short *)ecbuf = off; bp = (u_char *)(ecbuf + off); for (mp = m; mp; mp = mp->m_next) { register unsigned len = mp->m_len; u_char *mcp; if (len == 0) continue; mcp = mtod(mp, u_char *); if ((unsigned)bp & 01) { *bp++ = *mcp++; len--; } if (off = (len >> 1)) { register u_short *to, *from; to = (u_short *)bp; from = (u_short *)mcp; do *to++ = *from++; while (--off > 0); bp = (u_char *)to, mcp = (u_char *)from; } if (len & 01) *bp++ = *mcp++; } m_freem(m);}/* * Routine to copy from UNIBUS memory into mbufs. * Similar in spirit to if_rubaget. * * Warning: This makes the fairly safe assumption that * mbufs have even lengths. */struct mbuf *ecget(ecbuf, totlen, off0, ifp) u_char *ecbuf; int totlen, off0; struct ifnet *ifp;{ register struct mbuf *m; struct mbuf *top = 0, **mp = ⊤ register int off = off0, len; u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header)); u_char *packet_end = cp + totlen; if (off) { off += 2 * sizeof(u_short); totlen -= 2 *sizeof(u_short); cp += off; } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) return (0); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = totlen; m->m_len = MHLEN; while (totlen > 0) { register int words; u_char *mcp; if (top) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return (0); } m->m_len = MLEN; } len = min(totlen, (packet_end - cp)); if (len >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) m->m_len = len = min(len, MCLBYTES); else len = m->m_len; } else { /* * Place initial small packet/header at end of mbuf. */ if (len < m->m_len) { if (top == 0 && len + max_linkhdr <= m->m_len) m->m_data += max_linkhdr; m->m_len = len; } else len = m->m_len; } mcp = mtod(m, u_char *); if (words = (len >> 1)) { register u_short *to, *from; to = (u_short *)mcp; from = (u_short *)cp; do *to++ = *from++; while (--words > 0); mcp = (u_char *)to; cp = (u_char *)from; } if (len & 01) *mcp++ = *cp++; *mp = m; mp = &m->m_next; totlen -= len; if (cp == packet_end) cp = ecbuf; } return (top);bad: m_freem(top); return (0);}/* * Process an ioctl request. */ecioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; struct ec_softc *es = &ec_softc[ifp->if_unit]; struct ecdevice *addr; int s = splimp(), error = 0; addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ecinit(ifp->if_unit); /* before arpwhohas */ ((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 *)(es->es_addr); else { /* * The manual says we can't change the address * while the receiver is armed, * so reset everything */ ifp->if_flags &= ~IFF_RUNNING; bcopy((caddr_t)ina->x_host.c_host, (caddr_t)es->es_addr, sizeof(es->es_addr)); } ecinit(ifp->if_unit); /* does ec_setaddr() */ break; }#endif default: ecinit(ifp->if_unit); break; } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { addr->ec_xcr = EC_UECLR; ifp->if_flags &= ~IFF_RUNNING; } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) ecinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}ec_setaddr(physaddr,unit) u_char *physaddr; int unit;{ struct ec_softc *es = &ec_softc[unit]; struct uba_device *ui = ecinfo[unit]; register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; register char nibble; register int i, j; /* * Use the ethernet address supplied * Note that we do a UECLR here, so the receive buffers * must be requeued. */ #ifdef DEBUG printf("ec_setaddr: setting address for unit %d = %s", unit, ether_sprintf(physaddr));#endif addr->ec_xcr = EC_UECLR; addr->ec_rcr = 0; /* load requested address */ for (i = 0; i < 6; i++) { /* 6 bytes of address */ es->es_addr[i] = physaddr[i]; nibble = physaddr[i] & 0xf; /* lower nibble */ addr->ec_rcr = (nibble << 8); addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ addr->ec_rcr = (nibble << 8); for (j=0; j < 4; j++) { addr->ec_rcr = 0; addr->ec_rcr = EC_ASTEP; /* step counter */ addr->ec_rcr = 0; } nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ addr->ec_rcr = (nibble << 8); addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ addr->ec_rcr = (nibble << 8); for (j=0; j < 4; j++) { addr->ec_rcr = 0; addr->ec_rcr = EC_ASTEP; /* step counter */ addr->ec_rcr = 0; } }#ifdef DEBUG /* * Read the ethernet address off the board, one nibble at a time. */ addr->ec_xcr = EC_UECLR; addr->ec_rcr = 0; /* read RAM */ cp = es->es_addr;#undef NEXTBIT#define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 for (i=0; i < sizeof (es->es_addr); i++) { *cp = 0; for (j=0; j<=4; j+=4) { *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; } cp++; } printf("ec_setaddr: RAM address for unit %d = %s", unit, ether_sprintf(physaddr));#endif}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -