📄 if_ex.c
字号:
cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */ /* * Set up message queues and headers. * First the request queue. */ for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); bp->mb_rsrv = 0; bp->mb_length = MBDATALEN; bp->mb_status = MH_HOST; bp->mb_next = bp+1; } xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit); xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; /* Now the reply queue. */ for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); bp->mb_rsrv = 0; bp->mb_length = MBDATALEN; bp->mb_status = MH_EXOS; bp->mb_next = bp+1; } xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit); xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; /* * Write config msg address to EXOS and wait for * configuration to complete (guaranteed response * within 2 seconds). */ shiftreg = (u_long)0x0000FFFF; for (i = 0; i < 8; i++) { if (i == 4) shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit); while (addr->xd_portb & EX_UNREADY) ; addr->xd_portb = (u_char)(shiftreg & 0xFF); shiftreg >>= 8; } for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i); if (cm->cm_cc) printf("ex%d: configuration failed; cc = %x\n", unit, cm->cm_cc);}/* * Start or re-start output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. * This routine is called by exinit(), ether_output(), and excdint(). * In all cases, interrupts by EXOS are disabled. */exstart(ifp)struct ifnet *ifp;{ int unit = ifp->if_unit; struct uba_device *ui = exinfo[unit]; register struct ex_softc *xs = &ex_softc[unit]; register struct exdevice *addr = (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; struct mbuf *m; int len;#ifdef DEBUG if (xs->xs_if.if_flags & IFF_OACTIVE) panic("exstart(): xmit still pending");#endif IF_DEQUEUE(&xs->xs_if.if_snd, m); if (m == 0) return (0); len = if_wubaput(&xs->xs_ifuba, m); if (len - sizeof(struct ether_header) < ETHERMIN) len = ETHERMIN + sizeof(struct ether_header); /* * Place a transmit request. */ bp = exgetcbuf(xs); bp->mb_rqst = LLRTRANSMIT; bp->mb_et.et_nblock = 1; bp->mb_et.et_blks[0].bb_len = (u_short)len; *(u_long *)bp->mb_et.et_blks[0].bb_addr = UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info); xs->xs_if.if_flags |= IFF_OACTIVE; bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT; return (0);}/* * Command done interrupt. */excdint(unit) int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp = xs->xs_x2hnext; struct uba_device *ui = exinfo[unit]; struct exdevice *addr = (struct exdevice *)ui->ui_addr; while ((bp->mb_status & MH_OWNER) == MH_HOST) { switch (bp->mb_rqst) { case LLRECEIVE: exrecv(unit, bp); exhangrcv(unit); break; case LLRTRANSMIT:#ifdef DEBUG if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0) panic("exxmit: no xmit pending");#endif xs->xs_if.if_flags &= ~IFF_OACTIVE; xs->xs_if.if_opackets++; if (bp->mb_rply == LL_OK) { ; } else if (bp->mb_rply & LLXM_1RTRY) { xs->xs_if.if_collisions++; } else if (bp->mb_rply & LLXM_RTRYS) { xs->xs_if.if_collisions += 2; /* guess */ } else if (bp->mb_rply & LLXM_ERROR) { xs->xs_if.if_oerrors++; log(LOG_ERR, "ex%d: transmit error=%b\n", unit, bp->mb_rply, XMIT_BITS); } if (xs->xs_ifuba.ifu_xtofree) { m_freem(xs->xs_ifuba.ifu_xtofree); xs->xs_ifuba.ifu_xtofree = 0; } (void) exstart(&xs->xs_if); break; case LLNET_STSTCS: xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc; xs->xs_flags &= ~EX_STATPENDING; break; case LLNET_ADDRS: case LLNET_RECV: break;#ifdef DEBUG default: panic("ex%d: unknown reply");#endif } /* end of switch */ bp->mb_length = MBDATALEN; bp->mb_status |= MH_EXOS; /* free up buffer */ addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next; }}/* * Get a request buffer, fill in standard values, advance pointer. */struct ex_msg *exgetcbuf(xs) struct ex_softc *xs;{ register struct ex_msg *bp = xs->xs_h2xnext;#ifdef DEBUG if ((bp->mb_status & MH_OWNER) == MH_EXOS) panic("exgetcbuf(): EXOS owns message buffer");#endif bp->mb_1rsrv = 0; bp->mb_length = MBDATALEN; xs->xs_h2xnext = xs->xs_h2xnext->mb_next; return bp;}/* * Process Ethernet receive completion: * 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. */exrecv(unit, bp) int unit; register struct ex_msg *bp;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ether_header *eh; struct mbuf *m; register int len, off, resid; register struct ifqueue *inq; int s; xs->xs_if.if_ipackets++; len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; if (bp->mb_rply != LL_OK) { xs->xs_if.if_ierrors++; log(LOG_ERR, "ex%d: receive error=%b\n", unit, bp->mb_rply, RECV_BITS); return; } eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr); /* * Deal with trailer protocol: if type is trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ eh->ether_type = ntohs((u_short)eh->ether_type);#define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) if (eh->ether_type >= ETHERTYPE_TRAIL && eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len == 0) return; /* * 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, but we still have to drop * the type and length which are at the front of any trailer data. */ m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if); if (m == 0) return; ether_input(&xs->xs_if, eh, m);}/* * Send receive request to EXOS. * This routine is called by exinit and excdint, * with interrupts disabled in both cases. */exhangrcv(unit) int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp = exgetcbuf(xs); struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr; bp->mb_rqst = LLRECEIVE; bp->mb_er.er_nblock = 1; bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; *(u_long *)bp->mb_er.er_blks[0].bb_addr = UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info); bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT;}/* * Watchdog routine - place stats request to EXOS * (This could be dispensed with, if you don't care * about the if_ierrors count, or are willing to receive * bad packets in order to derive it.) */exwatch(unit) int unit;{ struct uba_device *ui = exinfo[unit]; struct exdevice *addr = (struct exdevice *)ui->ui_addr; register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp; int s = splimp(); if (xs->xs_flags & EX_STATPENDING) goto exspnd; bp = exgetcbuf(xs); xs->xs_flags |= EX_STATPENDING; bp->mb_rqst = LLNET_STSTCS; bp->mb_ns.ns_mask = READ_OBJ; bp->mb_ns.ns_rsrv = 0; bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */ bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */ bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit); bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT;exspnd: splx(s); xs->xs_if.if_timer = EXWATCHINTVL;}/* * Process an ioctl request. */exioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct ex_softc *xs = &ex_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; exinit(ifp->if_unit); switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(xs->xs_addr); else ex_setaddr(ina->x_host.c_host,ifp->if_unit); break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && xs->xs_flags & EX_RUNNING) { ((struct exdevice *) (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET; xs->xs_flags &= ~EX_RUNNING; } else if (ifp->if_flags & IFF_UP && (xs->xs_flags & EX_RUNNING) == 0) exinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */ex_setaddr(physaddr, unit) u_char *physaddr; int unit;{ register struct ex_softc *xs = &ex_softc[unit]; if (physaddr) { xs->xs_flags |= EX_SETADDR; bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); } ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);}/* * enable multicast reception on a particular address. */ex_setmulti(linkaddr, unit, slot) u_char *linkaddr; int unit;{ register struct ex_softc *xs = &ex_softc[unit]; struct uba_device *ui = exinfo[unit]; register struct exdevice *addr= (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; if (! (xs->xs_flags & EX_RUNNING)) return; bp = exgetcbuf(xs); bp->mb_rqst = LLNET_ADDRS; bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; bp->mb_na.na_slot = slot; bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT; bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ;#ifdef DEBUG log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, (slot == PHYSSLOT ? "reset addr" : "add multicast" ether_sprintf(bp->mb_na.na_addrs), slot);#endif /* * Now, re-enable reception on slot. */ bp = exgetcbuf(xs); bp->mb_rqst = LLNET_RECV; bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; bp->mb_nr.nr_slot = slot; bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT; bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -