📄 pfilt.c
字号:
}}/* * Pfilt_ioctl - ether net control * * EIOCGETP - get ethernet parameters * EIOCSETP - set ethernet read timeout * EIOCSETF - set ethernet read filter * EIOCENBS - enable signal when read packet available * EIOCINHS - inhibit signal when read packet available * FIONREAD - check for read packet available * EIOCSETW - set maximum read packet waiting queue length * EIOCFLUSH - flush read packet waiting queue * EIOCMBIS - set mode bits * EIOCMBIC - clear mode bits * EICODEVP - get device parameters * EIOCMFREE - number of free minors * EIOCIFNAME - get name of interface for this minor * EIOCTRUNCATE - set maximum number of bytes of packet to be returned * EIOCALLOWPROMISC - allows non-super-users to set IFF_PROMISC * EIOCALLOWCOPYALL - allows non-super-users to set IFF_PFCOPYALL * EIOCMAXBACKLOG - sets non-super-user's maximum backlog * EIOCSRTIMEOUT - set read timeout * EIOCGRTIMEOUT - get read timeout * EIOCSETIF - set interface for this minor *//* ARGSUSED */Pfilt_ioctl(dev, cmd, addr, flag)caddr_t addr;dev_t flag;{ register struct enState *enStatep = enStatePs[ENUNIT(dev)]; register struct enOpenDescriptor * d = enAllDescriptors[ENINDEX(dev)]; struct enPacket *dummy; /* a dummy pointer - used only for consistency * in the macro pfiltdequeue */ int ipl;#if DEBUG Pfiltprintf(ENDBG_TRACE) ("Pfilt_ioctl(%x, %x, %x, %x):\n", dev, cmd, addr, flag);#endif switch (cmd) { case EIOCGETP: { struct eniocb t; if (suser()) t.en_maxwaiting = ENMAXWAITING; else t.en_maxwaiting = ENNOTSUWAITING; t.en_maxpriority = ENMAXPRI; t.en_rtout = d->enOD_Timeout; t.en_addr = -1; t.en_maxfilters = ENMAXFILTERS; bcopy((caddr_t)&t, addr, sizeof t); } endcase case EIOCSETP: { struct eniocb t; bcopy(addr, (caddr_t)&t, sizeof t); d->enOD_Timeout = t.en_rtout; } endcase case EIOCSETF: { struct enfilter f; unsigned short *fp; bcopy(addr, (caddr_t)&f, sizeof f); if (f.enf_FilterLen > ENMAXFILTERS) { return(EINVAL); } /* insure that filter is installed indivisibly */ ipl = splenet(); smp_lock(&lk_pfilt, LK_RETRY); bcopy((caddr_t)&f, (caddr_t)&(d->enOD_OpenFilter), sizeof f); /* pre-compute length of filter */ fp = &(d->enOD_OpenFilter.enf_Filter[0]); d->enOD_FiltEnd = &(fp[d->enOD_OpenFilter.enf_FilterLen]); d->enOD_RecvCount = 0; /* reset counts when filter changes */ d->enOD_Drops = 0; pfiltdequeue((struct Queue *)d->enOD_Link.B, dummy); enDesq.enQ_NumQueued--; PfiltInsertDescriptor(&(enDesq), d); smp_unlock(&lk_pfilt); splx(ipl); } endcase /* * Enable signal n on input packet */ case EIOCENBS: { int snum; bcopy(addr, (caddr_t)&snum, sizeof snum); if (snum < NSIG) { d->enOD_SigProc = u.u_procp; d->enOD_SigPid = u.u_procp->p_pid; d->enOD_SigNumb = snum; /* This must be set last */ } else { goto bad; } } endcase /* * Disable signal on input packet */ case EIOCINHS: { d->enOD_SigNumb = 0; } endcase /* * Check for packet waiting */ case FIONREAD: { int n; register struct enWaitQueue *wq; ipl = splenet(); smp_lock(&lk_pfilt, LK_RETRY); if ((wq = &(d->enOD_Waiting))->enWQ_NumQueued) n = wq->enWQ_Packets[wq->enWQ_Head]->enP_ByteCount; else n = 0; smp_unlock(&lk_pfilt); splx(ipl); bcopy((caddr_t)&n, addr, sizeof n); } endcase /* * Set maximum recv queue length for a device */ case EIOCSETW: { unsigned un; bcopy(addr, (caddr_t)&un, sizeof un); /* * unsigned un MaxQueued * ---------------- ------------ * 0 -> DEFWAITING * 1..MAXWAITING -> un * MAXWAITING..-1 -> MAXWAITING * * Non-superusers use ENNOTSUWAITING instead of ENMAXWAITING */ if (!suser()) d->enOD_Waiting.enWQ_MaxWaiting = (un) ? min(un,ENNOTSUWAITING) : ENDEFWAITING; else d->enOD_Waiting.enWQ_MaxWaiting = (un) ? min(un, ENMAXWAITING) : ENDEFWAITING; } endcase /* * Flush all packets queued for a device */ case EIOCFLUSH: { ipl = splenet(); smp_lock(&lk_pfilt, LK_RETRY); PfiltFlushWaitQueue(d); d->enOD_Drops = 0; smp_unlock(&lk_pfilt); splx(ipl); } endcase /* * Set mode bits */ case EIOCMBIS: { u_short mode; short oldmode = d->enOD_Flag; bcopy(addr, (caddr_t)&mode, sizeof mode); if (mode&ENPRIVMODES) return(EINVAL); else d->enOD_Flag |= mode; /* if necessary, bump counter for promiscuous mode */ if ((mode & ENPROMISC) && ((oldmode & ENPROMISC) == 0)) { ipl = splenet(); /* lock PromiscCount */ smp_lock(&lk_pfilt, LK_RETRY); incPromiscCount(enStatep, dev); smp_unlock(&lk_pfilt); splx(ipl); /* unlock PromiscCount */ } /* if necessary, bump counter for copy-all mode */ if ((mode & ENCOPYALL) && ((oldmode & ENCOPYALL) == 0)) { ipl = splenet(); /* lock CopyAllCount */ smp_lock(&lk_pfilt, LK_RETRY); incCopyAllCount(enStatep, dev); smp_unlock(&lk_pfilt); splx(ipl); /* unlock CopyAllCount */ } } endcase /* * Clear mode bits */ case EIOCMBIC: { u_short mode; short oldmode = d->enOD_Flag; bcopy(addr, (caddr_t)&mode, sizeof mode); if (mode&ENPRIVMODES) return(EINVAL); else d->enOD_Flag &= ~mode; /* if necessary, drop counter for promiscuous mode */ if ((oldmode & ENPROMISC) && (mode & ENPROMISC)) { ipl = splenet(); /* lock PromiscCount */ smp_lock(&lk_pfilt, LK_RETRY); decPromiscCount(enStatep, dev); smp_unlock(&lk_pfilt); splx(ipl); /* unlock PromiscCount */ } /* if necessary, drop counter for copy-all mode */ if ((oldmode & ENCOPYALL) && (mode & ENCOPYALL)) { ipl = splenet(); /* lock CopyAllCount */ smp_lock(&lk_pfilt, LK_RETRY); decCopyAllCount(enStatep, dev); smp_unlock(&lk_pfilt); splx(ipl); /* unlock CopyAllCount */ } } endcase /* * Return hardware-specific device parameters. */ case EIOCDEVP: { bcopy((caddr_t)&(enDevParams), addr, sizeof(struct endevp)); } endcase; /* * Return # of free minor devices. */ case EIOCMFREE: { register int md; register int sum = 0; for (md = 0; md < enMaxMinors; md++) if (enAllocMap[md] == FALSE) sum++; *(int *)addr = sum; } endcase; case EIOCIFNAME: { struct ifreq ifr; register char *cp, *ep; register struct ifnet *ifp = enet_info[ENUNIT(dev)].ifp; ep = ifr.ifr_name + sizeof(ifr.ifr_name) - 2; bcopy(ifp->if_name, ifr.ifr_name, (sizeof(ifr.ifr_name) - 2)); for (cp = ifr.ifr_name; (cp < ep) && *cp; cp++) ; *cp++ = '0' + ifp->if_unit; /* unit better be < 10 */ *cp = '\0'; bcopy((caddr_t)&ifr, addr, sizeof(ifr)); } endcase; /* * Set maximum packet length to return */ case EIOCTRUNCATE: { int truncation; bcopy(addr, (caddr_t)&truncation, sizeof truncation); if (truncation < 0) d->enOD_Truncation = ENMAXINT; else d->enOD_Truncation = truncation; } endcase /* * Allows non-super-users to set IFF_PROMISC. This ioctl * (super-user-only) sets/clears a per-interface flag; if * the flag is set, then descriptors with ENPROMISC cause * the interface to go into promiscuous mode. We keep a * reference count on this, and clear IFF_PROMISC when the * the count goes to zero. */ case EIOCALLOWPROMISC: { int allowpromisc; register struct ifnet *ifp = enet_info[ENUNIT(dev)].ifp; int wantpromisc; bcopy(addr, (caddr_t)&allowpromisc, sizeof allowpromisc); if (allowpromisc < 0) { /* attempt to read current setting */ allowpromisc = (enStatep->ens_AllowPromisc == true); bcopy((caddr_t)&allowpromisc, addr, sizeof allowpromisc); return(0); } if (!suser()) return(EPERM); ipl = splenet(); /* lock PromiscCount */ smp_lock(&lk_pfilt, LK_RETRY); if ((enStatep->ens_AllowPromisc == true) && (allowpromisc == 0)) { /* Must disable IFF_PROMISC if we set it */ if (enStatep->ens_PromiscCount > 0) enetSetIfflags(ifp, (ifp->if_flags & ~IFF_PROMISC)); enStatep->ens_PromiscCount = 0; enStatep->ens_AllowPromisc = false; } if ((enStatep->ens_AllowPromisc == false) && (allowpromisc != 0)) { /* Count the number of descriptors wanting promiscuous mode */ wantpromisc = 0; forAllOpenDescriptors(d) if (d->enOD_Flag & ENPROMISC) wantpromisc++; enStatep->ens_PromiscCount = wantpromisc; if (wantpromisc > 0) enetSetIfflags(ifp, (ifp->if_flags | IFF_PROMISC)); enStatep->ens_AllowPromisc = true; } smp_unlock(&lk_pfilt); splx(ipl); /* unlock PromiscCount */ } endcase /* * Allows non-super-users to set IFF_PFCOPYALL. This ioctl * (super-user-only) sets/clears a per-interface flag; if * the flag is set, then descriptors with ENCOPYALL cause * ether_read() to go into copy-all mode. We keep a * reference count on this, and clear IFF_PFCOPYALL when the * the count goes to zero. */ case EIOCALLOWCOPYALL: { int allowcopyall; register struct ifnet *ifp = enet_info[ENUNIT(dev)].ifp; int wantcopyall; bcopy(addr, (caddr_t)&allowcopyall, sizeof allowcopyall); if (allowcopyall < 0) { /* attempt to read current setting */ allowcopyall = (enStatep->ens_AllowCopyAll == true); bcopy((caddr_t)&allowcopyall, addr, sizeof allowcopyall); return(0); } if (!suser()) return(EPERM); ipl = splenet(); /* lock CopyAllCount */ smp_lock(&lk_pfilt, LK_RETRY); if ((enStatep->ens_AllowCopyAll == true) && (allowcopyall == 0)) { /* Must disable IFF_PFCOPYALL if we set it */ if (enStatep->ens_CopyAllCount > 0) enetSetIfflags(ifp, (ifp->if_flags & ~IFF_PFCOPYALL)); enStatep->ens_CopyAllCount = 0; enStatep->ens_AllowCopyAll = false; } if ((enStatep->ens_AllowCopyAll == false) && (allowcopyall != 0)) { /* Count the number of descriptors wanting copy-all mode */ wantcopyall = 0; forAllOpenDescriptors(d) if (d->enOD_Flag & ENCOPYALL) wantcopyall++; enStatep->ens_CopyAllCount = wantcopyall; if (wantcopyall > 0) enetSetIfflags(ifp, (ifp->if_flags | IFF_PFCOPYALL)); enStatep->ens_AllowCopyAll = true; } smp_unlock(&lk_pfilt); splx(ipl); /* unlock CopyAllCount */ } endcase /* * Set the maximum backlog allowed for non-super-user descriptors. * Make sure it is within the legal range. */ case EIOCMAXBACKLOG: { int maxbacklog; bcopy(addr, (caddr_t)&maxbacklog, sizeof maxbacklog); if (maxbacklog < 0) { /* attempt to read current setting */ maxbacklog = enStatep->ens_UserMaxWaiting; bcopy((caddr_t)&maxbacklog, addr, sizeof maxbacklog); return(0); } if (!suser()) return(EPERM); if ((maxbacklog < 1) || (maxbacklog > ENMAXWAITING)) return(EINVAL); enStatep->ens_UserMaxWaiting = maxbacklog; } endcase /* * Set the read timeout for this descriptor. Converts * from struct timeval to ticks. */ case EIOCSRTIMEOUT: { struct timeval rtv; long ticks; bcopy(addr, (caddr_t)&rtv, sizeof rtv); /* Check to make sure this is not too big */ if (rtv.tv_sec >= ((1<<((NBBY*sizeof(long))-1))/hz) ) if (rtv.tv_usec >= 1000000) return(EINVAL); ticks = (rtv.tv_sec * hz) + (rtv.tv_usec / tick); d->enOD_Timeout = ticks; } endcase /* * Get the read timeout for this descriptor. Converts * from ticks to struct timeval. */ case EIOCGRTIMEOUT: { struct timeval rtv; long ticks = d->enOD_Timeout; rtv.tv_sec = ticks / hz;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -