📄 pfilt.c
字号:
ticks = ticks % hz; rtv.tv_usec = ticks * tick; bcopy((caddr_t)&rtv, addr, sizeof rtv); } endcase /* * Change the interface associated with a minor device */ case EIOCSETIF: { struct ifreq ifr; register struct ifnet *oldifp = enet_info[ENUNIT(dev)].ifp; register struct ifnet *newifp; register struct enState *newStatep = (struct enState *)0; int unit; struct ifnet *ifunit(); static struct ifnet *genericUnit(); bcopy(addr, (caddr_t)&ifr, sizeof(ifr)); if ((newifp = genericUnit(ifr.ifr_name)) == (struct ifnet *)0) if ((newifp = ifunit(ifr.ifr_name)) == (struct ifnet *)0) return(EINVAL); if (newifp == oldifp) /* no change */ return(0); /* find enState pointer for new interface */ for (unit = 0; unit < enUnits; unit++) { if (enet_info[unit].ifp == newifp) { newStatep = enStatePs[unit]; break; } } if (newStatep == (struct enState *)0) return(EINVAL); /* interface not known */ ipl = splenet(); smp_lock(&lk_pfilt, LK_RETRY); /* remove this from the old enState struct */ pfiltdequeue((struct Queue *)d->enOD_Link.B, dummy); enCurOpens--; if (d->enOD_Flag & ENPROMISC) decPromiscCount(enStatep, dev); if (d->enOD_Flag & ENCOPYALL) decCopyAllCount(enStatep, dev); enUnitMap[ENINDEX(dev)] = unit; /* change unit map */ /* add this to the new enState struct */ PfiltInsertDescriptor(&(newStatep->ens_Desq), d); PfiltFlushWaitQueue(d); if (d->enOD_Flag & ENPROMISC) incPromiscCount(newStatep, dev); if (d->enOD_Flag & ENCOPYALL) incCopyAllCount(newStatep, dev); smp_unlock(&lk_pfilt); splx(ipl); } endcase; default: { bad: return(EINVAL); } } return(0);} /**************************************************************** * * * Support for select() system call * * * * Other hooks in: * * PfiltInitDescriptor() * * PfiltInputDone() * * PfiltTimeout() * ****************************************************************//* * inspired by the code in tty.c for the same purpose. *//* * Pfilt_select - returns true iff the specific operation * will not block indefinitely. Otherwise, return * false but make a note that a selwakeup() must be done. */Pfilt_select(dev, rw)register dev_t dev;int rw;{ register struct enOpenDescriptor *d; register struct enWaitQueue *wq; register int ipl; register int avail; switch (rw) { case FREAD: /* * an imitation of the FIONREAD ioctl code */ d = (enAllDescriptors[ENINDEX(dev)]); ipl = splenet(); smp_lock(&lk_pfilt, LK_RETRY); wq = &(d->enOD_Waiting); if (wq->enWQ_NumQueued) avail = 1; /* at least one packet queued */ else { avail = 0; /* sorry, nothing queued now */ /* * If there's already a select() waiting on this * minor device then this is a collision. * [This shouldn't happen because enet minors * really should not be shared, but if a process * forks while one of these is open, it is possible * that both processes could select() us.] */ if (d->enOD_SelProc && d->enOD_SelProc->p_wchan == (caddr_t)&selwait) d->enOD_SelColl = 1; else d->enOD_SelProc = u.u_procp; } smp_unlock(&lk_pfilt); splx(ipl); return(avail); case FWRITE: /* * since the queueing for output is shared not just with * the other enet devices but also with the IP system, * we can't predict what would happen on a subsequent * write. However, since we presume that all writes * complete eventually, and probably fairly fast, we * pretend that select() is true. */ return(1); default: /* hmmm. */ return(1); /* don't block in select() */ }}Pfilt_wakeup(d)register struct enOpenDescriptor *d;{ if (d->enOD_SelProc) { selwakeup(d->enOD_SelProc, d->enOD_SelColl); d->enOD_SelColl = 0; d->enOD_SelProc = 0; }}/* * pfilt_filter - incoming linkage from if_XXXXX.c */struct mbuf *PfiltInputDone();struct mbuf *pfilt_filter(edp, m, eptr, istrailer)struct ether_driver *edp;register struct mbuf *m;struct ether_header *eptr;int istrailer;{ register struct enPacket *p; struct mbuf *m0; int s; int HowReceived = 0; short d_addr[4]; register short *sb, *dap; struct protosw *pr; int mustcopy = 0; int pfcopyall = (edp->ess_if.if_flags & IFF_PFCOPYALL); register struct enpextent *exp; register int offset; register int extents_left; struct enpextent map[MAX_EXTENTS];#ifdef SELF_PROF struct timeval starttv, endtv; if (enSelfProf) microtime(&starttv);#endif SELF_PROF#if DEBUG Pfiltprintf(ENDBG_TRACE)("pfilt_filter(%d):\n", en);#endif /* Copy the destination address into main memory */ sb = (short *)eptr->ether_dhost; dap = d_addr; dap[0] = sb[0]; dap[1] = sb[1]; dap[2] = sb[2]; /* Was it a MULTICAST (or BROADCAST) packet? */ if (eptr->ether_dhost[0] & 1) { HowReceived = ENSF_MULTICAST; /* set MULTICAST */ /* * Was it a broadcast packet? */ if ((*((long *)dap) == 0xFFFFFFFF) && (*((short *)&(dap[2])) == (short)0xFFFF)) { HowReceived = ENSF_BROADCAST; /* set BROADCAST */ mustcopy = 1; /* save a copy of the packet */ } else { /* * else we received a MULTICAST packet. * If other protocols might be interested * in the packet, save a copy of it. */ pr = (struct protosw *) iftype_to_proto(eptr->ether_type); if (pr && pr->pr_ifinput) { mustcopy = 1; } } } else { /* else not MULTICAST or BROADCAST packet, check if it's ours */ if (edp->ess_if.if_flags & IFF_PROMISC) { /* * All promiscuously received packets go to the filter * This includes COPYALL packets that we sent since * they appear to belong to someone else. */ sb = (short *)edp->ess_addr; /* our address */ if ((*((long *)dap) != *((long *)sb)) || (dap[2] != sb[2])) { HowReceived = ENSF_PROMISC; } else { /* * We are in PROMISC mode and this packet was * addressed directly to us; need to make a copy * if IFF_COPYALL mode is set. */ if (pfcopyall > 1) { mustcopy = 1; } } } else { /* else not in PROMISC mode, check to see if our own * output packet was looped back (ie. COPYALL mode is set). * If so, insure we hand it to the packetfilter only. * If a packet reaches here, it must have been either: * - directed at us, or * - a packet we sent which was looped back */ if (pfcopyall > 1) { sb = (short *)edp->ess_addr; /* our address */ if ((*((long *)dap) != *((long *)sb)) || (dap[2] != sb[2])) { /* The destination address does not match our own, * so we let the packetfilter eat it. * This works because mustcopy==0 and because * we label the packet as PROMISC. */ HowReceived = ENSF_PROMISC; } else { /* else packet was directed at us (it came in normally) * must save a copy for the protocols */ mustcopy = 1; } } } }/* filter: unused */#ifdef DEBUG_ER if (er_debug) { int cprintf(), mprintf(); /* er_debug=1 print to console (cprintf) * er_debug=2 print to error log (mprintf) */ (er_debug == 2 ? mprintf : cprintf)("%02x-%02x-%02x-%02x-%02x-%02x -> %02x-%02x-%02x-%02x-%02x-%02x %04x %x\n", eptr->ether_shost[0], eptr->ether_shost[1], eptr->ether_shost[2], eptr->ether_shost[3], eptr->ether_shost[4], eptr->ether_shost[5], eptr->ether_dhost[0], eptr->ether_dhost[1], eptr->ether_dhost[2], eptr->ether_dhost[3], eptr->ether_dhost[4], eptr->ether_dhost[5], eptr->ether_type, HowReceived); }#endif DEBUG_ER /* * If we don't need to copy the packet (and we aren't * promiscuous), then we can return here and now and * not bother anymore with the packet filter. */ if ((HowReceived != ENSF_PROMISC) && (mustcopy == 0)) return m; /* * If there are no active filters, just return. * This can happen if we are in PROMISC mode * or COPYALL mode, but not actually doing any filtering. */ if (pfactive == 0) { if (mustcopy) { return m; } else { m_freem(m); return 0; } } /* * We need local net header after all. */ MGET(m0, M_DONTWAIT, MT_DATA); if (m0 == 0) { /* out of mbufs? */ if (mustcopy) { return m; } else { m_freem(m); return (struct mbuf *) 0; } } /* * If we must copy the mbuf, do it now. If it * fails, screw the packet filter and process it normally. * If we don't have to copy, just append the mbuf. */ if (mustcopy) { m0->m_next = m_copy(m, 0, M_COPYALL); /* m_copy returns NULL if it fails */ if (m0->m_next == NULL) { m_free(m0); return m; } } else { m0->m_next = m; } /* * Copy the ether header and swap the protocol * type in "wire" format. */ *(mtod(m0, struct ether_header *)) = *eptr; eptr = mtod(m0, struct ether_header *); eptr->ether_type = htons((u_short)eptr->ether_type); m0->m_len = sizeof(struct ether_header); s = splenet(); smp_lock(&lk_pfilt, LK_RETRY); p = PfiltAllocatePacket(); /* panics if not possible */ p->enP_ByteCount = m_length(m0); microtime(&(p->enP_Stamp.ens_tstamp)); p->enP_mbuf = m0; p->enP_Stamp.ens_flags = HowReceived; p->enP_Stamp.ens_ifoverflows = edp->ess_missed; if (istrailer) { /* was trailer encapsulation */ p->enP_ByteCount -= 2 * sizeof(u_short); /* we've dropped trailer type & length */ p->enP_Stamp.ens_flags |= ENSF_TRAILER; } /* Build a map from packet byte offsets to mbufs */ exp = map; /* ASSUMPTION: m is non-null upon entry to this procedure */ exp->data = mtod(m0, char *); exp->offset = 0; offset = m0->m_len; exp->afterEnd = offset;#if INNERDEBUG Pfiltprintf(ENDBG_TRACE)("[o%d: aE:%d]",exp->offset,exp->afterEnd);#endif exp++; extents_left = (MAX_EXTENTS - 2); /* 1 just used, 1 left for sentinel */ while ((m0 = m0->m_next) && (--extents_left >= 0)) { exp->data = mtod(m0, char *); exp->offset = offset; offset += m0->m_len; exp->afterEnd = offset;#if INNERDEBUG Pfiltprintf(ENDBG_TRACE)("[o%d: aE:%d]",exp->offset,exp->afterEnd);#endif exp++; }#if INNERDEBUG Pfiltprintf(ENDBG_TRACE)("\n");#endif /* The last extent always has data == 0; we reserved one for this */ exp->afterEnd = MAX_OFFSET; exp->data = (char *)0; m0 = PfiltInputDone(enStatePs[edp->ess_enetunit], p, map); if (m0) m_freem(m0);#ifdef SELF_PROF if (enSelfProf) { microtime(&endtv); enPerPktProf.tv_sec += (endtv.tv_sec - starttv.tv_sec); enPerPktProf.tv_usec += (endtv.tv_usec - starttv.tv_usec); enPktCount++; }#endif SELF_PROF smp_unlock(&lk_pfilt); splx(s); if (mustcopy) return m; else return 0;}/* * PfiltInputDone - process correctly received packet * SMP: assumes lock held coming in */struct mbuf *PfiltInputDone(enStatep, p, exp)register struct enState *enStatep;register struct enPacket *p;struct enpextent *exp;{ register struct enOpenDescriptor *d; int queued = 0; int drops = 0; register unsigned long rcount; register struct enOpenDescriptor *prevd; int Exclusive; struct mbuf *notwanted = 0;#ifdef SELF_PROF struct timeval starttv, endtv; boolean accept;#endif SELF_PROF if (smp_debug) { if (!(smp_owner(&lk_pfilt))) panic("PfiltInputDone: not lock owner"); }#if INNERDEBUG Pfiltprintf(ENDBG_TRACE)("PfiltInputDone(%x): %x\n", enStatep, p);#endif enRmissed = p->enP_Stamp.ens_ifoverflows; forAllOpenDescriptors(d) { /* restrict access to promiscuously received packets */ if ( (p->enP_Stamp.ens_flags & ENSF_PROMISC) && ((d->enOD_Flag & ENPROMISC) == 0) ) continue;#ifdef SELF_PROF /* null filters always accept all packets */ if (d->enOD_OpenFilter.enf_FilterLen == 0) accept = true; else if (!enSelfProf) { accept = PfiltDoFilter(p, d, exp); } else { microtime(&starttv); accept = PfiltDoFilter(p, d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -