diff options
Diffstat (limited to 'sys/dev/usb/wlan/if_rum.c')
-rw-r--r-- | sys/dev/usb/wlan/if_rum.c | 1223 |
1 files changed, 962 insertions, 261 deletions
diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index 6a558f6..f1c9cdf 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -86,8 +86,6 @@ SYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RWTUN, &rum_debug, 0, "Debug level"); #endif -#define N(a) ((int)(sizeof (a) / sizeof ((a)[0]))) - static const STRUCT_USB_HOST_ID rum_devs[] = { #define RUM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } RUM_DEV(ABOCOM, HWU54DM), @@ -160,14 +158,21 @@ static struct ieee80211vap *rum_vap_create(struct ieee80211com *, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void rum_vap_delete(struct ieee80211vap *); +static void rum_cmdq_cb(void *, int); +static int rum_cmd_sleepable(struct rum_softc *, const void *, + size_t, uint8_t, CMD_FUNC_PROTO); static void rum_tx_free(struct rum_tx_data *, int); static void rum_setup_tx_list(struct rum_softc *); static void rum_unsetup_tx_list(struct rum_softc *); static int rum_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static uint8_t rum_crypto_mode(struct rum_softc *, u_int, int); static void rum_setup_tx_desc(struct rum_softc *, - struct rum_tx_desc *, uint32_t, uint16_t, int, - int); + struct rum_tx_desc *, struct ieee80211_key *, + uint32_t, uint8_t, uint8_t, int, int, int); +static uint32_t rum_tx_crypto_flags(struct rum_softc *, + struct ieee80211_node *, + const struct ieee80211_key *); static int rum_tx_mgt(struct rum_softc *, struct mbuf *, struct ieee80211_node *); static int rum_tx_raw(struct rum_softc *, struct mbuf *, @@ -186,6 +191,11 @@ static void rum_read_multi(struct rum_softc *, uint16_t, void *, static usb_error_t rum_write(struct rum_softc *, uint16_t, uint32_t); static usb_error_t rum_write_multi(struct rum_softc *, uint16_t, void *, size_t); +static usb_error_t rum_setbits(struct rum_softc *, uint16_t, uint32_t); +static usb_error_t rum_clrbits(struct rum_softc *, uint16_t, uint32_t); +static usb_error_t rum_modbits(struct rum_softc *, uint16_t, uint32_t, + uint32_t); +static int rum_bbp_busy(struct rum_softc *); static void rum_bbp_write(struct rum_softc *, uint8_t, uint8_t); static uint8_t rum_bbp_read(struct rum_softc *, uint8_t); static void rum_rf_write(struct rum_softc *, uint8_t, uint32_t); @@ -197,9 +207,18 @@ static void rum_select_band(struct rum_softc *, struct ieee80211_channel *); static void rum_set_chan(struct rum_softc *, struct ieee80211_channel *); -static void rum_enable_tsf_sync(struct rum_softc *); +static void rum_set_maxretry(struct rum_softc *, + struct ieee80211vap *); +static int rum_enable_tsf_sync(struct rum_softc *); static void rum_enable_tsf(struct rum_softc *); -static void rum_update_slot(struct rum_softc *); +static void rum_abort_tsf_sync(struct rum_softc *); +static void rum_get_tsf(struct rum_softc *, uint64_t *); +static void rum_update_slot_cb(struct rum_softc *, + union sec_param *, uint8_t); +static void rum_update_slot(struct ieee80211com *); +static void rum_wme_update_cb(struct rum_softc *, + union sec_param *, uint8_t); +static int rum_wme_update(struct ieee80211com *); static void rum_set_bssid(struct rum_softc *, const uint8_t *); static void rum_set_macaddr(struct rum_softc *, const uint8_t *); static void rum_update_mcast(struct ieee80211com *); @@ -207,13 +226,37 @@ static void rum_update_promisc(struct ieee80211com *); static void rum_setpromisc(struct rum_softc *); static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); +static int rum_bbp_wakeup(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); -static void rum_init(struct rum_softc *); +static void rum_clr_shkey_regs(struct rum_softc *); +static int rum_init(struct rum_softc *); static void rum_stop(struct rum_softc *); static void rum_load_microcode(struct rum_softc *, const uint8_t *, size_t); -static void rum_prepare_beacon(struct rum_softc *, +static int rum_set_beacon(struct rum_softc *, + struct ieee80211vap *); +static int rum_alloc_beacon(struct rum_softc *, struct ieee80211vap *); +static void rum_update_beacon_cb(struct rum_softc *, + union sec_param *, uint8_t); +static void rum_update_beacon(struct ieee80211vap *, int); +static int rum_common_key_set(struct rum_softc *, + struct ieee80211_key *, uint16_t); +static void rum_group_key_set_cb(struct rum_softc *, + union sec_param *, uint8_t); +static void rum_group_key_del_cb(struct rum_softc *, + union sec_param *, uint8_t); +static void rum_pair_key_set_cb(struct rum_softc *, + union sec_param *, uint8_t); +static void rum_pair_key_del_cb(struct rum_softc *, + union sec_param *, uint8_t); +static int rum_key_alloc(struct ieee80211vap *, + struct ieee80211_key *, ieee80211_keyix *, + ieee80211_keyix *); +static int rum_key_set(struct ieee80211vap *, + const struct ieee80211_key *); +static int rum_key_delete(struct ieee80211vap *, + const struct ieee80211_key *); static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void rum_scan_start(struct ieee80211com *); @@ -242,9 +285,9 @@ static const struct { { RT2573_MAC_CSR10, 0x00000718 }, { RT2573_MAC_CSR12, 0x00000004 }, { RT2573_MAC_CSR13, 0x00007f00 }, - { RT2573_SEC_CSR0, 0x00000000 }, - { RT2573_SEC_CSR1, 0x00000000 }, - { RT2573_SEC_CSR5, 0x00000000 }, + { RT2573_SEC_CSR2, 0x00000000 }, + { RT2573_SEC_CSR3, 0x00000000 }, + { RT2573_SEC_CSR4, 0x00000000 }, { RT2573_PHY_CSR1, 0x000023b0 }, { RT2573_PHY_CSR5, 0x00040a06 }, { RT2573_PHY_CSR6, 0x00080606 }, @@ -434,8 +477,8 @@ rum_attach(device_t self) sc->sc_udev = uaa->device; sc->sc_dev = self; - mtx_init(&sc->sc_mtx, device_get_nameunit(self), - MTX_NETWORK_LOCK, MTX_DEF); + RUM_LOCK_INIT(sc); + RUM_CMDQ_LOCK_INIT(sc); mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = RT2573_IFACE_INDEX; @@ -480,13 +523,21 @@ rum_attach(device_t self) | IEEE80211_C_IBSS /* IBSS mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ | IEEE80211_C_HOSTAP /* HostAp mode supported */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ | IEEE80211_C_TXPMGT /* tx power management */ | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_SHSLOT /* short slot time supported */ | IEEE80211_C_BGSCAN /* bg scanning supported */ | IEEE80211_C_WPA /* 802.11i */ + | IEEE80211_C_WME /* 802.11e */ ; + ic->ic_cryptocaps = + IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_AES_CCM | + IEEE80211_CRYPTO_TKIPMIC | + IEEE80211_CRYPTO_TKIP; + bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); @@ -504,6 +555,8 @@ rum_attach(device_t self) ic->ic_parent = rum_parent; ic->ic_vap_create = rum_vap_create; ic->ic_vap_delete = rum_vap_delete; + ic->ic_updateslot = rum_update_slot; + ic->ic_wme.wme_update = rum_wme_update; ic->ic_update_mcast = rum_update_mcast; ieee80211_radiotap_attach(ic, @@ -512,6 +565,8 @@ rum_attach(device_t self) &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), RT2573_RX_RADIOTAP_PRESENT); + TASK_INIT(&sc->cmdq_task, 0, rum_cmdq_cb, sc); + if (bootverbose) ieee80211_announce(ic); @@ -526,6 +581,7 @@ static int rum_detach(device_t self) { struct rum_softc *sc = device_get_softc(self); + struct ieee80211com *ic = &sc->sc_ic; /* Prevent further ioctls */ RUM_LOCK(sc); @@ -540,10 +596,15 @@ rum_detach(device_t self) rum_unsetup_tx_list(sc); RUM_UNLOCK(sc); - if (sc->sc_ic.ic_softc == sc) - ieee80211_ifdetach(&sc->sc_ic); + if (ic->ic_softc == sc) { + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_ifdetach(ic); + } + mbufq_drain(&sc->sc_snd); - mtx_destroy(&sc->sc_mtx); + RUM_CMDQ_LOCK_DESTROY(sc); + RUM_LOCK_DESTROY(sc); + return (0); } @@ -594,6 +655,11 @@ rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, /* override state transition machine */ rvp->newstate = vap->iv_newstate; vap->iv_newstate = rum_newstate; + vap->iv_key_alloc = rum_key_alloc; + vap->iv_key_set = rum_key_set; + vap->iv_key_delete = rum_key_delete; + vap->iv_update_beacon = rum_update_beacon; + vap->iv_max_aid = RT2573_ADDR_MAX; usb_callout_init_mtx(&rvp->ratectl_ch, &sc->sc_mtx, 0); TASK_INIT(&rvp->ratectl_task, 0, rum_ratectl_task, rvp); @@ -612,6 +678,7 @@ rum_vap_delete(struct ieee80211vap *vap) struct rum_vap *rvp = RUM_VAP(vap); struct ieee80211com *ic = vap->iv_ic; + m_freem(rvp->bcn_mbuf); usb_callout_drain(&rvp->ratectl_ch); ieee80211_draintask(ic, &rvp->ratectl_task); ieee80211_ratectl_deinit(vap); @@ -620,6 +687,56 @@ rum_vap_delete(struct ieee80211vap *vap) } static void +rum_cmdq_cb(void *arg, int pending) +{ + struct rum_softc *sc = arg; + struct rum_cmdq *rc; + + RUM_CMDQ_LOCK(sc); + while (sc->cmdq[sc->cmdq_first].func != NULL) { + rc = &sc->cmdq[sc->cmdq_first]; + RUM_CMDQ_UNLOCK(sc); + + RUM_LOCK(sc); + rc->func(sc, &rc->data, rc->rvp_id); + RUM_UNLOCK(sc); + + RUM_CMDQ_LOCK(sc); + memset(rc, 0, sizeof (*rc)); + sc->cmdq_first = (sc->cmdq_first + 1) % RUM_CMDQ_SIZE; + } + RUM_CMDQ_UNLOCK(sc); +} + +static int +rum_cmd_sleepable(struct rum_softc *sc, const void *ptr, size_t len, + uint8_t rvp_id, CMD_FUNC_PROTO) +{ + struct ieee80211com *ic = &sc->sc_ic; + + KASSERT(len <= sizeof(union sec_param), ("buffer overflow")); + + RUM_CMDQ_LOCK(sc); + if (sc->cmdq[sc->cmdq_last].func != NULL) { + device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__); + RUM_CMDQ_UNLOCK(sc); + + return EAGAIN; + } + + if (ptr != NULL) + memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len); + sc->cmdq[sc->cmdq_last].rvp_id = rvp_id; + sc->cmdq[sc->cmdq_last].func = func; + sc->cmdq_last = (sc->cmdq_last + 1) % RUM_CMDQ_SIZE; + RUM_CMDQ_UNLOCK(sc); + + ieee80211_runtask(ic, &sc->cmdq_task); + + return 0; +} + +static void rum_tx_free(struct rum_tx_data *data, int txerr) { struct rum_softc *sc = data->sc; @@ -687,7 +804,7 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) const struct ieee80211_txparam *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; - uint32_t tmp; + int ret; ostate = vap->iv_state; DPRINTF("%s -> %s\n", @@ -700,38 +817,40 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) switch (nstate) { case IEEE80211_S_INIT: - if (ostate == IEEE80211_S_RUN) { - /* abort TSF synchronization */ - tmp = rum_read(sc, RT2573_TXRX_CSR9); - rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); - } + if (ostate == IEEE80211_S_RUN) + rum_abort_tsf_sync(sc); + break; case IEEE80211_S_RUN: ni = ieee80211_ref_node(vap->iv_bss); if (vap->iv_opmode != IEEE80211_M_MONITOR) { - if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { - RUM_UNLOCK(sc); - IEEE80211_LOCK(ic); - ieee80211_free_node(ni); - return (-1); + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || + ni->ni_chan == IEEE80211_CHAN_ANYC) { + ret = EINVAL; + goto run_fail; } - rum_update_slot(sc); + rum_update_slot_cb(sc, NULL, 0); rum_enable_mrr(sc); rum_set_txpreamble(sc); rum_set_basicrates(sc); - IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); - rum_set_bssid(sc, ic->ic_macaddr); + rum_set_maxretry(sc, vap); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + rum_set_bssid(sc, sc->sc_bssid); } if (vap->iv_opmode == IEEE80211_M_HOSTAP || - vap->iv_opmode == IEEE80211_M_IBSS) - rum_prepare_beacon(sc, vap); + vap->iv_opmode == IEEE80211_M_IBSS) { + if ((ret = rum_alloc_beacon(sc, vap)) != 0) + goto run_fail; + } - if (vap->iv_opmode != IEEE80211_M_MONITOR) - rum_enable_tsf_sync(sc); - else + if (vap->iv_opmode != IEEE80211_M_MONITOR && + vap->iv_opmode != IEEE80211_M_AHDEMO) { + if ((ret = rum_enable_tsf_sync(sc)) != 0) + goto run_fail; + } else rum_enable_tsf(sc); /* enable automatic rate adaptation */ @@ -746,6 +865,12 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) RUM_UNLOCK(sc); IEEE80211_LOCK(ic); return (rvp->newstate(vap, nstate, arg)); + +run_fail: + RUM_UNLOCK(sc); + IEEE80211_LOCK(ic); + ieee80211_free_node(ni); + return ret; } static void @@ -794,6 +919,7 @@ tr_setup: tap->wt_flags = 0; tap->wt_rate = data->rate; + rum_get_tsf(sc, &tap->wt_tsf); tap->wt_antenna = sc->tx_ant; ieee80211_radiotap_tx(vap, m); @@ -847,6 +973,7 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct rum_softc *sc = usbd_xfer_softc(xfer); struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame_min *wh; struct ieee80211_node *ni; struct mbuf *m = NULL; struct usb_page_cache *pc; @@ -884,6 +1011,21 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) counter_u64_add(ic->ic_ierrors, 1); goto tr_setup; } + if ((flags & RT2573_RX_DEC_MASK) != RT2573_RX_DEC_OK) { + switch (flags & RT2573_RX_DEC_MASK) { + case RT2573_RX_IV_ERROR: + DPRINTFN(5, "IV/EIV error\n"); + break; + case RT2573_RX_MIC_ERROR: + DPRINTFN(5, "MIC error\n"); + break; + case RT2573_RX_KEY_ERROR: + DPRINTFN(5, "Key error\n"); + break; + } + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) { @@ -894,17 +1036,26 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) usbd_copy_out(pc, RT2573_RX_DESC_SIZE, mtod(m, uint8_t *), len); + wh = mtod(m, struct ieee80211_frame_min *); + + if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && + (flags & RT2573_RX_CIP_MASK) != + RT2573_RX_CIP_MODE(RT2573_MODE_NOSEC)) { + wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + m->m_flags |= M_WEP; + } + /* finalize mbuf */ m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; if (ieee80211_radiotap_active(ic)) { struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; - /* XXX read tsf */ tap->wr_flags = 0; tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, (flags & RT2573_RX_OFDM) ? IEEE80211_T_OFDM : IEEE80211_T_CCK); + rum_get_tsf(sc, &tap->wr_tsf); tap->wr_antsignal = RT2573_NOISE_FLOOR + rssi; tap->wr_antnoise = RT2573_NOISE_FLOOR; tap->wr_antenna = sc->rx_ant; @@ -922,8 +1073,11 @@ tr_setup: */ RUM_UNLOCK(sc); if (m) { - ni = ieee80211_find_rxnode(ic, - mtod(m, struct ieee80211_frame_min *)); + if (m->m_len >= sizeof(struct ieee80211_frame_min)) + ni = ieee80211_find_rxnode(ic, wh); + else + ni = NULL; + if (ni != NULL) { (void) ieee80211_input(ni, m, rssi, RT2573_NOISE_FLOOR); @@ -969,22 +1123,46 @@ rum_plcp_signal(int rate) return 0xff; /* XXX unsupported/unknown rate */ } +/* + * Map net80211 cipher to RT2573 security mode. + */ +static uint8_t +rum_crypto_mode(struct rum_softc *sc, u_int cipher, int keylen) +{ + switch (cipher) { + case IEEE80211_CIPHER_WEP: + return (keylen < 8 ? RT2573_MODE_WEP40 : RT2573_MODE_WEP104); + case IEEE80211_CIPHER_TKIP: + return RT2573_MODE_TKIP; + case IEEE80211_CIPHER_AES_CCM: + return RT2573_MODE_AES_CCMP; + default: + device_printf(sc->sc_dev, "unknown cipher %d\n", cipher); + return 0; + } +} + static void rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, - uint32_t flags, uint16_t xflags, int len, int rate) + struct ieee80211_key *k, uint32_t flags, uint8_t xflags, uint8_t qid, + int hdrlen, int len, int rate) { struct ieee80211com *ic = &sc->sc_ic; + struct wmeParams *wmep = &sc->wme_params[qid]; uint16_t plcp_length; int remainder; - desc->flags = htole32(flags); - desc->flags |= htole32(RT2573_TX_VALID); - desc->flags |= htole32(len << 16); + flags |= RT2573_TX_VALID; + flags |= len << 16; + + if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + const struct ieee80211_cipher *cip = k->wk_cipher; - desc->xflags = htole16(xflags); + len += cip->ic_header + cip->ic_trailer + cip->ic_miclen; - desc->wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | - RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); + desc->eiv = 0; /* for WEP */ + cip->ic_setiv(k, (uint8_t *)&desc->iv); + } /* setup PLCP fields */ desc->plcp_signal = rum_plcp_signal(rate); @@ -992,7 +1170,7 @@ rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, len += IEEE80211_CRC_LEN; if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { - desc->flags |= htole32(RT2573_TX_OFDM); + flags |= RT2573_TX_OFDM; plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; @@ -1012,6 +1190,15 @@ rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } + + desc->flags = htole32(flags); + desc->hdrlen = hdrlen; + desc->xflags = xflags; + + desc->wme = htole16(RT2573_QID(qid) | + RT2573_AIFSN(wmep->wmep_aifsn) | + RT2573_LOGCWMIN(wmep->wmep_logcwmin) | + RT2573_LOGCWMAX(wmep->wmep_logcwmax)); } static int @@ -1022,10 +1209,10 @@ rum_sendprot(struct rum_softc *sc, const struct ieee80211_frame *wh; struct rum_tx_data *data; struct mbuf *mprot; - int protrate, ackrate, pktlen, flags, isshort; + int protrate, pktlen, flags, isshort; uint16_t dur; - RUM_LOCK_ASSERT(sc, MA_OWNED); + RUM_LOCK_ASSERT(sc); KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, ("protection %d", prot)); @@ -1033,12 +1220,11 @@ rum_sendprot(struct rum_softc *sc, pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; protrate = ieee80211_ctl_rate(ic->ic_rt, rate); - ackrate = ieee80211_ack_rate(ic->ic_rt, rate); isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) + ieee80211_ack_duration(ic->ic_rt, rate, isshort); - flags = RT2573_TX_MORE_FRAG; + flags = 0; if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); @@ -1058,7 +1244,8 @@ rum_sendprot(struct rum_softc *sc, data->m = mprot; data->ni = ieee80211_ref_node(ni); data->rate = protrate; - rum_setup_tx_desc(sc, &data->desc, flags, 0, mprot->m_pkthdr.len, protrate); + rum_setup_tx_desc(sc, &data->desc, NULL, flags, 0, 0, 0, + mprot->m_pkthdr.len, protrate); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); @@ -1066,6 +1253,40 @@ rum_sendprot(struct rum_softc *sc, return 0; } +static uint32_t +rum_tx_crypto_flags(struct rum_softc *sc, struct ieee80211_node *ni, + const struct ieee80211_key *k) +{ + struct ieee80211vap *vap = ni->ni_vap; + u_int cipher; + uint32_t flags = 0; + uint8_t mode, pos; + + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + cipher = k->wk_cipher->ic_cipher; + pos = k->wk_keyix; + mode = rum_crypto_mode(sc, cipher, k->wk_keylen); + if (mode == 0) + return 0; + + flags |= RT2573_TX_CIP_MODE(mode); + + /* Do not trust GROUP flag */ + if (!(k >= &vap->iv_nw_keys[0] && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) + flags |= RT2573_TX_KEY_PAIR; + else + pos += 0 * RT2573_SKEY_MAX; /* vap id */ + + flags |= RT2573_TX_KEY_ID(pos); + + if (cipher == IEEE80211_CIPHER_TKIP) + flags |= RT2573_TX_TKIPMIC; + } + + return flags; +} + static int rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { @@ -1074,23 +1295,32 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; - struct ieee80211_key *k; + struct ieee80211_key *k = NULL; uint32_t flags = 0; uint16_t dur; + uint8_t ac, type, xflags = 0; + int hdrlen; - RUM_LOCK_ASSERT(sc, MA_OWNED); + RUM_LOCK_ASSERT(sc); data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); sc->tx_nfree--; wh = mtod(m0, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hdrlen = ieee80211_anyhdrsize(wh); + ac = M_WME_GETAC(m0); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m0); - if (k == NULL) { - m_freem(m0); - return ENOBUFS; - } + k = ieee80211_crypto_get_txkey(ni, m0); + if (k == NULL) + return (ENOENT); + + if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && + !k->wk_cipher->ic_encap(k, m0)) + return (ENOBUFS); + wh = mtod(m0, struct ieee80211_frame *); } @@ -1104,17 +1334,24 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) USETW(wh->i_dur, dur); /* tell hardware to add timestamp for probe responses */ - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) + if (type == IEEE80211_FC0_TYPE_MGT && + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == + IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= RT2573_TX_TIMESTAMP; } + if (type != IEEE80211_FC0_TYPE_CTL && !IEEE80211_QOS_HAS_SEQ(wh)) + xflags |= RT2573_TX_HWSEQ; + + if (k != NULL) + flags |= rum_tx_crypto_flags(sc, ni, k); + data->m = m0; data->ni = ni; data->rate = tp->mgmtrate; - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, tp->mgmtrate); + rum_setup_tx_desc(sc, &data->desc, k, flags, xflags, ac, hdrlen, + m0->m_pkthdr.len, tp->mgmtrate); DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate); @@ -1130,18 +1367,23 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_frame *wh; struct rum_tx_data *data; uint32_t flags; + uint8_t ac, type, xflags = 0; int rate, error; - RUM_LOCK_ASSERT(sc, MA_OWNED); - KASSERT(params != NULL, ("no raw xmit params")); + RUM_LOCK_ASSERT(sc); + + wh = mtod(m0, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + ac = params->ibp_pri & 3; rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) { - m_freem(m0); - return EINVAL; - } + if (!ieee80211_isratevalid(ic->ic_rt, rate)) + return (EINVAL); + flags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) flags |= RT2573_TX_NEED_ACK; @@ -1150,13 +1392,15 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, params->ibp_flags & IEEE80211_BPF_RTS ? IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, rate); - if (error || sc->tx_nfree == 0) { - m_freem(m0); - return ENOBUFS; - } + if (error || sc->tx_nfree == 0) + return (ENOBUFS); + flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; } + if (type != IEEE80211_FC0_TYPE_CTL && !IEEE80211_QOS_HAS_SEQ(wh)) + xflags |= RT2573_TX_HWSEQ; + data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); sc->tx_nfree--; @@ -1166,7 +1410,8 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, data->rate = rate; /* XXX need to setup descriptor ourself */ - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + rum_setup_tx_desc(sc, &data->desc, NULL, flags, xflags, ac, 0, + m0->m_pkthdr.len, rate); DPRINTFN(10, "sending raw frame len=%u rate=%u\n", m0->m_pkthdr.len, rate); @@ -1185,14 +1430,23 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; - struct ieee80211_key *k; + struct ieee80211_key *k = NULL; uint32_t flags = 0; uint16_t dur; - int error, rate; + uint8_t ac, type, qos, xflags = 0; + int error, hdrlen, rate; - RUM_LOCK_ASSERT(sc, MA_OWNED); + RUM_LOCK_ASSERT(sc); wh = mtod(m0, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hdrlen = ieee80211_anyhdrsize(wh); + + if (IEEE80211_QOS_HAS_SEQ(wh)) + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + else + qos = 0; + ac = M_WME_GETAC(m0); tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; if (IEEE80211_IS_MULTICAST(wh->i_addr1)) @@ -1203,16 +1457,24 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) rate = ni->ni_txrate; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m0); + k = ieee80211_crypto_get_txkey(ni, m0); if (k == NULL) { m_freem(m0); - return ENOBUFS; + return (ENOENT); + } + if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && + !k->wk_cipher->ic_encap(k, m0)) { + m_freem(m0); + return (ENOBUFS); } /* packet header may have moved, reset our local pointer */ wh = mtod(m0, struct ieee80211_frame *); } + if (type != IEEE80211_FC0_TYPE_CTL && !IEEE80211_QOS_HAS_SEQ(wh)) + xflags |= RT2573_TX_HWSEQ; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { int prot = IEEE80211_PROT_NONE; if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) @@ -1230,6 +1492,9 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) } } + if (k != NULL) + flags |= rum_tx_crypto_flags(sc, ni, k); + data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); sc->tx_nfree--; @@ -1239,15 +1504,18 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) data->rate = rate; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - flags |= RT2573_TX_NEED_ACK; - flags |= RT2573_TX_MORE_FRAG; + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) + flags |= RT2573_TX_NEED_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, rate, + dur = ieee80211_ack_duration(ic->ic_rt, rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); } - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + rum_setup_tx_desc(sc, &data->desc, k, flags, xflags, ac, hdrlen, + m0->m_pkthdr.len, rate); DPRINTFN(10, "sending frame len=%d rate=%d\n", m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate); @@ -1286,7 +1554,7 @@ rum_start(struct rum_softc *sc) struct ieee80211_node *ni; struct mbuf *m; - RUM_LOCK_ASSERT(sc, MA_OWNED); + RUM_LOCK_ASSERT(sc); if (!sc->sc_running) return; @@ -1307,24 +1575,22 @@ static void rum_parent(struct ieee80211com *ic) { struct rum_softc *sc = ic->ic_softc; - int startall = 0; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); RUM_LOCK(sc); if (sc->sc_detached) { RUM_UNLOCK(sc); return; } + RUM_UNLOCK(sc); + if (ic->ic_nrunning > 0) { - if (!sc->sc_running) { - rum_init(sc); - startall = 1; - } else - rum_setpromisc(sc); - } else if (sc->sc_running) + if (rum_init(sc) == 0) + ieee80211_start_all(ic); + else + ieee80211_stop(vap); + } else rum_stop(sc); - RUM_UNLOCK(sc); - if (startall) - ieee80211_start_all(ic); } static void @@ -1412,13 +1678,28 @@ rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) return (USB_ERR_NORMAL_COMPLETION); } -static void -rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) +static usb_error_t +rum_setbits(struct rum_softc *sc, uint16_t reg, uint32_t mask) { - uint32_t tmp; - int ntries; + return (rum_write(sc, reg, rum_read(sc, reg) | mask)); +} - DPRINTFN(2, "reg=0x%08x\n", reg); +static usb_error_t +rum_clrbits(struct rum_softc *sc, uint16_t reg, uint32_t mask) +{ + return (rum_write(sc, reg, rum_read(sc, reg) & ~mask)); +} + +static usb_error_t +rum_modbits(struct rum_softc *sc, uint16_t reg, uint32_t set, uint32_t unset) +{ + return (rum_write(sc, reg, (rum_read(sc, reg) & ~unset) | set)); +} + +static int +rum_bbp_busy(struct rum_softc *sc) +{ + int ntries; for (ntries = 0; ntries < 100; ntries++) { if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) @@ -1426,7 +1707,20 @@ rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) if (rum_pause(sc, hz / 100)) break; } - if (ntries == 100) { + if (ntries == 100) + return (ETIMEDOUT); + + return (0); +} + +static void +rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) +{ + uint32_t tmp; + + DPRINTFN(2, "reg=0x%08x\n", reg); + + if (rum_bbp_busy(sc) != 0) { device_printf(sc->sc_dev, "could not write to BBP\n"); return; } @@ -1443,13 +1737,7 @@ rum_bbp_read(struct rum_softc *sc, uint8_t reg) DPRINTFN(2, "reg=0x%08x\n", reg); - for (ntries = 0; ntries < 100; ntries++) { - if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) - break; - if (rum_pause(sc, hz / 100)) - break; - } - if (ntries == 100) { + if (rum_bbp_busy(sc) != 0) { device_printf(sc->sc_dev, "could not read BBP\n"); return 0; } @@ -1525,31 +1813,25 @@ static void rum_enable_mrr(struct rum_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - uint32_t tmp; - tmp = rum_read(sc, RT2573_TXRX_CSR4); - - tmp &= ~RT2573_MRR_CCK_FALLBACK; - if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) - tmp |= RT2573_MRR_CCK_FALLBACK; - tmp |= RT2573_MRR_ENABLED; - - rum_write(sc, RT2573_TXRX_CSR4, tmp); + if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) { + rum_setbits(sc, RT2573_TXRX_CSR4, + RT2573_MRR_ENABLED | RT2573_MRR_CCK_FALLBACK); + } else { + rum_modbits(sc, RT2573_TXRX_CSR4, + RT2573_MRR_ENABLED, RT2573_MRR_CCK_FALLBACK); + } } static void rum_set_txpreamble(struct rum_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - uint32_t tmp; - - tmp = rum_read(sc, RT2573_TXRX_CSR4); - tmp &= ~RT2573_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - tmp |= RT2573_SHORT_PREAMBLE; - - rum_write(sc, RT2573_TXRX_CSR4, tmp); + rum_setbits(sc, RT2573_TXRX_CSR4, RT2573_SHORT_PREAMBLE); + else + rum_clrbits(sc, RT2573_TXRX_CSR4, RT2573_SHORT_PREAMBLE); } static void @@ -1578,7 +1860,6 @@ static void rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) { uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104; - uint32_t tmp; /* update all BBP registers that depend on the band */ bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c; @@ -1608,13 +1889,13 @@ rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) rum_bbp_write(sc, 97, bbp97); rum_bbp_write(sc, 98, bbp98); - tmp = rum_read(sc, RT2573_PHY_CSR0); - tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ); - if (IEEE80211_IS_CHAN_2GHZ(c)) - tmp |= RT2573_PA_PE_2GHZ; - else - tmp |= RT2573_PA_PE_5GHZ; - rum_write(sc, RT2573_PHY_CSR0, tmp); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + rum_modbits(sc, RT2573_PHY_CSR0, RT2573_PA_PE_2GHZ, + RT2573_PA_PE_5GHZ); + } else { + rum_modbits(sc, RT2573_PHY_CSR0, RT2573_PA_PE_5GHZ, + RT2573_PA_PE_2GHZ); + } } static void @@ -1689,11 +1970,26 @@ rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) rum_pause(sc, hz / 100); } +static void +rum_set_maxretry(struct rum_softc *sc, struct ieee80211vap *vap) +{ + const struct ieee80211_txparam *tp; + struct ieee80211_node *ni = vap->iv_bss; + struct rum_vap *rvp = RUM_VAP(vap); + + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + rvp->maxretry = tp->maxretry < 0xf ? tp->maxretry : 0xf; + + rum_modbits(sc, RT2573_TXRX_CSR4, RT2573_SHORT_RETRY(rvp->maxretry) | + RT2573_LONG_RETRY(rvp->maxretry), + RT2573_SHORT_RETRY_MASK | RT2573_LONG_RETRY_MASK); +} + /* * Enable TSF synchronization and tell h/w to start sending beacons for IBSS * and HostAP operating modes. */ -static void +static int rum_enable_tsf_sync(struct rum_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -1705,85 +2001,178 @@ rum_enable_tsf_sync(struct rum_softc *sc) * Change default 16ms TBTT adjustment to 8ms. * Must be done before enabling beacon generation. */ - rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8); + if (rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8) != 0) + return EIO; } tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000; /* set beacon interval (in 1/16ms unit) */ tmp |= vap->iv_bss->ni_intval * 16; + tmp |= RT2573_TSF_TIMER_EN | RT2573_TBTT_TIMER_EN; - tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; - if (vap->iv_opmode == IEEE80211_M_STA) - tmp |= RT2573_TSF_MODE(1); - else - tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + /* + * Local TSF is always updated with remote TSF on beacon + * reception. + */ + tmp |= RT2573_TSF_SYNC_MODE(RT2573_TSF_SYNC_MODE_STA); + break; + case IEEE80211_M_IBSS: + /* + * Local TSF is updated with remote TSF on beacon reception + * only if the remote TSF is greater than local TSF. + */ + tmp |= RT2573_TSF_SYNC_MODE(RT2573_TSF_SYNC_MODE_IBSS); + tmp |= RT2573_BCN_TX_EN; + break; + case IEEE80211_M_HOSTAP: + /* SYNC with nobody */ + tmp |= RT2573_TSF_SYNC_MODE(RT2573_TSF_SYNC_MODE_HOSTAP); + tmp |= RT2573_BCN_TX_EN; + break; + default: + device_printf(sc->sc_dev, + "Enabling TSF failed. undefined opmode %d\n", + vap->iv_opmode); + return EINVAL; + } + + if (rum_write(sc, RT2573_TXRX_CSR9, tmp) != 0) + return EIO; - rum_write(sc, RT2573_TXRX_CSR9, tmp); + return 0; } static void rum_enable_tsf(struct rum_softc *sc) { - rum_write(sc, RT2573_TXRX_CSR9, - (rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000) | - RT2573_TSF_TICKING | RT2573_TSF_MODE(2)); + rum_modbits(sc, RT2573_TXRX_CSR9, RT2573_TSF_TIMER_EN | + RT2573_TSF_SYNC_MODE(RT2573_TSF_SYNC_MODE_DIS), 0x00ffffff); +} + +static void +rum_abort_tsf_sync(struct rum_softc *sc) +{ + rum_clrbits(sc, RT2573_TXRX_CSR9, 0x00ffffff); +} + +static void +rum_get_tsf(struct rum_softc *sc, uint64_t *buf) +{ + rum_read_multi(sc, RT2573_TXRX_CSR12, buf, sizeof (*buf)); } static void -rum_update_slot(struct rum_softc *sc) +rum_update_slot_cb(struct rum_softc *sc, union sec_param *data, uint8_t rvp_id) { struct ieee80211com *ic = &sc->sc_ic; uint8_t slottime; - uint32_t tmp; slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; - tmp = rum_read(sc, RT2573_MAC_CSR9); - tmp = (tmp & ~0xff) | slottime; - rum_write(sc, RT2573_MAC_CSR9, tmp); + rum_modbits(sc, RT2573_MAC_CSR9, slottime, 0xff); DPRINTF("setting slot time to %uus\n", slottime); } static void -rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid) +rum_update_slot(struct ieee80211com *ic) { - uint32_t tmp; + rum_cmd_sleepable(ic->ic_softc, NULL, 0, 0, rum_update_slot_cb); +} - tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; - rum_write(sc, RT2573_MAC_CSR4, tmp); +static void +rum_wme_update_cb(struct rum_softc *sc, union sec_param *data, uint8_t rvp_id) +{ + struct ieee80211com *ic = &sc->sc_ic; + const struct wmeParams *chanp = + ic->ic_wme.wme_chanParams.cap_wmeParams; + int error = 0; + + error = rum_write(sc, RT2573_AIFSN_CSR, + chanp[WME_AC_VO].wmep_aifsn << 12 | + chanp[WME_AC_VI].wmep_aifsn << 8 | + chanp[WME_AC_BK].wmep_aifsn << 4 | + chanp[WME_AC_BE].wmep_aifsn); + if (error) + goto print_err; + error = rum_write(sc, RT2573_CWMIN_CSR, + chanp[WME_AC_VO].wmep_logcwmin << 12 | + chanp[WME_AC_VI].wmep_logcwmin << 8 | + chanp[WME_AC_BK].wmep_logcwmin << 4 | + chanp[WME_AC_BE].wmep_logcwmin); + if (error) + goto print_err; + error = rum_write(sc, RT2573_CWMAX_CSR, + chanp[WME_AC_VO].wmep_logcwmax << 12 | + chanp[WME_AC_VI].wmep_logcwmax << 8 | + chanp[WME_AC_BK].wmep_logcwmax << 4 | + chanp[WME_AC_BE].wmep_logcwmax); + if (error) + goto print_err; + error = rum_write(sc, RT2573_TXOP01_CSR, + chanp[WME_AC_BK].wmep_txopLimit << 16 | + chanp[WME_AC_BE].wmep_txopLimit); + if (error) + goto print_err; + error = rum_write(sc, RT2573_TXOP23_CSR, + chanp[WME_AC_VO].wmep_txopLimit << 16 | + chanp[WME_AC_VI].wmep_txopLimit); + if (error) + goto print_err; + + memcpy(sc->wme_params, chanp, sizeof(*chanp) * WME_NUM_AC); - tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16; - rum_write(sc, RT2573_MAC_CSR5, tmp); + return; + +print_err: + device_printf(sc->sc_dev, "%s: WME update failed, error %d\n", + __func__, error); } -static void -rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) +static int +rum_wme_update(struct ieee80211com *ic) { - uint32_t tmp; + struct rum_softc *sc = ic->ic_softc; - tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; - rum_write(sc, RT2573_MAC_CSR2, tmp); + rum_cmd_sleepable(sc, NULL, 0, 0, rum_wme_update_cb); - tmp = addr[4] | addr[5] << 8 | 0xff << 16; - rum_write(sc, RT2573_MAC_CSR3, tmp); + return (0); } static void -rum_setpromisc(struct rum_softc *sc) +rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid) { - uint32_t tmp; - tmp = rum_read(sc, RT2573_TXRX_CSR0); + rum_write(sc, RT2573_MAC_CSR4, + bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); + rum_write(sc, RT2573_MAC_CSR5, + bssid[4] | bssid[5] << 8 | RT2573_NUM_BSSID_MSK(1)); +} - tmp &= ~RT2573_DROP_NOT_TO_ME; - if (sc->sc_ic.ic_promisc == 0) - tmp |= RT2573_DROP_NOT_TO_ME; +static void +rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) +{ - rum_write(sc, RT2573_TXRX_CSR0, tmp); + rum_write(sc, RT2573_MAC_CSR2, + addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); + rum_write(sc, RT2573_MAC_CSR3, + addr[4] | addr[5] << 8 | 0xff << 16); +} - DPRINTF("%s promiscuous mode\n", sc->sc_ic.ic_promisc > 0 ? +static void +rum_setpromisc(struct rum_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_promisc == 0) + rum_setbits(sc, RT2573_TXRX_CSR0, RT2573_DROP_NOT_TO_ME); + else + rum_clrbits(sc, RT2573_TXRX_CSR0, RT2573_DROP_NOT_TO_ME); + + DPRINTF("%s promiscuous mode\n", ic->ic_promisc > 0 ? "entering" : "leaving"); } @@ -1793,23 +2182,15 @@ rum_update_promisc(struct ieee80211com *ic) struct rum_softc *sc = ic->ic_softc; RUM_LOCK(sc); - if (!sc->sc_running) { - RUM_UNLOCK(sc); - return; - } - rum_setpromisc(sc); + if (sc->sc_running) + rum_setpromisc(sc); RUM_UNLOCK(sc); } static void rum_update_mcast(struct ieee80211com *ic) { - static int warning_printed; - - if (warning_printed == 0) { - ic_printf(ic, "need to implement %s\n", __func__); - warning_printed = 1; - } + /* Ignore. */ } static const char * @@ -1908,6 +2289,27 @@ rum_read_eeprom(struct rum_softc *sc) } static int +rum_bbp_wakeup(struct rum_softc *sc) +{ + unsigned int ntries; + + for (ntries = 0; ntries < 100; ntries++) { + if (rum_read(sc, RT2573_MAC_CSR12) & 8) + break; + rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ + if (rum_pause(sc, hz / 100)) + break; + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "timeout waiting for BBP/RF to wakeup\n"); + return (ETIMEDOUT); + } + + return (0); +} + +static int rum_bbp_init(struct rum_softc *sc) { int i, ntries; @@ -1926,7 +2328,7 @@ rum_bbp_init(struct rum_softc *sc) } /* initialize BBP registers to default values */ - for (i = 0; i < N(rum_def_bbp); i++) + for (i = 0; i < nitems(rum_def_bbp); i++) rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val); /* write vendor-specific BBP values (from EEPROM) */ @@ -1940,42 +2342,46 @@ rum_bbp_init(struct rum_softc *sc) } static void +rum_clr_shkey_regs(struct rum_softc *sc) +{ + rum_write(sc, RT2573_SEC_CSR0, 0); + rum_write(sc, RT2573_SEC_CSR1, 0); + rum_write(sc, RT2573_SEC_CSR5, 0); +} + +static int rum_init(struct rum_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; - usb_error_t error; - int i, ntries; - - RUM_LOCK_ASSERT(sc, MA_OWNED); + int i, ret; - rum_stop(sc); + RUM_LOCK(sc); + if (sc->sc_running) { + ret = 0; + goto end; + } /* initialize MAC registers to default values */ - for (i = 0; i < N(rum_def_mac); i++) + for (i = 0; i < nitems(rum_def_mac); i++) rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val); + /* reset some WME parameters to default values */ + sc->wme_params[0].wmep_aifsn = 2; + sc->wme_params[0].wmep_logcwmin = 4; + sc->wme_params[0].wmep_logcwmax = 10; + /* set host ready */ - rum_write(sc, RT2573_MAC_CSR1, 3); + rum_write(sc, RT2573_MAC_CSR1, RT2573_RESET_ASIC | RT2573_RESET_BBP); rum_write(sc, RT2573_MAC_CSR1, 0); /* wait for BBP/RF to wakeup */ - for (ntries = 0; ntries < 100; ntries++) { - if (rum_read(sc, RT2573_MAC_CSR12) & 8) - break; - rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ - if (rum_pause(sc, hz / 100)) - break; - } - if (ntries == 100) { - device_printf(sc->sc_dev, - "timeout waiting for BBP/RF to wakeup\n"); - goto fail; - } + if ((ret = rum_bbp_wakeup(sc)) != 0) + goto end; - if ((error = rum_bbp_init(sc)) != 0) - goto fail; + if ((ret = rum_bbp_init(sc)) != 0) + goto end; /* select default channel */ rum_select_band(sc, ic->ic_curchan); @@ -1985,10 +2391,16 @@ rum_init(struct rum_softc *sc) /* clear STA registers */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); + /* clear security registers (if required) */ + if (sc->sc_clr_shkeys == 0) { + rum_clr_shkey_regs(sc); + sc->sc_clr_shkeys = 1; + } + rum_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); /* initialize ASIC */ - rum_write(sc, RT2573_MAC_CSR1, 4); + rum_write(sc, RT2573_MAC_CSR1, RT2573_HOST_READY); /* * Allocate Tx and Rx xfer queues. @@ -2012,21 +2424,25 @@ rum_init(struct rum_softc *sc) sc->sc_running = 1; usbd_xfer_set_stall(sc->sc_xfer[RUM_BULK_WR]); usbd_transfer_start(sc->sc_xfer[RUM_BULK_RD]); - return; -fail: rum_stop(sc); -#undef N +end: RUM_UNLOCK(sc); + + if (ret != 0) + rum_stop(sc); + + return ret; } static void rum_stop(struct rum_softc *sc) { - uint32_t tmp; - - RUM_LOCK_ASSERT(sc, MA_OWNED); + RUM_LOCK(sc); + if (!sc->sc_running) { + RUM_UNLOCK(sc); + return; + } sc->sc_running = 0; - RUM_UNLOCK(sc); /* @@ -2036,16 +2452,15 @@ rum_stop(struct rum_softc *sc) usbd_transfer_drain(sc->sc_xfer[RUM_BULK_RD]); RUM_LOCK(sc); - rum_unsetup_tx_list(sc); /* disable Rx */ - tmp = rum_read(sc, RT2573_TXRX_CSR0); - rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); + rum_setbits(sc, RT2573_TXRX_CSR0, RT2573_DISABLE_RX); /* reset ASIC */ - rum_write(sc, RT2573_MAC_CSR1, 3); + rum_write(sc, RT2573_MAC_CSR1, RT2573_RESET_ASIC | RT2573_RESET_BBP); rum_write(sc, RT2573_MAC_CSR1, 0); + RUM_UNLOCK(sc); } static void @@ -2082,35 +2497,318 @@ rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size) rum_pause(sc, hz / 8); } -static void -rum_prepare_beacon(struct rum_softc *sc, struct ieee80211vap *vap) +static int +rum_set_beacon(struct rum_softc *sc, struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; + struct rum_vap *rvp = RUM_VAP(vap); + struct mbuf *m = rvp->bcn_mbuf; const struct ieee80211_txparam *tp; struct rum_tx_desc desc; - struct mbuf *m0; - if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) - return; - if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) - return; + RUM_LOCK_ASSERT(sc); - m0 = ieee80211_beacon_alloc(vap->iv_bss, &RUM_VAP(vap)->bo); - if (m0 == NULL) - return; + if (m == NULL) + return EINVAL; + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) + return EINVAL; tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; - rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ, - m0->m_pkthdr.len, tp->mgmtrate); + rum_setup_tx_desc(sc, &desc, NULL, RT2573_TX_TIMESTAMP, + RT2573_TX_HWSEQ, 0, 0, m->m_pkthdr.len, tp->mgmtrate); - /* copy the first 24 bytes of Tx descriptor into NIC memory */ - rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24); + /* copy the Tx descriptor into NIC memory */ + if (rum_write_multi(sc, RT2573_HW_BCN_BASE(0), (uint8_t *)&desc, + RT2573_TX_DESC_SIZE) != 0) + return EIO; /* copy beacon header and payload into NIC memory */ - rum_write_multi(sc, RT2573_HW_BEACON_BASE0 + 24, mtod(m0, uint8_t *), - m0->m_pkthdr.len); + if (rum_write_multi(sc, RT2573_HW_BCN_BASE(0) + RT2573_TX_DESC_SIZE, + mtod(m, uint8_t *), m->m_pkthdr.len) != 0) + return EIO; - m_freem(m0); + return 0; +} + +static int +rum_alloc_beacon(struct rum_softc *sc, struct ieee80211vap *vap) +{ + struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211_node *ni = vap->iv_bss; + struct mbuf *m; + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return EINVAL; + + m = ieee80211_beacon_alloc(ni); + if (m == NULL) + return ENOMEM; + + if (rvp->bcn_mbuf != NULL) + m_freem(rvp->bcn_mbuf); + + rvp->bcn_mbuf = m; + + return (rum_set_beacon(sc, vap)); +} + +static void +rum_update_beacon_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rvp_id) +{ + struct ieee80211vap *vap = data->vap; + + rum_set_beacon(sc, vap); +} + +static void +rum_update_beacon(struct ieee80211vap *vap, int item) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rum_softc *sc = ic->ic_softc; + struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; + struct mbuf *m = rvp->bcn_mbuf; + int mcast = 0; + + RUM_LOCK(sc); + if (m == NULL) { + m = ieee80211_beacon_alloc(ni); + if (m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + RUM_UNLOCK(sc); + return; + } + rvp->bcn_mbuf = m; + } + + switch (item) { + case IEEE80211_BEACON_ERP: + rum_update_slot(ic); + break; + case IEEE80211_BEACON_TIM: + mcast = 1; /*TODO*/ + break; + default: + break; + } + RUM_UNLOCK(sc); + + setbit(bo->bo_flags, item); + ieee80211_beacon_update(ni, m, mcast); + + rum_cmd_sleepable(sc, &vap, sizeof(vap), 0, rum_update_beacon_cb); +} + +static int +rum_common_key_set(struct rum_softc *sc, struct ieee80211_key *k, + uint16_t base) +{ + + if (rum_write_multi(sc, base, k->wk_key, k->wk_keylen)) + return EIO; + + if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { + if (rum_write_multi(sc, base + IEEE80211_KEYBUF_SIZE, + k->wk_txmic, 8)) + return EIO; + if (rum_write_multi(sc, base + IEEE80211_KEYBUF_SIZE + 8, + k->wk_rxmic, 8)) + return EIO; + } + + return 0; +} + +static void +rum_group_key_set_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + uint8_t mode; + + if (sc->sc_clr_shkeys == 0) { + rum_clr_shkey_regs(sc); + sc->sc_clr_shkeys = 1; + } + + mode = rum_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen); + if (mode == 0) + goto print_err; + + DPRINTFN(1, "setting group key %d for vap %d, mode %d " + "(tx %s, rx %s)\n", k->wk_keyix, rvp_id, mode, + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); + + /* Install the key. */ + if (rum_common_key_set(sc, k, RT2573_SKEY(rvp_id, k->wk_keyix)) != 0) + goto print_err; + + /* Set cipher mode. */ + if (rum_modbits(sc, rvp_id < 2 ? RT2573_SEC_CSR1 : RT2573_SEC_CSR5, + mode << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX, + RT2573_MODE_MASK << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX) + != 0) + goto print_err; + + /* Mark this key as valid. */ + if (rum_setbits(sc, RT2573_SEC_CSR0, + 1 << (rvp_id * RT2573_SKEY_MAX + k->wk_keyix)) != 0) + goto print_err; + + return; + +print_err: + device_printf(sc->sc_dev, "%s: cannot set group key %d for vap %d\n", + __func__, k->wk_keyix, rvp_id); +} + +static void +rum_group_key_del_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + + DPRINTF("%s: removing group key %d for vap %d\n", __func__, + k->wk_keyix, rvp_id); + rum_clrbits(sc, + rvp_id < 2 ? RT2573_SEC_CSR1 : RT2573_SEC_CSR5, + RT2573_MODE_MASK << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX); + rum_clrbits(sc, RT2573_SEC_CSR0, + rvp_id * RT2573_SKEY_MAX + k->wk_keyix); +} + +static void +rum_pair_key_set_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + uint8_t buf[IEEE80211_ADDR_LEN + 1]; + uint8_t mode; + + mode = rum_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen); + if (mode == 0) + goto print_err; + + DPRINTFN(1, "setting pairwise key %d for vap %d, mode %d " + "(tx %s, rx %s)\n", k->wk_keyix, rvp_id, mode, + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); + + /* Install the key. */ + if (rum_common_key_set(sc, k, RT2573_PKEY(k->wk_keyix)) != 0) + goto print_err; + + IEEE80211_ADDR_COPY(buf, k->wk_macaddr); + buf[IEEE80211_ADDR_LEN] = mode; + + /* Set transmitter address and cipher mode. */ + if (rum_write_multi(sc, RT2573_ADDR_ENTRY(k->wk_keyix), + buf, sizeof buf) != 0) + goto print_err; + + /* Enable key table lookup for this vap. */ + if (sc->vap_key_count[rvp_id]++ == 0) + if (rum_setbits(sc, RT2573_SEC_CSR4, 1 << rvp_id) != 0) + goto print_err; + + /* Mark this key as valid. */ + if (rum_setbits(sc, + k->wk_keyix < 32 ? RT2573_SEC_CSR2 : RT2573_SEC_CSR3, + 1 << (k->wk_keyix % 32)) != 0) + goto print_err; + + return; + +print_err: + device_printf(sc->sc_dev, + "%s: cannot set pairwise key %d, vap %d\n", __func__, k->wk_keyix, + rvp_id); +} + +static void +rum_pair_key_del_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + + DPRINTF("%s: removing key %d\n", __func__, k->wk_keyix); + rum_clrbits(sc, (k->wk_keyix < 32) ? RT2573_SEC_CSR2 : RT2573_SEC_CSR3, + 1 << (k->wk_keyix % 32)); + sc->keys_bmap &= ~(1 << k->wk_keyix); + if (--sc->vap_key_count[rvp_id] == 0) + rum_clrbits(sc, RT2573_SEC_CSR4, 1 << rvp_id); +} + +static int +rum_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct rum_softc *sc = vap->iv_ic->ic_softc; + uint8_t i; + + if (!(&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + RUM_LOCK(sc); + for (i = 0; i < RT2573_ADDR_MAX; i++) { + if ((sc->keys_bmap & (1 << i)) == 0) { + sc->keys_bmap |= 1 << i; + *keyix = i; + break; + } + } + RUM_UNLOCK(sc); + if (i == RT2573_ADDR_MAX) { + device_printf(sc->sc_dev, + "%s: no free space in the key table\n", + __func__); + return 0; + } + } else + *keyix = 0; + } else { + *keyix = k - vap->iv_nw_keys; + } + *rxkeyix = *keyix; + return 1; +} + +static int +rum_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + struct rum_softc *sc = vap->iv_ic->ic_softc; + int group; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return 1; + } + + group = k >= &vap->iv_nw_keys[0] && k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]; + + return !rum_cmd_sleepable(sc, k, sizeof(*k), 0, + group ? rum_group_key_set_cb : rum_pair_key_set_cb); +} + +static int +rum_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + struct rum_softc *sc = vap->iv_ic->ic_softc; + int group; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return 1; + } + + group = k >= &vap->iv_nw_keys[0] && k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]; + + return !rum_cmd_sleepable(sc, k, sizeof(*k), 0, + group ? rum_group_key_del_cb : rum_pair_key_del_cb); } static int @@ -2118,20 +2816,17 @@ rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct rum_softc *sc = ni->ni_ic->ic_softc; + int ret; RUM_LOCK(sc); /* prevent management frames from being sent if we're not ready */ if (!sc->sc_running) { - RUM_UNLOCK(sc); - m_freem(m); - ieee80211_free_node(ni); - return ENETDOWN; + ret = ENETDOWN; + goto bad; } if (sc->tx_nfree < RUM_TX_MINFREE) { - RUM_UNLOCK(sc); - m_freem(m); - ieee80211_free_node(ni); - return EIO; + ret = EIO; + goto bad; } if (params == NULL) { @@ -2139,14 +2834,14 @@ rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, * Legacy path; interpret frame contents to decide * precisely how to send the frame. */ - if (rum_tx_mgt(sc, m, ni) != 0) + if ((ret = rum_tx_mgt(sc, m, ni)) != 0) goto bad; } else { /* * Caller supplied explicit parameters to use in * sending the frame. */ - if (rum_tx_raw(sc, m, ni, params) != 0) + if ((ret = rum_tx_raw(sc, m, ni, params)) != 0) goto bad; } RUM_UNLOCK(sc); @@ -2154,8 +2849,9 @@ rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return 0; bad: RUM_UNLOCK(sc); + m_freem(m); ieee80211_free_node(ni); - return EIO; + return ret; } static void @@ -2185,29 +2881,34 @@ rum_ratectl_task(void *arg, int pending) { struct rum_vap *rvp = arg; struct ieee80211vap *vap = &rvp->vap; - struct ieee80211com *ic = vap->iv_ic; - struct rum_softc *sc = ic->ic_softc; + struct rum_softc *sc = vap->iv_ic->ic_softc; struct ieee80211_node *ni; - int ok, fail; - int sum, retrycnt; + int ok[3], fail; + int sum, success, retrycnt; RUM_LOCK(sc); - /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ + /* read and clear statistic registers (STA_CSR0 to STA_CSR5) */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta)); - ok = (le32toh(sc->sta[4]) >> 16) + /* TX ok w/o retry */ - (le32toh(sc->sta[5]) & 0xffff); /* TX ok w/ retry */ - fail = (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ - sum = ok+fail; - retrycnt = (le32toh(sc->sta[5]) & 0xffff) + fail; + ok[0] = (le32toh(sc->sta[4]) & 0xffff); /* TX ok w/o retry */ + ok[1] = (le32toh(sc->sta[4]) >> 16); /* TX ok w/ one retry */ + ok[2] = (le32toh(sc->sta[5]) & 0xffff); /* TX ok w/ multiple retries */ + fail = (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ - ni = ieee80211_ref_node(vap->iv_bss); - ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt); - (void) ieee80211_ratectl_rate(ni, NULL, 0); - ieee80211_free_node(ni); + success = ok[0] + ok[1] + ok[2]; + sum = success + fail; + /* XXX at least */ + retrycnt = ok[1] + ok[2] * 2 + fail * (rvp->maxretry + 1); + + if (sum != 0) { + ni = ieee80211_ref_node(vap->iv_bss); + ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt); + (void) ieee80211_ratectl_rate(ni, NULL, 0); + ieee80211_free_node(ni); + } /* count TX retry-fail as Tx errors */ - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, fail); + if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, fail); usb_callout_reset(&rvp->ratectl_ch, hz, rum_ratectl_timeout, rvp); RUM_UNLOCK(sc); @@ -2217,12 +2918,9 @@ static void rum_scan_start(struct ieee80211com *ic) { struct rum_softc *sc = ic->ic_softc; - uint32_t tmp; RUM_LOCK(sc); - /* abort TSF synchronization */ - tmp = rum_read(sc, RT2573_TXRX_CSR9); - rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); + rum_abort_tsf_sync(sc); rum_set_bssid(sc, ieee80211broadcastaddr); RUM_UNLOCK(sc); @@ -2234,8 +2932,11 @@ rum_scan_end(struct ieee80211com *ic) struct rum_softc *sc = ic->ic_softc; RUM_LOCK(sc); - rum_enable_tsf_sync(sc); - rum_set_bssid(sc, ic->ic_macaddr); + if (ic->ic_opmode != IEEE80211_M_AHDEMO) + rum_enable_tsf_sync(sc); + else + rum_enable_tsf(sc); + rum_set_bssid(sc, sc->sc_bssid); RUM_UNLOCK(sc); } |