📄 if_pn.c
字号:
pn = mtod (m, struct pn_header *); pn->vh_shost = in_lnaof ( ((struct arpcom *)ifp)->ac_ipaddr); if (pn->vh_shost == 0) { panic ("pnoutput: interface not found in in_ifaddr\n"); error = EPERM; goto bad; } /* map the destination address if it's a broadcast */ if ((pn->vh_dhost = dest) == INADDR_ANY) pn->vh_dhost = PN_BROADCAST; pn->vh_version = RING_VERSION; pn->vh_type = type; pn->vh_info = htons (info); /* this gets changed if testing packets */ /* queue packet, and if interface not active, send */ 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) pnstart (unit); splx (s); return (0);qfull : m0 = m; splx (s);bad : m_freem (m0); return (error); }/********************************************************************************* pnioctl -*/LOCAL VOID pnioctl (ifp, cmd, data) FAST struct ifnet *ifp; int cmd; caddr_t data; { FAST struct sockaddr *sin; FAST struct ifaddr *ifa = (struct ifaddr *)data; int error = 0; FAST int s = splimp(); switch (cmd) { case SIOCSIFADDR: sin = (struct sockaddr *)data; if (sin->sa_family != AF_INET) { error = EINVAL; break; } pnsetaddr(ifp, (struct sockaddr_in *)sin); /* store the internet address in arpcom */ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; if (!(ifp->if_flags & IFF_RUNNING)) { pninit (ifp->if_unit); if ((ifp->if_flags & IFF_UP) == 0) error = ENETDOWN; /* self test failed, give error */ } break; case SIOCSIFFLAGS: /* not implemented (set interface up/down) */ default: error = EINVAL; break; } splx (s); return (error); }/********************************************************************************* pnsetaddr - set pronet address** set up the address for this interface. Uses the network number* from the passed address and an invalid host number.* pnidentify figures out and inserts real host address later.*/LOCAL VOID pnsetaddr (ifp, sin) FAST struct ifnet *ifp; FAST struct sockaddr_in *sin; { FAST struct pn_softc *vs = &pn_softc[ifp->if_unit]; FAST struct pn_regs *addr = vs->pn_regs; int lna = in_lnaof (((struct sockaddr_in *)sin)->sin_addr); /* set the board's host number, overriding the hardware address */ if (IS_80) addr->pn_ctl.rbufdmaptr = 0xc000 | lna; }/********************************************************************************* pnrcsrintr - rcv csr intr handler*/LOCAL VOID pnrcsrintr (unit) int unit; { int csr; int rstatr; int rcntr; FAST struct pn_regs *addr = pn_softc[unit].pn_regs; if ((addr->pn_ctl.rcsr & (PN_IRQ|PN_RDY)) != (PN_IRQ|PN_RDY)) logMsg ("proNET: rcv csr vector number clash!\n"); else { csr = addr->pn_ctl.rcsr & 0xffff; rstatr = addr->pn_ctl.rstatr & 0x7; rcntr = addr->pn_ctl.rcntr & 0x3fff; netJobAdd (pnrint, unit, csr, rstatr, rcntr); } addr->pn_ctl.rcsr = PN_IEN | PN_MEN | PN_JNR | PN_RTI | PN_CEN; addr->pn_ctl.rstcntr = 0; /* get ready for next pkt */ }/********************************************************************************* pntcsrintr - xmt csr intr handler*/LOCAL VOID pntcsrintr (unit) FAST 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; FAST int rfsreg = addr->pn_ctl.rfsreg & 0xffff; sysBusIntAck (vs->pnIntLevel); if ((tcsr & (PN_IRQ|PN_RDY)) != (PN_IRQ|PN_RDY)) { pnprintf("proNET: xmt csr vector number clash!\n"); logMsg ("tcsr = %#x\n", addr->pn_ctl.tcsr ); if ((addr->pn_ctl.tcsr & (PN_IRQ)) != (PN_IRQ)) logMsg ("PN_IRQ not on\n"); if ((addr->pn_ctl.tcsr & (PN_RDY)) != (PN_RDY)) logMsg ("PN_RDY not on\n"); addr->pn_ctl.tcsr = PN_RTI; /* clear/reset the interrupt */ } else { /* should call pnxint() here, but duplicated here for speed */ 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 & PNTERR) { if (vs->vs_tries++ < PNRETRY) { /* re-order refused bits and cancel the "any": * what's wrong here? * * rfsreg = ((rfsreg >> 9) & 0x7f) | ((rfsreg & 0xff) << 7); */ if (tcsr & PN_TMO) { vs->vs_otimeout++; pnprintf ("pntcsrintr: RESTART (TIMEOUT) %#x\n", rfsreg); } if (tcsr & PN_REF) { vs->vs_if.if_collisions++; vs->vs_refused++; pnprintf ("pntcsrintr: RESTART (refused) %#x\n", rfsreg); } if (tcsr & PN_BDF) { pnprintf ("pntcsrintr: RESTART (bad form) %#x\n", rfsreg); } /* doesn't need to be at task level, 'cuz we're restarting */ pnstart (unit); 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*/); } /* let's only call pnstart if there are messages in the output queue */ if (vs->vs_if.if_snd.ifq_len > 0) netJobAdd (pnstart, unit); } }/********************************************************************************* filltbuf -** takes a chain of mbufs and copies the chain into a buffer.* returns the number of bytes put into the buffer. if board is* not swabbing it also swabs the bytes. does not free mbuf chain.** RETURNS: number of bytes filled*/LOCAL int filltbuf (unit, buf, mchain) int unit; caddr_t buf; struct mbuf *mchain; { FAST u_long *tbufda; FAST struct mbuf *m; BOOL odd = FALSE; int len = 0; struct pn_softc *vs = &pn_softc[unit]; struct pn_regs *addr = vs->pn_regs; /* sum mbuf chain, and check for odd length mbuf's */ for (m = mchain; m != NULL; m = m->m_next) { if (m->m_len & 0x1 || m->m_off & 0x1) odd = TRUE; len += m->m_len; } tbufda = (u_long*)&addr->pn_ctl.tbufda; vs->vs_ostrt = (TBUFSIZE - ((len + 3) >> 2)) & 0x3ff; addr->pn_ctl.tbufad = vs->vs_ostrt; m = mchain; if (odd) { caddr_t bpend; FAST caddr_t bp = buf; /* double buffering! however this code probably never runs */ for (; m != NULL; m = m->m_next) { pncopy (mtod (m, caddr_t), bp, m->m_len); bp += m->m_len; } bpend = bp; for (bp = buf; bp < bpend; bp += 4) *tbufda = *(u_long *)bp; } else { int flag = 0; for (; m != NULL; m = m->m_next) flag = movep (mtod (m, u_long *), tbufda, m->m_len, flag); } addr->pn_ctl.tbufad = vs->vs_ostrt; return (len); }/********************************************************************************* emptyrbuf - empty a buffer into a chain of mbufs** This routine is admitted to be hard to understand. It is doing three* things at once: copying the buffer, moving IP trailers to the front of* the packet and skipping the ring header.** NOTE:* IP trailers part is not tested.** RETURNS: the start of the chain, or 0 if error** ARGSUSED*/LOCAL struct mbuf *emptyrbuf (unit, addr, pktad, totlen, off0, skip, ifp) int unit; /* unit number */ struct pn_regs *addr; /* device address */ int pktad; /* index of pkt in RBUFFER */ FAST int totlen; /* bytes to copy */ int off0; /* trailer offset */ int skip; /* header length */ struct ifnet *ifp; { FAST int len; FAST struct mbuf *m; struct mbuf *top = (struct mbuf *) 0; FAST struct mbuf **mp = ⊤ int off = off0; /* assuming off = 0, ie. no trailers */ int index = ((pktad + skip) >> 1) & 0x1fff; /* word array index */ FAST caddr_t bp = (caddr_t)&addr->pn_rbuffer[index]; pntracehdr ("input", (struct pn_header *)&(addr->pn_rbuffer[pktad>>1]), 1); while (totlen > 0) { MGET(m,M_DONTWAIT,MT_DATA); if (m == (struct mbuf *)0) { if (top != (struct mbuf *)0) m_freem (top); return ((struct mbuf *)0); } if (off) { len = totlen - off; index = ((pktad + off + skip) >> 1) & 0x1fff; bp = (caddr_t)&(addr->pn_rbuffer[index]); } else len = totlen; m->m_off = MMINOFF; if (ifp) { /* Leave room for ifp */ m->m_len = MIN(MLEN - sizeof(ifp), len); m->m_off += sizeof(ifp); } else m->m_len = MIN(MLEN, len); m->m_next = (struct mbuf *)0; if ((index << 1) + m->m_len >= RBUFSIZE) { caddr_t tp = mtod (m, caddr_t); int cut = RBUFSIZE - (index << 1); pncopy(bp,tp,cut); pncopy((caddr_t)addr->pn_rbuffer,tp+cut,m->m_len-cut); index = (m->m_len - cut) >> 1; bp = (caddr_t)&(addr->pn_rbuffer[index]); } else { pncopy(bp, mtod (m,caddr_t), m->m_len); index += (m->m_len >> 1); bp += m->m_len; } *mp = m; mp = &m->m_next; if (off) { off += m->m_len; if (off == totlen) { index = ((pktad + skip) >> 1) & 0x1fff; bp = (caddr_t)&(addr->pn_rbuffer[index]); off = 0; totlen = off0; } } else totlen -= m->m_len; if (ifp) { /* prepend interface pointer to first mbuf */ m->m_len += sizeof(ifp); m->m_off -= sizeof(ifp); *(mtod (m, struct ifnet **)) = ifp; ifp = (struct ifnet *)0; } } return (top); }/* debugging aid printout routines *//********************************************************************************* pnprt_hdr - print the local net header in "v" with title "s"*/LOCAL VOID pnprt_hdr (s, v, nl) char *s; FAST struct pn_header *v; int nl; { printf ("%10s @ %#10x: d=%#x s=%#x v=%#x t=%#x i=%#x", s, v, 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)); if (nl) printf("\n"); }/********************************************************************************* pn_errors - print error statistics and zero*/VOID pn_errors (unit) { FAST struct pn_softc *vs = &pn_softc[unit]; printf ("oerrors = %d", vs->vs_if.if_oerrors); vs->vs_if.if_oerrors = 0; printf ("otimeout = %d", vs->vs_otimeout); vs->vs_otimeout = 0; printf ("collisions = %d", vs->vs_if.if_collisions); vs->vs_if.if_collisions = 0; printf ("refused = %d", vs->vs_refused); vs->vs_refused = 0; }BOOL xmovep (from, to, len) short *from; short *to; int len; { while (len -= 2) *to = *from++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -