summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/wlan/if_rum.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/wlan/if_rum.c')
-rw-r--r--sys/dev/usb/wlan/if_rum.c1223
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);
}
OpenPOWER on IntegriCloud