📄 if_en.c
字号:
* backed off 16 times, and give up. */ if (es->es_mask == 0) { printf("en%d: send error\n", unit); enxint(unit); return; } /* * Another backoff. Restart with delay based on n low bits * of the interval timer. */ es->es_mask <<= 1; es->es_delay = mfpr(ICR) &~ es->es_mask; enstart(unit);}#ifdef notdefstruct sockproto enproto = { AF_ETHERLINK };struct sockaddr_en endst = { sizeof(endst), AF_ETHERLINK };struct sockaddr_en ensrc = { sizeof(ensrc), AF_ETHERLINK };#endif/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Otherwise purge input buffered data path and 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. */enrint(unit) int unit;{ register struct en_softc *es = &en_softc[unit]; struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; register struct en_header *en; struct mbuf *m; int len; short resid; register struct ifqueue *inq; int off, s; es->es_if.if_ipackets++; /* * Purge BDP; drop if input error indicated. */ if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); if (addr->en_istat&EN_IERROR) { es->es_if.if_ierrors++; goto setup; } /* * Calculate input data length. * Get pointer to ethernet header (in input buffer). * Deal with trailer protocol: if type is PUP trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ resid = addr->en_iwc; if (resid) resid |= 0176000; len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; len -= sizeof (struct en_header); if (len > ENMRU) goto setup; /* sanity */ en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); en->en_type = ntohs(en->en_type);#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) if (en->en_type >= ENTYPE_TRAIL && en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { off = (en->en_type - ENTYPE_TRAIL) * 512; if (off > ENMTU) goto setup; /* sanity */ en->en_type = ntohs(*endataaddr(en, off, u_short *)); resid = ntohs(*(endataaddr(en, off+2, u_short *))); if (off + resid > len) goto setup; /* sanity */ len = off + resid; } else off = 0; if (len == 0) goto setup;#ifdef ENF_SWABIPS if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);#endif /* * Pull packet off interface. Off is nonzero if packet * has trailing header; if_rubaget 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(&es->es_ifuba, len, off, &es->es_if); if (m == 0) goto setup; switch (en->en_type) {#ifdef INET case ENTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break;#endif#ifdef PUP case ENTYPE_PUP: rpup_input(m); goto setup;#endif#ifdef NS case ETHERTYPE_NS: if (es->es_nsactive) { schednetisr(NETISR_NS); inq = &nsintrq; } else { m_freem(m); goto setup; } break;#endif default:#ifdef notdef enproto.sp_protocol = en->en_type; endst.sen_host = en->en_dhost; endst.sen_net = ensrc.sen_net = es->es_if.if_net; ensrc.sen_host = en->en_shost; raw_input(m, &enproto, (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);#else m_freem(m);#endif goto setup; } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); splx(s);setup: /* * Reset for next packet. */ addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; addr->en_istat = EN_IEN|EN_GO;}/* * 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. */oldenoutput(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ int type, dest, s, error; register struct mbuf *m = m0; register struct en_header *en; register int off; 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: { struct in_addr in; in = ((struct sockaddr_in *)dst)->sin_addr; if (in_broadcast(in)) dest = EN_BROADCAST; else dest = in_lnaof(in); } if (dest >= 0x100) { error = EPERM; /* ??? */ goto bad; } off = m->m_pkthdr.len - m->m_len; /* need per host negotiation */ if ((ifp->if_flags & IFF_NOTRAILERS) == 0) if (off > 0 && (off & 0x1ff) == 0 && (m->m_flags & M_EXT) == 0 && m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { type = ENTYPE_TRAIL + (off>>9); m->m_data -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); goto gottrailertype; } type = ENTYPE_IP; off = 0; goto gottype;#endif#ifdef NS case AF_NS: { u_char *up; type = ETHERTYPE_NS; up = ((struct sockaddr_ns *)dst)->sns_addr.x_host.c_host; if (*up & 1) dest = EN_BROADCAST; else dest = up[5]; off = 0; goto gottype; }#endif#ifdef PUP case AF_PUP: dest = ((struct sockaddr_pup *)dst)->spup_host; type = ENTYPE_PUP; off = 0; goto gottype;#endif#ifdef notdef case AF_ETHERLINK: goto gotheader;#endif default: printf("en%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. */ M_PREPEND(m, sizeof (struct en_header), M_DONTWAIT); if (m == NULL) return (ENOBUFS); en = mtod(m, struct en_header *); /* add en_shost later */ en->en_dhost = dest; en->en_type = htons((u_short)type);#ifdef notdefgotheader:#endif /* * 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 (en_softc[ifp->if_unit].es_oactive == 0) enstart(ifp->if_unit); splx(s); return (0);qfull: m0 = m; splx(s);bad: m_freem(m0); return (error);}/* * Process an ioctl request. */enioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct en_softc *es = ((struct en_softc *)ifp); struct ifaddr *ifa = (struct ifaddr *) data; int s = splimp(), error = 0; struct endevice *enaddr; switch (cmd) { case SIOCSIFADDR: enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; es->es_host = (~enaddr->en_addr) & 0xff; /* * Attempt to check agreement of protocol address * and board address. */ switch (ifa->ifa_addr->sa_family) { case AF_INET: if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) return (EADDRNOTAVAIL); break;#ifdef NS case AF_NS: if (IA_SNS(ifa)->sns_addr.x_host.c_host[5] != es->es_host) return (EADDRNOTAVAIL); es->es_nsactive = 1; break;#endif } ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) eninit(ifp->if_unit); break; default: error = EINVAL; break; } splx(s); return (error);}#ifdef ENF_SWABIPS/* * Swab bytes * Jeffrey Mogul, Stanford */enswab(from, to, n) register unsigned char *from, *to; register int n;{ register unsigned long temp; if ((n <= 0) || (n > 0xFFFF)) { printf("enswab: bad len %d\n", n); return; } n >>= 1; n++;#define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} /* round to multiple of 8 */ while ((--n) & 07) STEP; n >>= 3; while (--n >= 0) { STEP; STEP; STEP; STEP; STEP; STEP; STEP; STEP; }}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -