📄 if_vv.c
字号:
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;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 */ if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp, vs->vs_ifuba.ifu_uban); addr = (struct vvreg *)ui->ui_addr; ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; addr->vvoba = (u_short) ubainfo; addr->vvoea = (u_short) (ubainfo >> 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]; vs->vs_if.if_timer = 0; addr = (struct vvreg *)ui->ui_addr; oc = 0xffff & (addr->vvocsr); if (vs->vs_oactive == 0) { vvprintf("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_oerrors++; vvprintf("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; register int s; vs = &vv_softc[unit]; vvprintf("vv%d: lost a transmit interrupt.\n", unit); vs->vs_timeouts++; s = splimp(); vvstart(unit); splx(s);}/* * 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 ubainfo, len, off, s; short resid; vs = &vv_softc[unit]; vs->vs_if.if_ipackets++; 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, vs->vs_ifuba.ifu_uban); /* * receive errors? */ if (addr->vvicsr & VVRERR) { vvprintf("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) { vvprintf("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) { vvprintf("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) { vvprintf("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) { vvprintf("vv%d: trailer packet too short\n", unit); vvprintf("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) { vvprintf("vv%d: len is zero, vvicsr = %b\n", unit, 0xffff&(addr->vvicsr), VV_IBITS); goto dropit; } m = if_rubaget(&vs->vs_ifuba, len, off); if (m == NULL) { vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit, 0xffff&(addr->vvicsr), VV_IBITS); goto dropit; } if (off) { m->m_off += 2 * sizeof(u_short); m->m_len -= 2 * sizeof(u_short); } /* 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: vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); m_freem(m); goto setup; } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUEIF(inq, m, &vs->vs_if); splx(s); /* * Reset for the next packet. */setup: ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; addr->vviba = (u_short) ubainfo; addr->vviea = (u_short) (ubainfo >> 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) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst;{ 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; 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) { vvprintf("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));#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_off >= MMINOFF + 2 * sizeof (u_short)) { type = RING_TRAILER; m->m_off -= 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. */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct vv_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_DATA); if (m == NULL) { error = ENOBUFS; goto bad; } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct vv_header); } else { m->m_off -= sizeof (struct vv_header); m->m_len += sizeof (struct vv_header); } 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;{ struct ifaddr *ifa = (struct ifaddr *) data; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) vvinit(ifp->if_unit); /* * Did self-test succeed? */ if ((ifp->if_flags & IFF_UP) == 0) error = ENETDOWN; /* * 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) != vv_softc[ifp->if_unit].vs_host) error = EADDRNOTAVAIL; break; } break; default: error = EINVAL; } 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -