diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index 486df5234321..3c14e8c97c36 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -238,7 +238,7 @@ wi_attach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; int i, nrates, buflen; u_int16_t val; u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE]; @@ -266,6 +266,7 @@ wi_attach(device_t dev) MTX_DEF | MTX_RECURSE); #endif + sc->sc_firmware_type = WI_NOTYPE; sc->wi_cmd_count = 500; /* Reset the NIC. */ if (wi_reset(sc) != 0) @@ -306,10 +307,14 @@ wi_attach(device_t dev) ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); + ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_DS; ic->ic_opmode = IEEE80211_M_STA; - ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_AHDEMO; ic->ic_state = IEEE80211_S_INIT; + ic->ic_caps = IEEE80211_C_PMGT + | IEEE80211_C_WEP /* everyone supports WEP */ + ; + ic->ic_max_aid = WI_MAX_AID; /* * Query the card for available channels and setup the @@ -468,11 +473,11 @@ wi_attach(device_t dev) /* * Call MI attach routine. */ - ieee80211_ifattach(ifp); + ieee80211_ifattach(ic); /* override state transition method */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = wi_newstate; - ieee80211_media_init(ifp, wi_media_change, wi_media_status); + ieee80211_media_init(ic, wi_media_change, wi_media_status); #if NBPFILTER > 0 bpfattach2(ifp, DLT_IEEE802_11_RADIO, @@ -495,6 +500,10 @@ wi_attach(device_t dev) sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_th_len); sc->sc_rx_th.wr_ihdr.it_present = htole32(WI_RX_RADIOTAP_PRESENT); #endif + + if (bootverbose) + ieee80211_announce(ic); + return (0); } @@ -502,7 +511,7 @@ int wi_detach(device_t dev) { struct wi_softc *sc = device_get_softc(dev); - struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ifnet *ifp = &sc->sc_if; WI_LOCK_DECL(); WI_LOCK(sc); @@ -515,7 +524,7 @@ wi_detach(device_t dev) #if NBPFILTER > 0 bpfdetach(ifp); #endif - ieee80211_ifdetach(ifp); + ieee80211_ifdetach(&sc->sc_ic); WI_UNLOCK(sc); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); wi_free(dev); @@ -539,7 +548,7 @@ wi_activate(struct device *self, enum devact act) break; case DVACT_DEACTIVATE: - if_deactivate(&sc->sc_ic.ic_if); + if_deactivate(&sc->sc_if); break; } splx(s); @@ -549,7 +558,7 @@ wi_activate(struct device *self, enum devact act) void wi_power(struct wi_softc *sc, int why) { - struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ifnet *ifp = &sc->sc_if; int s; s = splnet(); @@ -585,7 +594,7 @@ void wi_intr(void *arg) { struct wi_softc *sc = arg; - struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ifnet *ifp = &sc->sc_if; u_int16_t status; WI_LOCK_DECL(); @@ -698,8 +707,9 @@ wi_init(void *arg) IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(sdl)); wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN); - wi_write_val(sc, WI_RID_PM_ENABLED, - (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); + if (ic->ic_caps & IEEE80211_C_PMGT) + wi_write_val(sc, WI_RID_PM_ENABLED, + (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); /* not yet common 802.11 configuration */ wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen); @@ -817,8 +827,8 @@ out: void wi_stop(struct ifnet *ifp, int disable) { - struct ieee80211com *ic = (struct ieee80211com *) ifp; struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; WI_LOCK_DECL(); WI_LOCK(sc); @@ -841,7 +851,6 @@ wi_stop(struct ifnet *ifp, int disable) sc->sc_tx_timer = 0; sc->sc_scan_timer = 0; - sc->sc_syn_timer = 0; sc->sc_false_syns = 0; sc->sc_naps = 0; ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); @@ -857,6 +866,7 @@ wi_start(struct ifnet *ifp) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ieee80211_frame *wh; + struct ether_header *eh; struct mbuf *m0; struct wi_frame frmhdr; int cur, fid, off, error; @@ -910,6 +920,23 @@ wi_start(struct ifnet *ifp) ifp->if_flags |= IFF_OACTIVE; break; } + if (m0->m_len < sizeof(struct ether_header) && + (m0 = m_pullup(m0, sizeof(struct ether_header))) == NULL) { + ifp->if_oerrors++; + continue; + } + eh = mtod(m0, struct ether_header *); + ni = ieee80211_find_txnode(ic, eh->ether_dhost); + if (ni == NULL) { + m_freem(m0); + continue; + } + if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && + (m0->m_flags & M_PWR_SAV) == 0) { + ieee80211_pwrsave(ic, ni, m0); + ieee80211_free_node(ni); + continue; + } ifp->if_opackets++; m_copydata(m0, 0, ETHER_HDR_LEN, (caddr_t)&frmhdr.wi_ehdr); @@ -917,30 +944,30 @@ wi_start(struct ifnet *ifp) BPF_MTAP(ifp, m0); #endif - m0 = ieee80211_encap(ifp, m0, &ni); + m0 = ieee80211_encap(ic, m0, ni); if (m0 == NULL) { ifp->if_oerrors++; + ieee80211_free_node(ni); continue; } wh = mtod(m0, struct ieee80211_frame *); - if (ic->ic_flags & IEEE80211_F_WEPON) - wh->i_fc[1] |= IEEE80211_FC1_WEP; - } #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m0); #endif frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX); - if (ic->ic_opmode == IEEE80211_M_HOSTAP && - (wh->i_fc[1] & IEEE80211_FC1_WEP)) { - if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) { - ifp->if_oerrors++; - if (ni && ni != ic->ic_bss) - ieee80211_free_node(ic, ni); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + struct ieee80211_key *k; + + k = ieee80211_crypto_encap(ic, ni, m0); + if (k == NULL) { + if (ni != NULL) + ieee80211_free_node(ni); continue; } - frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) + frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); } #if NBPFILTER > 0 if (sc->sc_drvbpf) { @@ -961,8 +988,8 @@ wi_start(struct ifnet *ifp) error = wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 || wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0; m_freem(m0); - if (ni && ni != ic->ic_bss) - ieee80211_free_node(ic, ni); + if (ni != NULL) + ieee80211_free_node(ni); if (error) { ifp->if_oerrors++; continue; @@ -986,8 +1013,7 @@ wi_start(struct ifnet *ifp) static int wi_reset(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; #define WI_INIT_TRIES 3 int i; int error = 0; @@ -1052,20 +1078,8 @@ wi_watchdog(struct ifnet *ifp) ifp->if_timer = 1; } - if (sc->sc_syn_timer) { - if (--sc->sc_syn_timer == 0) { - struct ieee80211com *ic = (struct ieee80211com *) ifp; - DPRINTF2(("wi_watchdog: %d false syns\n", - sc->sc_false_syns)); - sc->sc_false_syns = 0; - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); - sc->sc_syn_timer = 5; - } - ifp->if_timer = 1; - } - /* TODO: rate control */ - ieee80211_watchdog(ifp); + ieee80211_watchdog(&sc->sc_ic); } static int @@ -1085,12 +1099,8 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct wi_req wreq; WI_LOCK_DECL(); - WI_LOCK(sc); - - if (sc->wi_gone) { - error = ENODEV; - goto out; - } + if (sc->wi_gone) + return (ENODEV); switch (cmd) { case SIOCSIFFLAGS: @@ -1099,6 +1109,7 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) * changing is the promisc flag, try to short-circuit a call to * wi_init() by just setting PROMISC in the hardware. */ + WI_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ic->ic_opmode != IEEE80211_M_HOSTAP && ifp->if_flags & IFF_RUNNING) { @@ -1121,20 +1132,24 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sc->wi_gone = 0; } sc->sc_if_flags = ifp->if_flags; + WI_UNLOCK(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: + WI_LOCK(sc); error = wi_write_multi(sc); + WI_UNLOCK(sc); break; case SIOCGIFGENERIC: + WI_LOCK(sc); error = wi_get_cfg(ifp, cmd, data); + WI_UNLOCK(sc); break; case SIOCSIFGENERIC: error = suser(td); - if (error) - break; - error = wi_set_cfg(ifp, cmd, data); + if (error == 0) + error = wi_set_cfg(ifp, cmd, data); break; case SIOCGPRISM2DEBUG: error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); @@ -1151,32 +1166,29 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSPRISM2DEBUG: if ((error = suser(td))) - goto out; + return (error); error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); if (error) break; + WI_LOCK(sc); error = wi_set_debug(sc, &wreq); + WI_UNLOCK(sc); break; case SIOCG80211: ireq = (struct ieee80211req *) data; - switch (ireq->i_type) { - case IEEE80211_IOC_STATIONNAME: + if (ireq->i_type == IEEE80211_IOC_STATIONNAME) { ireq->i_len = sc->sc_nodelen + 1; error = copyout(sc->sc_nodename, ireq->i_data, ireq->i_len); break; - default: - error = ieee80211_ioctl(ifp, cmd, data); - break; } - break; + goto ioctl_common; case SIOCS80211: - error = suser(td); - if (error) - break; ireq = (struct ieee80211req *) data; - switch (ireq->i_type) { - case IEEE80211_IOC_STATIONNAME: + if (ireq->i_type == IEEE80211_IOC_STATIONNAME) { + error = suser(td); + if (error) + break; if (ireq->i_val != 0 || ireq->i_len > IEEE80211_NWID_LEN) { error = EINVAL; @@ -1186,32 +1198,32 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = copyin(ireq->i_data, nodename, ireq->i_len); if (error) break; + WI_LOCK(sc); if (sc->sc_enabled) { error = wi_write_ssid(sc, WI_RID_NODENAME, nodename, ireq->i_len); - if (error) - break; } - memcpy(sc->sc_nodename, nodename, IEEE80211_NWID_LEN); - sc->sc_nodelen = ireq->i_len; - break; - default: - error = ieee80211_ioctl(ifp, cmd, data); + if (error == 0) { + memcpy(sc->sc_nodename, nodename, + IEEE80211_NWID_LEN); + sc->sc_nodelen = ireq->i_len; + } + WI_UNLOCK(sc); break; } - break; + goto ioctl_common; default: - error = ieee80211_ioctl(ifp, cmd, data); + ioctl_common: + WI_LOCK(sc); + error = ieee80211_ioctl(ic, cmd, data); + if (error == ENETRESET) { + if (sc->sc_enabled) + wi_init(sc); /* XXX no error return */ + error = 0; + } + WI_UNLOCK(sc); break; } - if (error == ENETRESET) { - if (sc->sc_enabled) - wi_init(sc); /* XXX no error return */ - error = 0; - } -out: - WI_UNLOCK(sc); - return (error); } @@ -1250,23 +1262,22 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0) imr->ifm_status |= IFM_ACTIVE; len = sizeof(val); - if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0) - rate = 0; - else { + if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) == 0 && + len == sizeof(val)) { /* convert to 802.11 rate */ + val = le16toh(val); rate = val * 2; if (sc->sc_firmware_type == WI_LUCENT) { - if (rate == 4 * 2) + if (rate == 10) rate = 11; /* 5.5Mbps */ - else if (rate == 5 * 2) - rate = 22; /* 11Mbps */ } else { if (rate == 4*2) rate = 11; /* 5.5Mbps */ else if (rate == 8*2) rate = 22; /* 11Mbps */ } - } + } else + rate = 0; imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B); switch (ic->ic_opmode) { case IEEE80211_M_STA: @@ -1291,7 +1302,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid)) return; @@ -1304,7 +1315,8 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) * change-of-BSSID indications. */ if ((ifp->if_flags & IFF_PROMISC) != 0 && - sc->sc_false_syns >= WI_MAX_FALSE_SYNS) + !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns, + WI_MAX_FALSE_SYNS)) return; ieee80211_new_state(ic, IEEE80211_S_RUN, -1); @@ -1313,8 +1325,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN]) static void wi_rx_monitor(struct wi_softc *sc, int fid) { - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; struct wi_frame *rx_frame; struct mbuf *m; int datlen, hdrlen; @@ -1397,7 +1408,7 @@ static void wi_rx_intr(struct wi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; struct wi_frame frmhdr; struct mbuf *m; struct ieee80211_frame *wh; @@ -1502,13 +1513,6 @@ wi_rx_intr(struct wi_softc *sc) } #endif wh = mtod(m, struct ieee80211_frame *); - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - /* - * WEP is decrypted by hardware. Clear WEP bit - * header for ieee80211_input(). - */ - wh->i_fc[1] &= ~IEEE80211_FC1_WEP; - } /* synchronize driver's BSSID with firmware's BSSID */ dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; @@ -1518,36 +1522,25 @@ wi_rx_intr(struct wi_softc *sc) /* * Locate the node for sender, track state, and * then pass this node (referenced) up to the 802.11 - * layer for its use. We are required to pass - * something so we fallback to ic_bss when this frame - * is from an unknown sender. + * layer for its use. */ - if (ic->ic_opmode != IEEE80211_M_STA) { - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) - ni = ieee80211_ref_node(ic->ic_bss); - } else - ni = ieee80211_ref_node(ic->ic_bss); + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *) wh); /* * Send frame up for processing. */ - ieee80211_input(ifp, m, ni, rssi, rstamp); + ieee80211_input(ic, m, ni, rssi, rstamp); /* * The frame may have caused the node to be marked for * reclamation (e.g. in response to a DEAUTH message) * so use free_node here instead of unref_node. */ - if (ni == ic->ic_bss) - ieee80211_unref_node(&ni); - else - ieee80211_free_node(ic, ni); + ieee80211_free_node(ni); } static void wi_tx_ex_intr(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; struct wi_frame frmhdr; int fid; @@ -1591,8 +1584,7 @@ wi_tx_ex_intr(struct wi_softc *sc) static void wi_tx_intr(struct wi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; int fid, cur; if (sc->wi_gone) @@ -1628,7 +1620,7 @@ static void wi_info_intr(struct wi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = &sc->sc_if; int i, fid, len, off; u_int16_t ltbuf[2]; u_int16_t stat; @@ -1708,7 +1700,7 @@ wi_info_intr(struct wi_softc *sc) static int wi_write_multi(struct wi_softc *sc) { - struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ifnet *ifp = &sc->sc_if; int n; struct ifmultiaddr *ifma; struct wi_mcast mlist; @@ -1863,7 +1855,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) case WI_RID_TX_CRYPT_KEY: case WI_RID_DEFLT_CRYPT_KEYS: case WI_RID_TX_RATE: - return ieee80211_cfgget(ifp, cmd, data); + return ieee80211_cfgget(ic, cmd, data); case WI_RID_MICROWAVE_OVEN: if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) { @@ -1917,7 +1909,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) case WI_RID_READ_APS: if (ic->ic_opmode == IEEE80211_M_HOSTAP) - return ieee80211_cfgget(ifp, cmd, data); + return ieee80211_cfgget(ic, cmd, data); if (sc->sc_scan_timer > 0) { error = EINPROGRESS; break; @@ -1954,11 +1946,11 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) break; case WI_RID_READ_CACHE: - return ieee80211_cfgget(ifp, cmd, data); + return ieee80211_cfgget(ic, cmd, data); case WI_RID_SCAN_RES: /* compatibility interface */ if (ic->ic_opmode == IEEE80211_M_HOSTAP) - return ieee80211_cfgget(ifp, cmd, data); + return ieee80211_cfgget(ic, cmd, data); if (sc->sc_scan_timer > 0) { error = EINPROGRESS; break; @@ -2040,7 +2032,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_nodelen); break; default: - return ieee80211_cfgget(ifp, cmd, data); + return ieee80211_cfgget(ic, cmd, data); } break; } @@ -2060,6 +2052,7 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) struct mbuf *m; int i, len, error, mif, val; struct ieee80211_rateset *rs; + WI_LOCK_DECL(); error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); if (error) @@ -2075,20 +2068,23 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) error = ENOSPC; break; } - if (sc->sc_enabled) { + WI_LOCK(sc); + if (sc->sc_enabled) error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, len); - if (error) - break; + if (error == 0) { + sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2; + memcpy(sc->sc_nodename, &wreq.wi_val[1], + sc->sc_nodelen); } - sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2; - memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen); + WI_UNLOCK(sc); break; case WI_RID_MICROWAVE_OVEN: case WI_RID_ROAMING_MODE: case WI_RID_SYSTEM_SCALE: case WI_RID_FRAG_THRESH: + /* XXX unlocked reads */ if (wreq.wi_type == WI_RID_MICROWAVE_OVEN && (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0) break; @@ -2105,11 +2101,14 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) case WI_RID_RTS_THRESH: case WI_RID_CNFAUTHMODE: case WI_RID_MAX_DATALEN: + WI_LOCK(sc); if (sc->sc_enabled) { error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, sizeof(u_int16_t)); - if (error) + if (error != 0) { + WI_UNLOCK(sc); break; + } } switch (wreq.wi_type) { case WI_RID_FRAG_THRESH: @@ -2134,9 +2133,11 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_max_datalen = le16toh(wreq.wi_val[0]); break; } + WI_UNLOCK(sc); break; case WI_RID_TX_RATE: + WI_LOCK(sc); switch (le16toh(wreq.wi_val[0])) { case 3: ic->ic_fixed_rate = -1; @@ -2148,46 +2149,56 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) / 2 == le16toh(wreq.wi_val[0])) break; } - if (i == rs->rs_nrates) + if (i == rs->rs_nrates) { + WI_UNLOCK(sc); return EINVAL; + } ic->ic_fixed_rate = i; } if (sc->sc_enabled) error = wi_write_txrate(sc); + WI_UNLOCK(sc); break; case WI_RID_SCAN_APS: + WI_LOCK(sc); if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP) error = wi_scan_ap(sc, 0x3fff, 0x000f); + WI_UNLOCK(sc); break; case WI_RID_SCAN_REQ: /* compatibility interface */ + WI_LOCK(sc); if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP) error = wi_scan_ap(sc, wreq.wi_val[0], wreq.wi_val[1]); + WI_UNLOCK(sc); break; case WI_RID_MGMT_XMIT: - if (!sc->sc_enabled) { + WI_LOCK(sc); + if (!sc->sc_enabled) error = ENETDOWN; - break; - } - if (ic->ic_mgtq.ifq_len > 5) { + else if (ic->ic_mgtq.ifq_len > 5) error = EAGAIN; - break; + else { + /* NB: m_devget uses M_DONTWAIT so can hold the lock */ + /* XXX wi_len looks in u_int8_t, not in u_int16_t */ + m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, + ifp, NULL); + if (m != NULL) + IF_ENQUEUE(&ic->ic_mgtq, m); + else + error = ENOMEM; } - /* XXX wi_len looks in u_int8_t, not in u_int16_t */ - m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL); - if (m == NULL) { - error = ENOMEM; - break; - } - IF_ENQUEUE(&ic->ic_mgtq, m); + WI_UNLOCK(sc); break; case WI_RID_MIF: mif = wreq.wi_val[0]; val = wreq.wi_val[1]; + WI_LOCK(sc); error = wi_cmd(sc, WI_CMD_WRITEMIF, mif, val, 0); + WI_UNLOCK(sc); break; case WI_RID_PROCFRAME: /* ignore for compatibility */ @@ -2199,20 +2210,30 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) error = ENOSPC; break; } + WI_LOCK(sc); memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2; memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen); - error = ENETRESET; + if (sc->sc_enabled) + wi_init(sc); /* XXX no error return */ + WI_UNLOCK(sc); break; default: - if (sc->sc_enabled) { + WI_LOCK(sc); + if (sc->sc_enabled) error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, len); - if (error) - break; + if (error == 0) { + /* XXX ieee80211_cfgset does a copyin */ + error = ieee80211_cfgset(ic, cmd, data); + if (error == ENETRESET) { + if (sc->sc_enabled) + wi_init(sc); + error = 0; + } } - error = ieee80211_cfgset(ifp, cmd, data); + WI_UNLOCK(sc); break; } return error; @@ -2284,27 +2305,30 @@ wi_write_wep(struct wi_softc *sc) switch (sc->sc_firmware_type) { case WI_LUCENT: - val = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0; + val = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0; error = wi_write_val(sc, WI_RID_ENCRYPTION, val); if (error) break; - error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_wep_txkey); - if (error) - break; - memset(wkey, 0, sizeof(wkey)); - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - keylen = ic->ic_nw_keys[i].wk_len; - wkey[i].wi_keylen = htole16(keylen); - memcpy(wkey[i].wi_keydat, ic->ic_nw_keys[i].wk_key, - keylen); + if (ic->ic_flags & IEEE80211_F_PRIVACY) { + error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, + ic->ic_def_txkey); + if (error) + break; + memset(wkey, 0, sizeof(wkey)); + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + keylen = ic->ic_nw_keys[i].wk_keylen; + wkey[i].wi_keylen = htole16(keylen); + memcpy(wkey[i].wi_keydat, + ic->ic_nw_keys[i].wk_key, keylen); + } + error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS, + wkey, sizeof(wkey)); } - error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS, - wkey, sizeof(wkey)); break; case WI_INTERSIL: case WI_SYMBOL: - if (ic->ic_flags & IEEE80211_F_WEPON) { + if (ic->ic_flags & IEEE80211_F_PRIVACY) { /* * ONLY HWB3163 EVAL-CARD Firmware version * less than 0.8 variant2 @@ -2336,26 +2360,35 @@ wi_write_wep(struct wi_softc *sc) error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val); if (error) break; - error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY, - ic->ic_wep_txkey); - if (error) - break; - /* - * It seems that the firmware accept 104bit key only if - * all the keys have 104bit length. We get the length of - * the transmit key and use it for all other keys. - * Perhaps we should use software WEP for such situation. - */ - keylen = ic->ic_nw_keys[ic->ic_wep_txkey].wk_len; - if (keylen > IEEE80211_WEP_KEYLEN) - keylen = 13; /* 104bit keys */ - else - keylen = IEEE80211_WEP_KEYLEN; - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - error = wi_write_rid(sc, WI_RID_P2_CRYPT_KEY0 + i, - ic->ic_nw_keys[i].wk_key, keylen); + if (val & PRIVACY_INVOKED) { + error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY, + ic->ic_def_txkey); if (error) break; + if ((val & HOST_DECRYPT) == 0) { + /* + * It seems that the firmware accept 104bit key + * only if all the keys have 104bit length. We + * get the length of the transmit key and use it + * for all other keys. Perhaps we should use + * software WEP for such situation. + */ + if (ic->ic_def_txkey != IEEE80211_KEYIX_NONE) + keylen = ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen; + else /* XXX should not hapen */ + keylen = IEEE80211_WEP_KEYLEN; + if (keylen > IEEE80211_WEP_KEYLEN) + keylen = 13; /* 104bit keys */ + else + keylen = IEEE80211_WEP_KEYLEN; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + error = wi_write_rid(sc, + WI_RID_P2_CRYPT_KEY0 + i, + ic->ic_nw_keys[i].wk_key, keylen); + if (error) + break; + } + } } break; } @@ -2636,7 +2669,7 @@ wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen) static int wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { - struct ifnet *ifp = &ic->ic_if; + struct ifnet *ifp = ic->ic_ifp; struct wi_softc *sc = ifp->if_softc; struct ieee80211_node *ni = ic->ic_bss; int buflen; @@ -2654,9 +2687,16 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) sc->sc_flags &= ~WI_FLAGS_OUTRANGE; return (*sc->sc_newstate)(ic, nstate, arg); + case IEEE80211_S_SCAN: + case IEEE80211_S_AUTH: + case IEEE80211_S_ASSOC: + ic->ic_state = nstate; /* NB: skip normal ieee80211 handling */ + break; + case IEEE80211_S_RUN: sc->sc_flags &= ~WI_FLAGS_OUTRANGE; buflen = IEEE80211_ADDR_LEN; + IEEE80211_ADDR_COPY(old_bssid, ni->ni_bssid); wi_read_rid(sc, WI_RID_CURRENT_BSSID, ni->ni_bssid, &buflen); IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid); buflen = sizeof(val); @@ -2670,10 +2710,9 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) htole16(ni->ni_chan->ic_flags); #endif - if (IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid)) - sc->sc_false_syns++; - else - sc->sc_false_syns = 0; + /* If not equal, then discount a false synchronization. */ + if (!IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid)) + sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1); if (ic->ic_opmode == IEEE80211_M_HOSTAP) { ni->ni_esslen = ic->ic_des_esslen; @@ -2681,7 +2720,7 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; ni->ni_intval = ic->ic_lintval; ni->ni_capinfo = IEEE80211_CAPINFO_ESS; - if (ic->ic_flags & IEEE80211_F_WEPON) + if (ic->ic_flags & IEEE80211_F_PRIVACY) ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; } else { /* XXX check return value */ @@ -2692,15 +2731,8 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/ memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen); } - break; - - case IEEE80211_S_SCAN: - case IEEE80211_S_AUTH: - case IEEE80211_S_ASSOC: - break; + return (*sc->sc_newstate)(ic, nstate, arg); } - - ic->ic_state = nstate; /* NB: skip normal ieee80211 handling */ return 0; } @@ -2717,8 +2749,8 @@ wi_scan_ap(struct wi_softc *sc, u_int16_t chanmask, u_int16_t txrate) (void)wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); break; case WI_INTERSIL: - val[0] = chanmask; /* channel */ - val[1] = txrate; /* tx rate */ + val[0] = htole16(chanmask); /* channel */ + val[1] = htole16(txrate); /* tx rate */ error = wi_write_rid(sc, WI_RID_SCAN_REQ, val, sizeof(val)); break; case WI_SYMBOL: @@ -2732,7 +2764,7 @@ wi_scan_ap(struct wi_softc *sc, u_int16_t chanmask, u_int16_t txrate) } if (error == 0) { sc->sc_scan_timer = WI_SCAN_WAIT; - sc->sc_ic.ic_if.if_timer = 1; + sc->sc_if.if_timer = 1; DPRINTF(("wi_scan_ap: start scanning, " "chamask 0x%x txrate 0x%x\n", chanmask, txrate)); } diff --git a/sys/dev/wi/if_wi_pci.c b/sys/dev/wi/if_wi_pci.c index 89c9d97826e6..5d11d4d20aa7 100644 --- a/sys/dev/wi/if_wi_pci.c +++ b/sys/dev/wi/if_wi_pci.c @@ -246,10 +246,9 @@ wi_pci_attach(device_t dev) static int wi_pci_suspend(device_t dev) { - struct wi_softc *sc; - struct ifnet *ifp; - sc = device_get_softc(dev); - ifp = &sc->sc_if; + struct wi_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = ic->ic_ifp; wi_stop(ifp, 1); @@ -259,10 +258,9 @@ wi_pci_suspend(device_t dev) static int wi_pci_resume(device_t dev) { - struct wi_softc *sc; - struct ifnet *ifp; - sc = device_get_softc(dev); - ifp = &sc->sc_if; + struct wi_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = ic->ic_ifp; if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) return (0); diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index 0a8388e77b7b..facc42ba38ee 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -59,7 +59,10 @@ #define WI_RID_ROAMING_MODE 0xFC2D #define WI_RID_CUR_TX_RATE 0xFD44 /* current TX rate */ +#define WI_MAX_AID 256 /* max stations for ap operation */ + struct wi_softc { + struct arpcom sc_arp; struct ieee80211com sc_ic; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); @@ -134,7 +137,6 @@ struct wi_softc { int sc_txcur; /* index of current TX*/ int sc_tx_timer; int sc_scan_timer; - int sc_syn_timer; struct wi_counters sc_stats; u_int16_t sc_ibss_port; @@ -160,6 +162,7 @@ struct wi_softc { u_int16_t wi_confbits_param0; } wi_debug; + struct timeval sc_last_syn; int sc_false_syns; u_int16_t sc_txbuf[IEEE80211_MAX_LEN/2]; @@ -175,7 +178,7 @@ struct wi_softc { } u_rx_rt; int sc_rx_th_len; }; -#define sc_if sc_ic.ic_if +#define sc_if sc_arp.ac_if #define sc_tx_th u_tx_rt.th #define sc_rx_th u_rx_rt.th