📄 if_pn.c
字号:
* There is a problem with Proteon's software address * override so the address returned from the first * broadcast message after powerup may be wrong. */ ignorexmt = FALSE; continue; } /* copy out the rcv pkt from RBUFFER to rbuf */ msg = msgStart; for (pktsz = 0; pktsz < PNBUFSIZE && pktsz < (addr->pn_ctl.rcntr >> 1); pktsz++) { *msg++ = addr->pn_rbuffer [pktsz]; } addr->pn_ctl.rstcntr = 0; /* clear CNTR */ v = (struct pn_header *) msgStart; /* proper message type */ if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { if (shost == 0) { shost = v->vh_shost & 0xff; ((struct pn_header *)(vs->vs_tbuf))->vh_dhost = shost; } successes++; } else failures++; v->vh_type = 0; /* zap it out so we can check again */ } if (failures >= PNIDENTRETRY) { if (flg) { printf("pn%d: failed self-test after %d tries in %s mode\n", unit, PNIDENTRETRY, ix == 0 ? "digital loopback" : (ix == 1 ? "analog loopback" : "network")); printf("pn%d: rstatr = %#x, rcsr = %#x, tcsr = %#x\n", unit, 0x7 & addr->pn_ctl.rstatr, /*PN_SBITS,*/ 0xffff & addr->pn_ctl.rcsr/*, PN_RBITS*/, 0xffff & addr->pn_ctl.tcsr/*, PN_TBITS*/); } addr->pn_ctl.rcsr = PN_RST; /* kill the sick board */ addr->pn_ctl.tcsr = PN_RST; free ((char *) msgStart); return (0); } } free ((char *) msgStart); return (shost); }/********************************************************************************* pnstart - start or restart output on interface** If interface active, then a retransmit, just restuff registers and go.* If interface not already active, get another datagram off the interface* queue, copy to buffer and send it.*/LOCAL VOID pnstart (unit) int unit; { int s; FAST struct mbuf *m; FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; /* active? */ if (vs->vs_oactive) { addr->pn_ctl.tbufad = vs->vs_ostrt; /* retransmit */ goto restart; } /* not active, try dequeueing a new message */ s = splimp(); IF_DEQUEUE(&vs->vs_if.if_snd, m); splx (s); /* any message? */ if (m == NULL) { vs->vs_oactive = 0; return; } /* prepare to send */ vs->vs_olen = filltbuf (unit, vs->vs_tbuf, m); m_freem (m);restart : /* make sure this packet will fit in the interface */ if (vs->vs_olen > PNBUFSIZE) { printf ("pn%d: vs_olen: %d > PNBUFSIZE\n", unit, vs->vs_olen); panic ("pnstart: vs_olen botch"); } vs->vs_if.if_timer = PNTIMEOUT; vs->vs_oactive = 1; /* supposed to setup for 82258 transmit dma here */ if (addr->pn_ctl.tcsr & PN_NOK) vs->vs_init++; /* count ring inits */ addr->pn_ctl.tcsr = PN_IEN | PN_INI | PN_ORI; }/********************************************************************************* pnwatchdog -** Transmit watchdog timer routine. This routine gets called when we lose* a transmit interrupt. The best we can do is try to restart output.*/LOCAL VOID pnwatchdog (unit) int unit; { FAST int s; FAST struct pn_softc *vs = &pn_softc[unit]; pnprintf("pn%d: lost a transmit interrupt.\n", unit); vs->vs_timeouts++; s = splimp (); pnstart (unit); splx (s); }/********************************************************************************* pnxint - transmit interrupt** Start new output if more data available.*/LOCAL VOID pnxint (unit) int unit; { FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; FAST int tcsr = addr->pn_ctl.tcsr & 0xffff; vs->vs_if.if_timer = 0; addr->pn_ctl.tcsr = PN_RTI; /* clear/reset the interrupt */ if (vs->vs_oactive == 0) { pnprintf("pn%d: stray interrupt tcsr = %#x\n", unit, tcsr/*,PN_TBITS*/); return; } /* retransmit on soft error. * TODO: sort retransmits to end of queue if possible */ if (tcsr & (PN_TMO | PN_REF)) { if (vs->vs_tries++ < PNRETRY) { if (tcsr & PN_TMO) vs->vs_otimeout++; if (tcsr & PN_REF) { vs->vs_if.if_collisions++; vs->vs_refused++; } pnstart (unit); /* restart this message */ return; } } vs->vs_if.if_opackets++; vs->vs_oactive = 0; vs->vs_tries = 0; if (tcsr & PNTERR) { vs->vs_if.if_oerrors++; pnprintf ("pn%d: error tcsr = %#x\n", unit, tcsr/*, PN_TBITS*/); } pnstart (unit); }/********************************************************************************* pnrint - receive interrupt** First, stash data on packet just received. Then* swap receive buffers and start a new receive. Now! Then check error* status of packet. Then undo trailers, examine the packet, and pass it* on the the appropriate higher protocol.*/LOCAL VOID pnrint (unit, rcsr, rstatr, rcntr) int unit; FAST int rcsr; /* this is the current input CSR */ FAST int rstatr; /* ditto here as status register */ int rcntr; { FAST struct pn_header *pn; FAST struct mbuf *m; struct ifqueue *inq; int len; int s; FAST int off; int type; short resid; /* this is the current residual */ int index; FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; vs->vs_if.if_ipackets++; /* save device registers, as we are restarting * (note rcsr saved it initial interrupt time) */ if (rcntr < vs->rcvhd) len = RBUFSIZE - vs->rcvhd + rcntr; else len = rcntr - vs->rcvhd; /* only 14 addr bits */ len -= sizeof (struct pn_header); /* but remove local net hdr len */ /* get a pointer to packet in RBUFFER */ index = vs->rcvhd; pn = (struct pn_header *)&(addr->pn_rbuffer[index >> 1]); pntracehdr ("rint", pn, 1); vs->rcvhd = (rcntr + 3) & 0x3ffc; /* blk addr of next pkt */ if (! (vs->vs_if.if_flags & IFF_UP)) { pnprintf ("pn%d: not up!\n", unit); return; } /* Now that a new receive has been started, do the processing * on the old packet (bufno) */ if (rstatr & PNRERR) { pnprintf("pn%d: receive error, rcsr = %#x, rstatr = %#x\n", unit, rcsr, rstatr); if (rstatr & RBDF) vs->vs_ibadf++; goto dropit; } if (rcsr & PN_PER) { /* don't have to clear it because the recieve command * above wrote 0 to the parity bit */ vs->vs_parity++; /* Only on 10 megabit proNET is PN_PER 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 PN_BDF. */ if (!IS_80) goto dropit; } /* fundamental length check */ if ((rstatr & ROVR) || (len > PNMRU) || (len <= 0)) { pnprintf( "pn%d: len too long or short, len = %d, rcsr = %#x, rstatr = %#x\n", unit, len, rcsr, /*PN_RBITS,*/ rstatr/*, PN_SBITS*/); goto dropit; } /* check the protocol header version */ if (pn->vh_version != RING_VERSION) { pnprintf("pn%d: bad protocol header version %d\n", unit, pn->vh_version & 0xff); goto dropit; } /* untested trailer handling -- taken straight from VAX code */ off = 0;#define pndataaddr(pn, off, type) ((type)(((caddr_t)((pn)+1)+(off)))) if (pn->vh_type >= RING_IPTrailer && pn->vh_type < RING_IPTrailer+RING_IPNTrailer) { off = (pn->vh_type - RING_IPTrailer) * 512; if (off > PNMTU) { pnprintf("pn%d: off > PNMTU, off = %d, rcsr = %#x\n", unit, off, rcsr/*, PN_RBITS*/); goto dropit; } pn->vh_type = ntohs(*pndataaddr(pn, off, u_short *)); resid = ntohs(*pndataaddr(pn, 2+off, u_short *)); /* 2+off -> better code */ if (off + resid > len) { pnprintf ("pn%d: trailer packet too short\n", unit); pnprintf ("pn%d: len=%d, off=%d, resid=%d, rcsr=%#x, rstatr=%#x\n", unit, len, off, resid, rcsr/*, PN_RBITS*/, rstatr/*, PN_SBITS*/); goto dropit; } len = off + resid; } if (len == 0) { pnprintf("pn%d: len is zero, rcsr = %#x, rstatr = %#x\n", unit, rcsr/*, PN_RBITS*/, rstatr/*, PN_SBITS*/); goto dropit; } /* save packet type for later demux */ type = pn->vh_type & 0xff; /* Copy buffer into mbuf chain, without net header. * Could wait until type is o.k., but almost certainly is so why wait * Note that this part of the code runs SLOW, which is why the * multiple receive buffers are used. It still must be reckoned * that the keyboard is still locked out... */ m = emptyrbuf (unit, addr, index, len, off, sizeof(struct pn_header), &vs->vs_if); if (m == 0) /* success? */ goto dropit; /* remove trailer header length header */ if (off) { struct ifnet *ifp; ifp = *(mtod (m, struct ifnet **)); m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); *(mtod (m, struct ifnet **)) = ifp; } /* demultiplex on packet type */ switch (type) {#ifdef INET case RING_IP: inq = &ipintrq; s = splimp (); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem (m); } else IF_ENQUEUE(inq, m); splx (s); netJobAdd (ipintr, 0); break;#endif default: pnprintf ("pn%d: unknown pkt type %#x\n", unit, type); m_freem (m); } return; /* next packet receive is already started */dropit : /* drop packet on floor -- count them!! */ pnprintf ("pn%d: dropped it!\n", unit); vs->vs_if.if_ierrors++; }/********************************************************************************* pnoutput -** RETURNS: 0 if OK, otherwise UNIX errno*/LOCAL VOID pnoutput (ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; { FAST struct pn_header *pn; FAST int s; int type; int dest; int error; u_short info = 0; FAST struct mbuf *m = m0; FAST int unit = ifp->if_unit; FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; switch (dst->sa_family) {#ifdef INET case AF_INET: dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; /* * Take the local net address part of the address, * and use it as node number. This is not exactly * kosher under some circumstances, but I'll let it fly. */ if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { pnprintf("pn%d: can't do af%d\n", unit, dst->sa_family); error = EPERM; goto bad; } type = RING_IP; /* NO TRAILERS OUTBOUND */ break;#endif default: pnprintf("pn%d: can't handle af%d\n", unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; } /* add local net header. If no space in first mbuf, allocate another */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct pn_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_HEADER); if (m == (struct mbuf *)0) { error = ENOBUFS; goto bad; } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct pn_header); } else { m->m_off -= sizeof (struct pn_header); m->m_len += sizeof (struct pn_header); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -