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

📄 if_vv.c

📁 open bsd vax module -if function
💻 C
📖 第 1 页 / 共 2 页
字号:
done:	/* deallocate mbuf used for send packet (won't be one, anyways) */	if (vs->vs_ifuba.ifu_xtofree) {		m_freem(vs->vs_ifuba.ifu_xtofree);		vs->vs_ifuba.ifu_xtofree = 0;	}	return(shost);}/* * Start or restart output on interface. * If interface is active, this is a retransmit, so just * restuff registers and go. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. */vvstart(dev)	dev_t dev;{	register struct uba_device *ui;	register struct vv_softc *vs;	register struct vvreg *addr;	register struct mbuf *m;	register int unit, ubaaddr, dest, s;	unit = VVUNIT(dev);	ui = vvinfo[unit];	vs = &vv_softc[unit];	if (vs->vs_oactive)		goto restart;	/*	 * Not already active: dequeue another request	 * and map it to the UNIBUS.  If no more requests,	 * just return.	 */	s = splimp();	IF_DEQUEUE(&vs->vs_if.if_snd, m);	splx(s);	if (m == NULL) {		vs->vs_oactive = 0;		return;	}	dest = mtod(m, struct vv_header *)->vh_dhost;	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);	vs->vs_lastx = dest;	vs->vs_if.if_obytes += vs->vs_olen;	vs->vs_if.if_lastchange = time;restart:	/*	 * Have request mapped to UNIBUS for transmission.	 * Purge any stale data from this BDP, and start the output.	 *	 * Make sure this packet will fit in the interface.	 */	if (vs->vs_olen > VVBUFSIZE) {		printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);		panic("vvdriver vs_olen botch");	}	vs->vs_if.if_timer = VVTIMEOUT;	vs->vs_oactive = 1;	/* ship it */#ifdef notdef	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);#endif	addr = (struct vvreg *)ui->ui_addr;	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);	addr->vvoba = (u_short) ubaaddr;	addr->vvoea = (u_short) (ubaaddr >> 16);	addr->vvowc = -((vs->vs_olen + 1) >> 1);	addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */	if (addr->vvocsr & VV_NOK)		vs->vs_init++;			/* count ring inits */	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;}/* * proNET transmit interrupt * Start another output if more data to send. */vvxint(unit)	int unit;{	register struct uba_device *ui;	register struct vv_softc *vs;	register struct vvreg *addr;	register int oc;	ui = vvinfo[unit];	vs = &vv_softc[unit];#ifdef QBA	splx(vs->vs_ipl);#endif	vs->vs_if.if_timer = 0;	addr = (struct vvreg *)ui->ui_addr;	oc = 0xffff & (addr->vvocsr);	if (vs->vs_oactive == 0) {		vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit,		    oc, VV_OBITS);		return;	}	/*	 * we retransmit on soft error	 * TODO: sort retransmits to end of queue if possible!	 */	if (oc & (VV_OPT | VV_RFS)) {		if (vs->vs_tries++ < VVRETRY) {			if (oc & VV_OPT)				vs->vs_otimeout++;			if (oc & VV_RFS) {				vs->vs_if.if_collisions++;				vs->vs_refused++;			}			vvstart(unit);		/* restart this message */			return;		}	}	vs->vs_if.if_opackets++;	vs->vs_oactive = 0;	vs->vs_tries = 0;	if (oc & VVXERR) {		vs->vs_if.if_obytes -= vs->vs_olen;		vs->vs_if.if_oerrors++;		vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n",		    unit, 0xffff & oc, VV_OBITS);	}	if (vs->vs_ifuba.ifu_xtofree) {		m_freem(vs->vs_ifuba.ifu_xtofree);		vs->vs_ifuba.ifu_xtofree = 0;	}	vvstart(unit);}/* * Transmit watchdog timer routine. * This routine gets called when we lose a transmit interrupt. * The best we can do is try to restart output. */vvwatchdog(unit)	int unit;{	register struct vv_softc *vs;	vs = &vv_softc[unit];	log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit);	vs->vs_timeouts++;	vvstart(unit);}/* * proNET 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.  Otherwise decapsulate * packet based on type and pass to type specific higher-level * input routine. */vvrint(unit)	int unit;{	register struct vv_softc *vs;	register struct vvreg *addr;	register struct vv_header *vv;	register struct ifqueue *inq;	register struct mbuf *m;	int ubaaddr, len, off, s;	short resid;	vs = &vv_softc[unit];#ifdef QBA	splx(vs->vs_ipl);#endif	vs->vs_if.if_ipackets++;	vs->vs_if.if_lastchange = time;	addr = (struct vvreg *)vvinfo[unit]->ui_addr;	/*	 * Purge BDP	 */	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);	/*	 * receive errors?	 */	if (addr->vvicsr & VVRERR) {		vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit,		    0xffff&(addr->vvicsr), VV_IBITS);		if (addr->vvicsr & VV_BDF)			vs->vs_ibadf++;		goto dropit;	}	/*	 * parity errors?	 */	if (addr->vvicsr & VV_LDE) {		/* we don't have to clear it because the receive command */		/* writes 0 to parity bit */		vs->vs_parity++;		/*		 * only on 10 megabit proNET is VV_LDE an end-to-end parity		 * bit. On 80 megabit, it returns to the intended use of		 * node-to-node parity. End-to-end parity errors on 80 megabit		 * give VV_BDF.		 */		if (vs->vs_is80 == 0)		    goto dropit;	}	/*	 * Get packet length from residual word count	 *	 * Compute header offset if trailer protocol	 *	 * 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.  The vh_info field	 * carries the offset to the trailer data in trailer	 * format packets.	 */	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);	vvtracehdr("vi", vv);	resid = addr->vviwc & 01777;	/* only low 10 bits valid */	if (resid)		resid |= 0176000;	/* high 6 bits are undefined */	len = ((VVBUFSIZE >> 1) + resid) << 1;	len -= sizeof(struct vv_header);	if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {		vvlog(LOG_DEBUG, "vv%d: len too long or short, \len = %d, vvicsr = %b\n",			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);		goto dropit;	}	/* check the protocol header version */	if (vv->vh_version != RING_VERSION) {		vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n",		    unit, vv->vh_version & 0xff);		goto dropit;	}#define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))	if (vv->vh_type == RING_TRAILER ) {		off = ntohs((u_short)vv->vh_info);		if (off > VVMTU) {			vvlog(LOG_DEBUG,			    "vv%d: off > VVMTU, off = %d, vvicsr = %b\n",			    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);			goto dropit;		}		vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));		resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));		if (off + resid > len) {			vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n",			    unit);			vvlog(LOG_DEBUG,			    "vv%d: off = %d, resid = %d, vvicsr = %b\n",			    unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS);			goto dropit;		}		len = off + resid;	} else		off = 0;	if (len == 0) {		vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit,			    0xffff&(addr->vvicsr), VV_IBITS);		goto dropit;	}	m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);	if (m == NULL) {		vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n",		    unit, 0xffff&(addr->vvicsr), VV_IBITS);		goto dropit;	}	vs->vs_if.if_ibytes += m->m_pkthdr.len;	if (vv->vh_dhost == VV_BROADCAST) {		m->m_flags |= M_BCAST;		vs->vs_if.if_imcasts++;	}	/* Keep track of source address of this packet */	vs->vs_lastr = vv->vh_shost;	/*	 * Demultiplex on packet type	 */	switch (vv->vh_type) {#ifdef INET	case RING_IP:		schednetisr(NETISR_IP);		inq = &ipintrq;		break;#endif	default:		vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n",		    unit, vv->vh_type);		m_freem(m);		vs->vs_if.if_noproto++;		goto setup;	}	s = splimp();	if (IF_QFULL(inq)) {		IF_DROP(inq);		m_freem(m);		vs->vs_if.if_iqdrops++;	} else		IF_ENQUEUE(inq, m);	splx(s);	/*	 * Reset for the next packet.	 */setup:	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);	addr->vviba = (u_short) ubaaddr;	addr->vviea = (u_short) (ubaaddr >> 16);	addr->vviwc = -(VVBUFSIZE) >> 1;	addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;	return;	/*	 * Drop packet on floor -- count them!!	 */dropit:	vs->vs_if.if_ierrors++;	goto setup;}/* * proNET 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. */vvoutput(ifp, m0, dst, rt)	struct ifnet *ifp;	struct mbuf *m0;	struct sockaddr *dst;	struct rtentry *rt;{	register struct mbuf *m;	register struct vv_header *vv;	register int off;	register int unit;	register struct vvreg *addr;	register struct vv_softc *vs;	register int s;	int type, dest, error;	m = m0;	unit = ifp->if_unit;	if ((ifp->if_flags & IFF_UP) == 0)		return (ENETDOWN);	addr = (struct vvreg *)vvinfo[unit]->ui_addr;	vs = &vv_softc[unit];	/*	 * Check to see if the input side has wedged due the UBA	 * vectoring through 0.	 *	 * We are lower than device ipl when we enter this routine,	 * so if the interface is ready with an input packet then	 * an input interrupt must have slipped through the cracks.	 *	 * Avoid the race with an input interrupt by watching to see	 * if any packets come in.	 */	s = vs->vs_if.if_ipackets;	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {		log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n",			    unit, 0xffff&(addr->vvicsr), VV_IBITS);		s = splimp();		vvrint(unit);		splx(s);	}	switch (dst->sa_family) {#ifdef INET	case AF_INET:		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))			dest = VV_BROADCAST;		else			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);#ifdef LOOPBACK		if (dest == vs->vs_host && (loif.if_flags & IFF_UP))			return (looutput(&loif, m0, dst, rt));#endif LOOPBACK		if (dest >= 0x100) {			error = EPERM;			goto bad;		}		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;		/*		 * Trailerize, if the configuration allows it.		 * TODO: Need per host negotiation.		 */		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)		if (off > 0 && (off & 0x1ff) == 0 &&		    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {			type = RING_TRAILER;			m->m_data -= 2 * sizeof (u_short);			m->m_len += 2 * sizeof (u_short);			*mtod(m, u_short *) = htons((short)RING_IP);			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);			goto gottrailertype;		}		type = RING_IP;		off = 0;		goto gottype;#endif	default:		printf("vv%d: can't handle af%d\n", 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 vv_header), M_DONTWAIT);	if (m == 0)		return (ENOBUFS);	vv = mtod(m, struct vv_header *);	vv->vh_shost = vs->vs_host;	vv->vh_dhost = dest;	vv->vh_version = RING_VERSION;	vv->vh_type = type;	vv->vh_info = htons((u_short)off);	vvtracehdr("vo", vv);	/*	 * 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 (vs->vs_oactive == 0)		vvstart(unit);	splx(s);	return (0);qfull:	m0 = m;	splx(s);bad:	m_freem(m0);	return(error);}/* * Process an ioctl request. */vvioctl(ifp, cmd, data)	register struct ifnet *ifp;	int cmd;	caddr_t data;{	register struct vv_softc *vs = &vv_softc[ifp->if_unit];	struct ifaddr *ifa = (struct ifaddr *) data;	struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]);	int s = splimp(), error = 0;	switch (cmd) {	case SIOCSIFADDR:		if ((vs->vs_flags & VS_RUNNING) == 0)			vvinit(ifp->if_unit, 1);		/*		 * Did self-test succeed?		 */		if ((ifp->if_flags & IFF_UP) == 0)			error = ENETDOWN;		else {			/*			 * 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) & 0xff) !=				    vs->vs_host)					error = EADDRNOTAVAIL;				break;			}		}		break;	case SIOCSIFFLAGS:		if ((ifp->if_flags & IFF_UP) == 0 &&		    vs->vs_flags & VS_RUNNING) {			addr->vvicsr = VV_RST;			addr->vvocsr = VV_RST;			vs->vs_flags &= ~VS_RUNNING;		} else if (ifp->if_flags & IFF_UP &&		    (vs->vs_flags & VS_RUNNING) == 0)			vvinit(ifp->if_unit, 1);		break;	default:		error = EINVAL;		break;	}	splx(s);	return (error);}/* * vvprt_hdr(s, v) print the local net header in "v" *	with title is "s" */vvprt_hdr(s, v)	char *s;	register struct vv_header *v;{	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",		s,		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),		0xffff & (int)(v->vh_info));}#endif NVV

⌨️ 快捷键说明

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