📄 if_wi.c
字号:
id = CSR_READ_2(sc, WI_RX_FID); /* * if we have the procframe flag set, disregard all this and just * read the data from the device. */ if (sc->wi_procframe || sc->wi_debug.wi_monitor) { struct wi_frame *rx_frame; int datlen, hdrlen; /* first allocate mbuf for packet storage */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { ifp->if_ierrors++; return; } MCLGET(m, M_DONTWAIT); if (!(m->m_flags & M_EXT)) { m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.rcvif = ifp; /* now read wi_frame first so we know how much data to read */ if (wi_read_data(sc, id, 0, mtod(m, caddr_t), sizeof(struct wi_frame))) { m_freem(m); ifp->if_ierrors++; return; } rx_frame = mtod(m, struct wi_frame *); switch ((rx_frame->wi_status & WI_STAT_MAC_PORT) >> 8) { case 7: switch (rx_frame->wi_frame_ctl & WI_FCTL_FTYPE) { case WI_FTYPE_DATA: hdrlen = WI_DATA_HDRLEN; datlen = rx_frame->wi_dat_len + WI_FCS_LEN; break; case WI_FTYPE_MGMT: hdrlen = WI_MGMT_HDRLEN; datlen = rx_frame->wi_dat_len + WI_FCS_LEN; break; case WI_FTYPE_CTL: /* * prism2 cards don't pass control packets * down properly or consistently, so we'll only * pass down the header. */ hdrlen = WI_CTL_HDRLEN; datlen = 0; break; default: device_printf(sc->dev, "received packet of " "unknown type on port 7\n"); m_freem(m); ifp->if_ierrors++; return; } break; case 0: hdrlen = WI_DATA_HDRLEN; datlen = rx_frame->wi_dat_len + WI_FCS_LEN; break; default: device_printf(sc->dev, "received packet on invalid " "port (wi_status=0x%x)\n", rx_frame->wi_status); m_freem(m); ifp->if_ierrors++; return; } if ((hdrlen + datlen + 2) > MCLBYTES) { device_printf(sc->dev, "oversized packet received " "(wi_dat_len=%d, wi_status=0x%x)\n", datlen, rx_frame->wi_status); m_freem(m); ifp->if_ierrors++; return; } if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen, datlen + 2)) { m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = hdrlen + datlen; ifp->if_ipackets++; /* Handle BPF listeners. */ BPF_MTAP(ifp, m); m_freem(m); } else { struct wi_frame rx_frame; /* First read in the frame header */ if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { ifp->if_ierrors++; return; } if (rx_frame.wi_status & WI_STAT_ERRSTAT) { ifp->if_ierrors++; return; } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { ifp->if_ierrors++; return; } MCLGET(m, M_DONTWAIT); if (!(m->m_flags & M_EXT)) { m_freem(m); ifp->if_ierrors++; return; } eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; if (rx_frame.wi_status == WI_STAT_MGMT && sc->wi_ptype == WI_PORTTYPE_HOSTAP) { if ((WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len + 2) > MCLBYTES) { device_printf(sc->dev, "oversized mgmt packet " "received in hostap mode " "(wi_dat_len=%d, wi_status=0x%x)\n", rx_frame.wi_dat_len, rx_frame.wi_status); m_freem(m); ifp->if_ierrors++; return; } /* Put the whole header in there. */ bcopy(&rx_frame, mtod(m, void *), sizeof(struct wi_frame)); if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW, mtod(m, caddr_t) + WI_802_11_OFFSET_RAW, rx_frame.wi_dat_len + 2)) { m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len; /* XXX: consider giving packet to bhp? */ wihap_mgmt_input(sc, &rx_frame, m); return; } if (rx_frame.wi_status == WI_STAT_1042 || rx_frame.wi_status == WI_STAT_TUNNEL || rx_frame.wi_status == WI_STAT_WMP_MSG) { if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { device_printf(sc->dev, "oversized packet received " "(wi_dat_len=%d, wi_status=0x%x)\n", rx_frame.wi_dat_len, rx_frame.wi_status); m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = rx_frame.wi_dat_len + WI_SNAPHDR_LEN;#if 0 bcopy((char *)&rx_frame.wi_addr1, (char *)&eh->ether_dhost, ETHER_ADDR_LEN); if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { bcopy((char *)&rx_frame.wi_addr2, (char *)&eh->ether_shost, ETHER_ADDR_LEN); } else { bcopy((char *)&rx_frame.wi_addr3, (char *)&eh->ether_shost, ETHER_ADDR_LEN); }#else bcopy((char *)&rx_frame.wi_dst_addr, (char *)&eh->ether_dhost, ETHER_ADDR_LEN); bcopy((char *)&rx_frame.wi_src_addr, (char *)&eh->ether_shost, ETHER_ADDR_LEN);#endif bcopy((char *)&rx_frame.wi_type, (char *)&eh->ether_type, ETHER_TYPE_LEN); if (wi_read_data(sc, id, WI_802_11_OFFSET, mtod(m, caddr_t) + sizeof(struct ether_header), m->m_len + 2)) { m_freem(m); ifp->if_ierrors++; return; } } else { if((rx_frame.wi_dat_len + sizeof(struct ether_header)) > MCLBYTES) { device_printf(sc->dev, "oversized packet received " "(wi_dat_len=%d, wi_status=0x%x)\n", rx_frame.wi_dat_len, rx_frame.wi_status); m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = rx_frame.wi_dat_len + sizeof(struct ether_header); if (wi_read_data(sc, id, WI_802_3_OFFSET, mtod(m, caddr_t), m->m_len + 2)) { m_freem(m); ifp->if_ierrors++; return; } } ifp->if_ipackets++; if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { /* * Give host AP code first crack at data * packets. If it decides to handle it (or * drop it), it will return a non-zero. * Otherwise, it is destined for this host. */ if (wihap_data_input(sc, &rx_frame, m)) return; } /* Receive packet. */#ifdef WICACHE wi_cache_store(sc, eh, m, rx_frame.wi_q_info);#endif (*ifp->if_input)(ifp, m); }}static voidwi_txeof(sc, status) struct wi_softc *sc; int status;{ struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; if (status & WI_EV_TX_EXC) ifp->if_oerrors++; else ifp->if_opackets++; return;}static voidwi_inquire(xsc) void *xsc;{ struct wi_softc *sc; struct ifnet *ifp; int s; sc = xsc; ifp = &sc->arpcom.ac_if; sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); /* Don't do this while we're transmitting */ if (ifp->if_flags & IFF_OACTIVE) return; WI_LOCK(sc, s); wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0); WI_UNLOCK(sc, s); return;}static voidwi_update_stats(sc) struct wi_softc *sc;{ struct wi_ltv_gen gen; u_int16_t id; struct ifnet *ifp; u_int32_t *ptr; int len, i; u_int16_t t; ifp = &sc->arpcom.ac_if; id = CSR_READ_2(sc, WI_INFO_FID); wi_read_data(sc, id, 0, (char *)&gen, 4); /* * if we just got our scan results, copy it over into the scan buffer * so we can return it to anyone that asks for it. (add a little * compatibility with the prism2 scanning mechanism) */ if (gen.wi_type == WI_INFO_SCAN_RESULTS) { sc->wi_scanbuf_len = gen.wi_len; wi_read_data(sc, id, 4, (char *)sc->wi_scanbuf, sc->wi_scanbuf_len * 2); return; } else if (gen.wi_type != WI_INFO_COUNTERS) return; len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; ptr = (u_int32_t *)&sc->wi_stats; for (i = 0; i < len - 1; i++) { t = CSR_READ_2(sc, WI_DATA1);#ifdef WI_HERMES_STATS_WAR if (t > 0xF000) t = ~t & 0xFFFF;#endif ptr[i] += t; } ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + sc->wi_stats.wi_tx_multi_retries + sc->wi_stats.wi_tx_retry_limit; return;}static voidwi_intr(xsc) void *xsc;{ struct wi_softc *sc = xsc; struct ifnet *ifp; u_int16_t status; int s; WI_LOCK(sc, s); ifp = &sc->arpcom.ac_if; if (sc->wi_gone || !(ifp->if_flags & IFF_UP)) { CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); CSR_WRITE_2(sc, WI_INT_EN, 0); WI_UNLOCK(sc, s); return; } /* Disable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, 0); status = CSR_READ_2(sc, WI_EVENT_STAT); CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); if (status & WI_EV_RX) { wi_rxeof(sc); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); } if (status & WI_EV_TX) { wi_txeof(sc, status); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); } if (status & WI_EV_ALLOC) { int id; id = CSR_READ_2(sc, WI_ALLOC_FID); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); if (id == sc->wi_tx_data_id) wi_txeof(sc, status); } if (status & WI_EV_INFO) { wi_update_stats(sc); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } if (status & WI_EV_TX_EXC) { wi_txeof(sc, status); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); } if (status & WI_EV_INFO_DROP) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); } /* Re-enable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); if (ifp->if_snd.ifq_head != NULL) { wi_start(ifp); } WI_UNLOCK(sc, s); return;}static intwi_cmd(sc, cmd, val0, val1, val2) struct wi_softc *sc; int cmd; int val0; int val1; int val2;{ int i, s = 0; static volatile int count = 0; if (count > 1) panic("Hey partner, hold on there!"); count++; /* wait for the busy bit to clear */ for (i = 500; i > 0; i--) { /* 5s */ if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { break; } DELAY(10*1000); /* 10 m sec */ } if (i == 0) { device_printf(sc->dev, "wi_cmd: busy bit won't clear.\n" ); count--; return(ETIMEDOUT); } CSR_WRITE_2(sc, WI_PARAM0, val0); CSR_WRITE_2(sc, WI_PARAM1, val1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -