📄 if_il.c
字号:
register struct il_rheader *il; struct mbuf *m; struct protosw *pr; int len, off, resid, s; struct ifqueue *inq; is->is_if.if_ipackets++; if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp, is->is_ifuba.ifu_uban); il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); len = il->ilr_length - sizeof(struct il_rheader); if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || len > ETHERMTU) { is->is_if.if_ierrors++;#ifdef notdef if (is->is_if.if_ierrors % 100 == 0) printf("il%d: += 100 input errors\n", unit);#endif goto setup; } /* * 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. */ il->ilr_type = ntohs((u_short)il->ilr_type);#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) if (il->ilr_type >= ETHERTYPE_TRAIL && il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) goto setup; /* sanity */ il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); resid = ntohs(*(ildataaddr(il, 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; ilget 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 = if_rubaget(&is->is_ifuba, len, off); if (m == 0) goto setup; if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } switch (il->ilr_type) {#ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: arpinput(&is->is_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(il->ilr_type)) && pr->pr_ifinput) { if ((m = (struct mbuf *)(*pr->pr_ifinput)(m, &is->is_if, &inq, il)) == 0) return; } else { if (is->is_unrecog != 0xffff) is->is_unrecog++; m_freem(m); goto setup; } break; } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUEIF(inq, m, &is->is_if); splx(s);setup: /* * Reset for next packet if possible. * If waiting for transmit command completion, set flag * and wait until command completes. */ if (is->is_flags & ILF_OACTIVE) { is->is_flags |= ILF_RCVPENDING; return; } addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; s = splhigh(); while ((addr->il_csr & IL_CDONE) == 0) ; splx(s);}/* * 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. */iloutput(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 il_softc *is = &il_softc[ifp->if_unit]; register struct mbuf *m = m0; register struct ether_header *il; register int off; struct protosw *pr; int usetrailers; 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(&is->is_ac, m, &idst, edst, &usetrailers)) return (0); /* if not yet resolved */ off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 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 *) = htons((u_short)ETHERTYPE_IP); *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); goto gottrailertype; } type = ETHERTYPE_IP; off = 0; goto gottype;#endif#ifdef NS case AF_NS: type = ETHERTYPE_NS; bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), (caddr_t)edst, sizeof (edst)); off = 0; goto gottype;#endif case AF_UNSPEC: il = (struct ether_header *)dst->sa_data; bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst)); type = il->ether_type; goto gottype; default: /* * try to find other address families and call protocol * specific output routine. */ if (pr=iffamily_to_proto(dst->sa_family)) { (*pr->pr_ifoutput)(ifp, m0, dst, &type, (char *)edst); goto gottype; } else { printf("il%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); } il = mtod(m, struct ether_header *); il->ether_type = htons((u_short)type); bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst)); bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost, sizeof(il->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); splx(s); m_freem(m); return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); if ((is->is_flags & ILF_OACTIVE) == 0) ilstart(ifp->if_unit); splx(s); return (0);bad: m_freem(m0); return (error);}/* * Watchdog routine, request statistics from board. */ilwatch(unit) int unit;{ register struct il_softc *is = &il_softc[unit]; register struct ifnet *ifp = &is->is_if; int s; if (is->is_flags & ILF_STATPENDING) { ifp->if_timer = is->is_scaninterval; return; } s = splimp(); is->is_flags |= ILF_STATPENDING; if ((is->is_flags & ILF_OACTIVE) == 0) ilstart(ifp->if_unit); splx(s); ifp->if_timer = is->is_scaninterval;}/* * Total up the on-board statistics. */iltotal(is) register struct il_softc *is;{ register u_short *interval, *sum, *end; interval = &is->is_stats.ils_frames; sum = &is->is_sum.ils_frames; end = is->is_sum.ils_fill2; while (sum < end) *sum++ += *interval++; is->is_if.if_collisions = is->is_sum.ils_collis; if ((is->is_flags & ILF_SETADDR) && (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, sizeof (is->is_addr)) != 0)) { printf("il%d: physaddr reverted\n", is->is_if.if_unit); is->is_flags &= ~ILF_RUNNING; ilinit(is->is_if.if_unit); }}/* * Process an ioctl request. */ilioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct il_softc *is = &il_softc[ifp->if_unit]; struct protosw *pr; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ilinit(ifp->if_unit); switch (ifa->ifa_addr.sa_family) {#ifdef INET case AF_INET: ((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 *) (il_softc[ifp->if_unit].is_addr); } else { il_setaddr(ina->x_host.c_host, ifp->if_unit); return (0); } 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 ((ifp->if_flags & IFF_UP) == 0 && is->is_flags & ILF_RUNNING) { ((struct ildevice *) (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; is->is_flags &= ~ILF_RUNNING; } else if (ifp->if_flags & IFF_UP && (is->is_flags & ILF_RUNNING) == 0) ilinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */il_setaddr(physaddr, unit)u_char *physaddr;int unit;{ register struct il_softc *is = &il_softc[unit]; if (! (is->is_flags & ILF_RUNNING)) return; bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); is->is_flags &= ~ILF_RUNNING; is->is_flags |= ILF_SETADDR; ilinit(unit);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -