⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pfilt.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif#ifdef	SELF_PROF    if (enSelfProf) {	struct timeval starttv, endtv;	microtime(&starttv);	microtime(&endtv);	enCalibrateProf.tv_sec += (endtv.tv_sec - starttv.tv_sec); 	enCalibrateProf.tv_usec += (endtv.tv_usec - starttv.tv_usec); 	enCalibrateCount++;    }#endif	SELF_PROF#ifdef	GNODE_CLONING    /*     * Each open enet file has a different minor device number.     * When a user tries to open any of them, we actually open     * any available minor device and associate it with the     * corresponding unit.     *     * This is not elegant, but UNIX will call     * open for each new open file using the same inode but calls     * close only when the last open file referring to the inode      * is released. This means that we cannot know inside the     * driver code when the resources associated with a particular     * open of the same inode should be deallocated.  Thus, we have     * to make up a temporary inode to represent each simultaneous     * open of the ethernet.  Each inode has a different minor device number.     */    unit = minor(dev);    /* check for illegal unit */    if ( (unit >= enUnits)				/* bad unit */	|| (enet_info[unit].ifp == 0)			/* ifp not known */	|| ((enet_info[unit].ifp->if_flags & IFF_UP) == 0) )							/* or if down */    {	return(ENXIO);    }#else    /*     * Without gnode cloning, we have to have a separate entry in     * /dev/ for each minor device.  They all start out bound to     * the first "up" interface.     */    for (unit = 0; unit < enUnits; unit++) {	/* check all units in order */	if (enet_info[unit].ifp				/* interface known */	    && (enet_info[unit].ifp->if_flags & IFF_UP) ) 	/* and up */		break;	/* fall out of loop */    }    /* check for illegal unit (i.e., nothing "up") */    if (unit >= enUnits)				/* bad unit */	return(ENXIO);#endif	GNODE_CLONING#ifdef	GNODE_CLONING    /* Allocate a minor device number */    md = PfiltFindMinor();#ifdef	DEBUG    Pfiltprintf(ENDBG_TRACE)("Pfilt_open: md = %d\n", md);#endif    if (md < 0)    {	return(EBUSY);    }    *newmin = md;#else    /* Use the minor device number supplied */    md = minor(dev);    if (md >= NPACKETFILTER)	return(ENXIO);		/* an illegal minor device number */    if (enAllocMap[md])	return(EBUSY);		/* already in use */#endif	GNODE_CLONING    enUnitMap[md] = unit;    enAllocMap[md] = TRUE;    enStatep = enStatePs[unit];    Pfiltprintf(ENDBG_DESQ)    	("Pfilt_open: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B);    s = splenet(); /* SMP */    smp_lock(&lk_pfilt, LK_RETRY);    pfactive++;    /* Allocate memory for this descriptor */    KM_ALLOC(enAllDescriptors[md], struct enOpenDescriptor *,		sizeof(struct enOpenDescriptor), KM_PFILT, KM_NOW_CL);    if (enAllDescriptors[md] == NULL)	return(ENOBUFS);    PfiltInitDescriptor(enAllDescriptors[md], ENHOLDSIG);		/* ENHOLDSIG is set by default; historical accident */    PfiltInsertDescriptor(&(enDesq), enAllDescriptors[md]);    smp_unlock(&lk_pfilt);    splx(s);    return(0);}/* * PfiltFindMinor - find a free logical device on specified unit */PfiltFindMinor(){	register int md;		for (md = 0; md < enMaxMinors; md++) {		if (enAllocMap[md] == FALSE)			return(md);	}	return(-1);}/* *  PfiltInit - initialize ethernet unit (called by pfilt_attach) */PfiltInit(enStatep, unit)register struct enState *enStatep;register int unit;{    int s;#ifdef	DEBUG    Pfiltprintf(ENDBG_INIT)("PfiltInit(%x %d):\n", enStatep, unit);#endif    s = splenet(); /* SMP */    smp_lock(&lk_pfilt, LK_RETRY);    /*  initialize free queue if not already done  */    if (enFreeq.enQ_F == 0)    {	register int i;	pfiltinitqueue((struct Queue *)&enFreeq);	for (i=0; i<ENPACKETS; i++)	{	    register struct enPacket *p;	    p = &enQueueElts[i];	    p->enP_RefCount = 0;	    p->enP_Stamp.ens_stamplen = sizeof(struct enstamp);	    PfiltDeallocatePacket(p);	}	/* calculate scavenger thresholds */	PfiltInitScavenge();	/* also a good time to init enAllocMap */	for (i = 0; i < enMaxMinors; i++)		enAllocMap[i] = FALSE;    }    pfiltinitqueue((struct Queue *)&enDesq);	/* init descriptor queue */    enStatep->ens_UserMaxWaiting = ENNOTSUWAITING;    enStatep->ens_AllowPromisc = false;    smp_unlock(&lk_pfilt);    splx(s);}/* *  Pfilt_close - ether net device close routine *//* ARGSUSED */Pfilt_close(dev, flag){    register int md = ENINDEX(dev);    register struct enState *enStatep = enStatePs[ENUNIT(dev)];    register struct enOpenDescriptor *d = enAllDescriptors[md];    struct enPacket *dummy;	/* a dummy pointer - used only for consistency				 * in the macro pfiltdequeue				 */    int ipl;    extern PfiltTimeout();    enAllocMap[md] = FALSE;#ifdef	DEBUG    Pfiltprintf(ENDBG_TRACE)("Pfilt_close(%d, %x):\n", md, flag);#endif    /*     *  insure that receiver doesn't try to queue something     *  for the device as we are decommissioning it.     *  (I don't think this is necessary, but I'm a coward.)     */    ipl = splenet();    smp_lock(&lk_pfilt, LK_RETRY);    pfactive--;    /* if necessary, drop counter for promiscuous mode */    if (d->enOD_Flag & ENPROMISC) {	decPromiscCount(enStatep, dev);    }    /* if necessary, drop counter for copy-all mode */    if (d->enOD_Flag & ENCOPYALL) {	decCopyAllCount(enStatep, dev);    }    pfiltdequeue((struct Queue *)d->enOD_Link.B, dummy);    enCurOpens--;    Pfiltprintf(ENDBG_DESQ)    		("Pfilt_close: Desq: %x, %x\n", enDesq.enQ_F, enDesq.enQ_B);    PfiltFlushWaitQueue(d);    untimeout(PfiltTimeout, (caddr_t)d);    KM_FREE(d, KM_PFILT);    enAllDescriptors[md] = (struct enOpenDescriptor *)0;    smp_unlock(&lk_pfilt);    splx(ipl);}/* *  Pfilt_read - read next packet from net *//* VARARGS */Pfilt_read(dev, uio)dev_t dev;register struct uio *uio;{    register struct enOpenDescriptor *d = enAllDescriptors[ENINDEX(dev)];    register struct enPacket *p;    int ipl;    int error;    int padneeded = 0;		/* modified by Pfiltrmove() */    int first = 1;		/* is this the first packet in a batch? */    extern PfiltTimeout();#if	DEBUG    Pfiltprintf(ENDBG_TRACE)("Pfilt_read(%x):", dev);#endif    ipl = splenet();    smp_lock(&lk_pfilt, LK_RETRY);    /*     *  If nothing is on the queue of packets waiting for     *  this open enet file, then set timer and sleep until     *  either the timeout has occurred or a packet has     *  arrived.     */    while (0 == d->enOD_Waiting.enWQ_NumQueued)    {	if (d->enOD_Timeout < 0)	{	    smp_unlock(&lk_pfilt);	    splx(ipl);	    return(0);	}	if (d->enOD_Timeout)	{	    /*	     *  If there was a previous timeout pending for this file,	     *  cancel it before setting another.  This is necessary since	     *  a cancel after the sleep might never happen if the read is	     *  interrupted by a signal.	     */	    if (d->enOD_RecvState == ENRECVTIMING)		untimeout(PfiltTimeout, (caddr_t)d);	    timeout(PfiltTimeout, (caddr_t)d, (int)(d->enOD_Timeout));	    d->enOD_RecvState = ENRECVTIMING;	}	else	    d->enOD_RecvState = ENRECVIDLE;	sleep_unlock((caddr_t)d, PRINET, &lk_pfilt);	smp_lock(&lk_pfilt, LK_RETRY);	switch (d->enOD_RecvState)	{	    case ENRECVTIMING:	    {		untimeout(PfiltTimeout, (caddr_t)d);		d->enOD_RecvState = ENRECVIDLE;		break;	    }	    case ENRECVTIMEDOUT:	    {		smp_unlock(&lk_pfilt);		splx(ipl);		return(0);	    }	}    }    /* We believe there is something waiting for us in the queue */    while (1) {	if (d->enOD_Waiting.enWQ_NumQueued <= 0) {	    /*	     * Either we emptied the queue or someone else did while	     * we weren't looking.	     */	    smp_unlock(&lk_pfilt);	    splx(ipl);	    return(0);	}	p = PfiltDeWaitQueue(&(d->enOD_Waiting));	if (first) {	    first = 0;	}	else {	/* this is not the first packet in a batch */	    if (uio->uio_resid <	    	(padneeded + sizeof(struct enstamp) + p->enP_ByteCount)) {		/* no more room in user's buffer; don't truncate packet */		PfiltPutBack(&(d->enOD_Waiting), p);		smp_unlock(&lk_pfilt);		splx(ipl);		return(0);	    }	}	/*  	 * Move data from packet into user space.	 */	smp_unlock(&lk_pfilt);	/* unlock for uiomove */	splx(ipl);	error = Pfiltrmove(p, uio, d->enOD_Flag, &padneeded, d->enOD_Truncation);	ipl = splenet();	smp_lock(&lk_pfilt, LK_RETRY); /* relock after uiomove */    	if (--(p->enP_RefCount) <= 0)	/* if no more claims on this packet */	{	    m_freem(p->enP_mbuf);	/* release mbuf */	    PfiltDeallocatePacket(p);	/* and packet */	}	if (d->enOD_Flag & ENBATCH && !error && uio->uio_resid > 0)	    continue;	else	    break;    }    smp_unlock(&lk_pfilt);    splx(ipl);    return(error);}/* *  PfiltTimeout - process ethernet read timeout */PfiltTimeout(d)register struct enOpenDescriptor * d;{    register int ipl;    register struct enOpenDescriptor *t;    register struct enState *enStatep;    register int unit;#ifdef	DEBUG    Pfiltprintf(ENDBG_TRACE)("PfiltTimeout(%x):\n", d);#endif    ipl = splenet();    smp_lock(&lk_pfilt, LK_RETRY);    if (smp) {	/* don't call Pfilt_wakeup if the descriptor has gone away */	for (unit = 0; unit < enUnits; unit++) {	    enStatep = enStatePs[unit];	    if (enDesq.enQ_F == 0)		continue;			/* never initialized */	    forAllOpenDescriptors(t) {		if (d == t)		    goto out;	    }	}	/* if we fall through to here, then descriptor is no longer valid */	smp_unlock(&lk_pfilt);	splx(ipl);	return(0);    }out:    d->enOD_RecvState = ENRECVTIMEDOUT;    Pfilt_wakeup(d);    smp_unlock(&lk_pfilt);    splx(ipl);    wakeup((caddr_t)d);}/* *  Pfilt_write - write next packet to net */int PfiltKludgeSleep[MAXUNITS];	/* Are we sleeping on IF_QFULL? */				/*  really, # of procs sleeping on IF_QFULL *//* VARARGS */Pfilt_write(dev, uio)dev_t dev;register struct uio *uio;{    register int unit = ENUNIT(dev);    register struct enState *enStatep = enStatePs[unit];    struct mbuf *mp;    register struct ifnet *ifp = enet_info[unit].ifp;    int ipl;    int error;    int sleepcount;    int PfiltKludgeTime();#if	DEBUG    Pfiltprintf(ENDBG_TRACE)("Pfilt_write(%x):\n", dev);#endif     if (uio->uio_resid == 0)	 return(0);     if (uio->uio_resid > ifp->if_mtu)	/* too large */	 return(EMSGSIZE);     /*     * Copy user data into mbufs     */     if (error = Pfiltwmove(uio, &mp)) {	 return(error);     }    ipl = splenet();    smp_lock(&lk_pfilt, LK_RETRY);    /*     * if the queue is full,     * hang around until there's room or until process is interrupted     */    sleepcount = 0;    while (IF_QFULL(&(ifp->if_snd))) {	if (sleepcount++ > 2) {	/* don't sleep too long */	    smp_unlock(&lk_pfilt);	    splx(ipl);	    return(ETIMEDOUT);	}	/* if nobody else has a timeout pending for this unit, set one */	if (PfiltKludgeSleep[unit] == 0)	    timeout(PfiltKludgeTime, (caddr_t)unit, 2 * hz);	PfiltKludgeSleep[unit]++;	/* record that we are sleeping */	if (setjmp(&u.u_qsave)) {	    /* sleep (following) was interrupted, clean up */#if	DEBUG	    Pfiltprintf(ENDBG_MISC)	    	("Pfilt_write(%x): enet%d sleep %d interrupted\n", dev,			unit, PfiltKludgeSleep[unit]);#endif	DEBUG	    PfiltKludgeSleep[unit]--;	/* we're no longer sleeping */	    m_freem(mp);	    splx(ipl);	    return(EINTR);	}	sleep_unlock((caddr_t)&(PfiltKludgeSleep[unit]), PRINET, &lk_pfilt);	smp_lock(&lk_pfilt, LK_RETRY);	PfiltKludgeSleep[unit]--;	/* we are no longer sleeping */    }        smp_unlock(&lk_pfilt);    /* place mbuf chain on outgoing queue & start if necessary */    error = (*ifp->if_output)(ifp, mp, &enetaf);			/* this always frees the mbuf chain */    enXcnt++;    splx(ipl);    return(error);}PfiltKludgeTime(unit)int unit;{	/* XXX perhaps we should always wakeup? */	if (PfiltKludgeSleep[unit]) {		wakeup((caddr_t)&(PfiltKludgeSleep[unit]));		/* XXX should we restart transmitter? */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -