📄 if_ec.c
字号:
if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } switch (ec->ether_type) {#ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: arpinput(&es->es_ac, m); goto setup;#endif#ifdef NS case ETHERTYPE_NS: schednetisr(NETISR_NS); inq = &nsintrq; break;#endif default: /* * see if other protocol families defined * and call protocol specific routines. * If no other protocols defined then dump message. */ if ((pr=iftype_to_proto(ec->ether_type)) && pr->pr_ifinput) { if ((m = (struct mbuf *)(*pr->pr_ifinput)(m, &es->es_if, &inq, ec)) == 0) return; } else { if (es->es_unrecog != 0xffff) es->es_unrecog++; m_freem(m); goto setup; } } if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); goto setup; } IF_ENQUEUEIF(inq, m, &es->es_if);setup: /* * Reset for next packet. */ addr->ec_rcr = EC_READ|EC_RCLR|rbuf;}/* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. * If destination is this address or broadcast, send packet to * loop device to kludge around the fact that 3com interfaces can't * talk to themselves. */ecoutput(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ int type, s, error; u_char edst[6]; struct in_addr idst; register struct ec_softc *es = &ec_softc[ifp->if_unit]; register struct mbuf *m = m0; register struct ether_header *ec; register int off; struct mbuf *mcopy = (struct mbuf *)0; int usetrailers; struct protosw *pr; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { error = ENETDOWN; goto bad; } switch (dst->sa_family) {#ifdef INET case AF_INET: idst = ((struct sockaddr_in *)dst)->sin_addr; if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) return (0); /* if not yet resolved */ if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, sizeof(edst))) mcopy = m_copy(m, 0, (int)M_COPYALL); off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; /* need per host negotiation */ if (usetrailers && off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2 * sizeof (u_short)) { type = ETHERTYPE_TRAIL + (off>>9); m->m_off -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); *mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP); *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); goto gottrailertype; } type = ETHERTYPE_IP; off = 0; goto gottype;#endif#ifdef NS case AF_NS: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), (caddr_t)edst, sizeof (edst)); if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))) { mcopy = m_copy(m, 0, (int)M_COPYALL); } else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) { return(looutput(&loif, m, dst)); } type = ETHERTYPE_NS; off = 0; goto gottype;#endif case AF_UNSPEC: ec = (struct ether_header *)dst->sa_data; bcopy((caddr_t)ec->ether_dhost, (caddr_t)edst, sizeof (edst)); type = ec->ether_type; goto gottype; default: if (pr=iffamily_to_proto(dst->sa_family)) { (*pr->pr_ifoutput)(ifp, m0, dst, &type, (char *)edst); goto gottype; } else { printf("ec%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; } }gottrailertype: /* * Packet to be sent as trailer: move first packet * (control information) to end of chain. */ while (m->m_next) m = m->m_next; m->m_next = m0; m = m0->m_next; m0->m_next = 0; m0 = m;gottype: /* * Add local net header. If no space in first mbuf, * allocate another. */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct ether_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_DATA); if (m == 0) { error = ENOBUFS; goto bad; } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct ether_header); } else { m->m_off -= sizeof (struct ether_header); m->m_len += sizeof (struct ether_header); } ec = mtod(m, struct ether_header *); ec->ether_type = htons((u_short)type); bcopy((caddr_t)edst, (caddr_t)ec->ether_dhost, sizeof (edst)); bcopy((caddr_t)es->es_addr, (caddr_t)ec->ether_shost, sizeof(ec->ether_shost)); /* * Queue message on interface, and start output if interface * not yet active. */ s = splimp(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); error = ENOBUFS; goto qfull; } IF_ENQUEUE(&ifp->if_snd, m); if (es->es_oactive == 0) ecstart(ifp->if_unit); splx(s); return (mcopy ? looutput(&loif, mcopy, dst) : 0);qfull: m0 = m; splx(s);bad: m_freem(m0); if (mcopy) m_freem(mcopy); return (error);}/* * 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 ) u_char *ecbuf; int totlen, off0;{ register struct mbuf *m; struct mbuf *top = 0, **mp = ⊤ register int off = off0, len; u_char *cp; cp = ecbuf + ECRDOFF + sizeof (struct ether_header); while (totlen > 0) { register int words; u_char *mcp; MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) goto bad; if (off) { len = totlen - off; cp = ecbuf + ECRDOFF + sizeof (struct ether_header) + off; } else len = totlen; if (len >= CLBYTES) { struct mbuf *p; MCLGET(m,p); if (p != 0) { m->m_len = len = CLBYTES; } else { m->m_len = len = MIN(MLEN, len); m->m_off = MMINOFF; } } else { m->m_len = len = MIN(MLEN, len); m->m_off = MMINOFF; } 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; if (off == 0) { totlen -= len; continue; } off += len; if (off == totlen) { cp = ecbuf + ECRDOFF + sizeof (struct ether_header); off = 0; totlen = off0; } } 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; struct protosw *pr; 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: if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) { error = (*pr->pr_ifioctl)(ifp, cmd, data); } 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 + -