summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-10-05 00:11:49 +0000
committerngie <ngie@FreeBSD.org>2015-10-05 00:11:49 +0000
commite3bac3a30a41f56ac36f4791a7df260f2155c8db (patch)
treeac20948d4aa368300bc16ece67336a1bed25e992 /sys/dev/usb
parentca6cf0ba737487849f2ee102afce74545600850c (diff)
parent85fa330dc74592563cea8d7cf0e628fd30683993 (diff)
downloadFreeBSD-src-e3bac3a30a41f56ac36f4791a7df260f2155c8db.zip
FreeBSD-src-e3bac3a30a41f56ac36f4791a7df260f2155c8db.tar.gz
MFhead @ r281414
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/wlan/if_rum.c1223
-rw-r--r--sys/dev/usb/wlan/if_rumreg.h81
-rw-r--r--sys/dev/usb/wlan/if_rumvar.h64
-rw-r--r--sys/dev/usb/wlan/if_run.c117
-rw-r--r--sys/dev/usb/wlan/if_runreg.h1
-rw-r--r--sys/dev/usb/wlan/if_runvar.h4
-rw-r--r--sys/dev/usb/wlan/if_upgt.c5
-rw-r--r--sys/dev/usb/wlan/if_ural.c27
-rw-r--r--sys/dev/usb/wlan/if_urtwn.c6
-rw-r--r--sys/dev/usb/wlan/if_zyd.c22
10 files changed, 1209 insertions, 341 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);
}
diff --git a/sys/dev/usb/wlan/if_rumreg.h b/sys/dev/usb/wlan/if_rumreg.h
index 44e627a..c673fd7 100644
--- a/sys/dev/usb/wlan/if_rumreg.h
+++ b/sys/dev/usb/wlan/if_rumreg.h
@@ -34,13 +34,36 @@
#define RT2573_WRITE_LED 0x0a
/*
- * Control and status registers.
+ * WME registers.
*/
#define RT2573_AIFSN_CSR 0x0400
#define RT2573_CWMIN_CSR 0x0404
#define RT2573_CWMAX_CSR 0x0408
+#define RT2573_TXOP01_CSR 0x040C
+#define RT2573_TXOP23_CSR 0x0410
#define RT2573_MCU_CODE_BASE 0x0800
-#define RT2573_HW_BEACON_BASE0 0x2400
+
+/*
+ * H/w encryption/decryption support
+ */
+#define KEY_SIZE (IEEE80211_KEYBUF_SIZE + IEEE80211_MICBUF_SIZE)
+#define RT2573_ADDR_MAX 64
+#define RT2573_SKEY_MAX 4
+
+#define RT2573_SKEY(vap, kidx) (0x1000 + ((vap) * RT2573_SKEY_MAX + \
+ (kidx)) * KEY_SIZE)
+#define RT2573_PKEY(id) (0x1200 + (id) * KEY_SIZE)
+
+#define RT2573_ADDR_ENTRY(id) (0x1a00 + (id) * 8)
+
+/*
+ * Shared memory area
+ */
+#define RT2573_HW_BCN_BASE(id) (0x2400 + (id) * 0x100)
+
+/*
+ * Control and status registers.
+ */
#define RT2573_MAC_CSR0 0x3000
#define RT2573_MAC_CSR1 0x3004
#define RT2573_MAC_CSR2 0x3008
@@ -95,13 +118,23 @@
#define RT2573_STA_CSR5 0x30d4
+/* possible values for register RT2573_ADDR_MODE */
+#define RT2573_MODE_MASK 0x7
+#define RT2573_MODE_NOSEC 0
+#define RT2573_MODE_WEP40 1
+#define RT2573_MODE_WEP104 2
+#define RT2573_MODE_TKIP 3
+#define RT2573_MODE_AES_CCMP 4
+#define RT2573_MODE_CKIP40 5
+#define RT2573_MODE_CKIP104 6
+
/* possible flags for register RT2573_MAC_CSR1 */
#define RT2573_RESET_ASIC (1 << 0)
#define RT2573_RESET_BBP (1 << 1)
#define RT2573_HOST_READY (1 << 2)
/* possible flags for register MAC_CSR5 */
-#define RT2573_ONE_BSSID 3
+#define RT2573_NUM_BSSID_MSK(n) (((n * 3) & 3) << 16)
/* possible flags for register TXRX_CSR0 */
/* Tx filter flags are in the low 16 bits */
@@ -122,13 +155,20 @@
#define RT2573_SHORT_PREAMBLE (1 << 18)
#define RT2573_MRR_ENABLED (1 << 19)
#define RT2573_MRR_CCK_FALLBACK (1 << 22)
+#define RT2573_LONG_RETRY(max) ((max) << 24)
+#define RT2573_LONG_RETRY_MASK (0xf << 24)
+#define RT2573_SHORT_RETRY(max) ((max) << 28)
+#define RT2573_SHORT_RETRY_MASK (0xf << 28)
/* possible flags for register TXRX_CSR9 */
-#define RT2573_TSF_TICKING (1 << 16)
-#define RT2573_TSF_MODE(x) (((x) & 0x3) << 17)
-/* TBTT stands for Target Beacon Transmission Time */
-#define RT2573_ENABLE_TBTT (1 << 19)
-#define RT2573_GENERATE_BEACON (1 << 20)
+#define RT2573_TSF_TIMER_EN (1 << 16)
+#define RT2573_TSF_SYNC_MODE(x) (((x) & 0x3) << 17)
+#define RT2573_TSF_SYNC_MODE_DIS 0
+#define RT2573_TSF_SYNC_MODE_STA 1
+#define RT2573_TSF_SYNC_MODE_IBSS 2
+#define RT2573_TSF_SYNC_MODE_HOSTAP 3
+#define RT2573_TBTT_TIMER_EN (1 << 19)
+#define RT2573_BCN_TX_EN (1 << 20)
/* possible flags for register PHY_CSR0 */
#define RT2573_PA_PE_2GHZ (1 << 16)
@@ -175,6 +215,10 @@ struct rum_tx_desc {
#define RT2573_TX_OFDM (1 << 5)
#define RT2573_TX_IFS_SIFS (1 << 6)
#define RT2573_TX_LONG_RETRY (1 << 7)
+#define RT2573_TX_TKIPMIC (1 << 8)
+#define RT2573_TX_KEY_PAIR (1 << 9)
+#define RT2573_TX_KEY_ID(id) (((id) & 0x3f) << 10)
+#define RT2573_TX_CIP_MODE(m) ((m) << 29)
uint16_t wme;
#define RT2573_QID(v) (v)
@@ -182,8 +226,9 @@ struct rum_tx_desc {
#define RT2573_LOGCWMIN(v) ((v) << 8)
#define RT2573_LOGCWMAX(v) ((v) << 12)
- uint16_t xflags;
-#define RT2573_TX_HWSEQ (1 << 12)
+ uint8_t hdrlen;
+ uint8_t xflags;
+#define RT2573_TX_HWSEQ (1 << 4)
uint8_t plcp_signal;
uint8_t plcp_service;
@@ -207,9 +252,25 @@ struct rum_rx_desc {
uint32_t flags;
#define RT2573_RX_BUSY (1 << 0)
#define RT2573_RX_DROP (1 << 1)
+#define RT2573_RX_UC2ME (1 << 2)
+#define RT2573_RX_MC (1 << 3)
+#define RT2573_RX_BC (1 << 4)
+#define RT2573_RX_MYBSS (1 << 5)
#define RT2573_RX_CRC_ERROR (1 << 6)
#define RT2573_RX_OFDM (1 << 7)
+#define RT2573_RX_DEC_MASK (3 << 8)
+#define RT2573_RX_DEC_OK (0 << 8)
+
+#define RT2573_RX_IV_ERROR (1 << 8)
+#define RT2573_RX_MIC_ERROR (2 << 8)
+#define RT2573_RX_KEY_ERROR (3 << 8)
+
+#define RT2573_RX_KEY_PAIR (1 << 28)
+
+#define RT2573_RX_CIP_MASK (7 << 29)
+#define RT2573_RX_CIP_MODE(m) ((m) << 29)
+
uint8_t rate;
uint8_t rssi;
uint8_t reserved1;
diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h
index 35da6d3..9fa733e 100644
--- a/sys/dev/usb/wlan/if_rumvar.h
+++ b/sys/dev/usb/wlan/if_rumvar.h
@@ -22,6 +22,7 @@
struct rum_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
+ uint64_t wr_tsf;
uint8_t wr_flags;
uint8_t wr_rate;
uint16_t wr_chan_freq;
@@ -32,7 +33,8 @@ struct rum_rx_radiotap_header {
} __packed __aligned(8);
#define RT2573_RX_RADIOTAP_PRESENT \
- ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ ((1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
@@ -42,6 +44,7 @@ struct rum_rx_radiotap_header {
struct rum_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
+ uint64_t wt_tsf;
uint8_t wt_flags;
uint8_t wt_rate;
uint16_t wt_chan_freq;
@@ -50,7 +53,8 @@ struct rum_tx_radiotap_header {
} __packed __aligned(8);
#define RT2573_TX_RADIOTAP_PRESENT \
- ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ ((1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA))
@@ -67,11 +71,29 @@ struct rum_tx_data {
};
typedef STAILQ_HEAD(, rum_tx_data) rum_txdhead;
+union sec_param {
+ struct ieee80211_key key;
+ struct wmeParams wme_params[WME_NUM_AC];
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
+ struct ieee80211vap *vap;
+};
+#define CMD_FUNC_PROTO void (*func)(struct rum_softc *, \
+ union sec_param *, uint8_t)
+
+struct rum_cmdq {
+ union sec_param data;
+ uint8_t rvp_id;
+
+ CMD_FUNC_PROTO;
+};
+#define RUM_CMDQ_SIZE 16
+
struct rum_vap {
struct ieee80211vap vap;
- struct ieee80211_beacon_offsets bo;
+ struct mbuf *bcn_mbuf;
struct usb_callout ratectl_ch;
struct task ratectl_task;
+ uint8_t maxretry;
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -90,7 +112,7 @@ struct rum_softc {
device_t sc_dev;
struct usb_device *sc_udev;
- struct usb_xfer *sc_xfer[RUM_N_TRANSFER];
+ struct usb_xfer *sc_xfer[RUM_N_TRANSFER];
uint8_t rf_rev;
uint8_t rffreq;
@@ -103,11 +125,24 @@ struct rum_softc {
struct mtx sc_mtx;
+ struct rum_cmdq cmdq[RUM_CMDQ_SIZE];
+ struct mtx cmdq_mtx;
+ struct task cmdq_task;
+ uint8_t cmdq_first;
+ uint8_t cmdq_last;
+
uint32_t sta[6];
uint32_t rf_regs[4];
uint8_t txpow[44];
u_int sc_detached:1,
- sc_running:1;
+ sc_running:1,
+ sc_clr_shkeys:1;
+
+ uint8_t sc_bssid[IEEE80211_ADDR_LEN];
+ struct wmeParams wme_params[WME_NUM_AC];
+
+ uint8_t vap_key_count[1];
+ uint64_t keys_bmap;
struct {
uint8_t val;
@@ -125,12 +160,19 @@ struct rum_softc {
uint8_t bbp17;
struct rum_rx_radiotap_header sc_rxtap;
- int sc_rxtap_len;
-
struct rum_tx_radiotap_header sc_txtap;
- int sc_txtap_len;
};
-#define RUM_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
-#define RUM_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
-#define RUM_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t)
+#define RUM_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \
+ MTX_NETWORK_LOCK, MTX_DEF);
+#define RUM_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define RUM_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define RUM_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
+#define RUM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
+
+#define RUM_CMDQ_LOCK_INIT(sc) \
+ mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF)
+#define RUM_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx)
+#define RUM_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx)
+#define RUM_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx)
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c
index c8707c4..83d4a88 100644
--- a/sys/dev/usb/wlan/if_run.c
+++ b/sys/dev/usb/wlan/if_run.c
@@ -382,8 +382,7 @@ static int run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int run_wme_update(struct ieee80211com *);
static void run_wme_update_cb(void *);
static void run_key_set_cb(void *);
-static int run_key_set(struct ieee80211vap *, struct ieee80211_key *,
- const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int run_key_set(struct ieee80211vap *, struct ieee80211_key *);
static void run_key_delete_cb(void *);
static int run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
static void run_ratectl_to(void *);
@@ -392,6 +391,8 @@ static void run_drain_fifo(void *);
static void run_iter_func(void *, struct ieee80211_node *);
static void run_newassoc_cb(void *);
static void run_newassoc(struct ieee80211_node *, int);
+static void run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
+ const struct ieee80211_rx_stats *, int, int);
static void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
static void run_tx_free(struct run_endpoint_queue *pq,
struct run_tx_data *, int);
@@ -830,6 +831,21 @@ detach:
return (ENXIO);
}
+static void
+run_drain_mbufq(struct run_softc *sc)
+{
+ struct mbuf *m;
+ struct ieee80211_node *ni;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+ while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+ ieee80211_free_node(ni);
+ m_freem(m);
+ }
+}
+
static int
run_detach(device_t self)
{
@@ -851,6 +867,9 @@ run_detach(device_t self)
/* free TX list, if any */
for (i = 0; i != RUN_EP_QUEUES; i++)
run_unsetup_tx_list(sc, &sc->sc_epq[i]);
+
+ /* Free TX queue */
+ run_drain_mbufq(sc);
RUN_UNLOCK(sc);
if (sc->sc_ic.ic_softc == sc) {
@@ -861,7 +880,6 @@ run_detach(device_t self)
ieee80211_ifdetach(ic);
}
- mbufq_drain(&sc->sc_snd);
mtx_destroy(&sc->sc_mtx);
return (0);
@@ -939,6 +957,10 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
/* override state transition machine */
rvp->newstate = vap->iv_newstate;
vap->iv_newstate = run_newstate;
+ if (opmode == IEEE80211_M_IBSS) {
+ rvp->recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = run_recv_mgmt;
+ }
ieee80211_ratectl_init(vap);
ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
@@ -1670,14 +1692,14 @@ run_get_txpower(struct run_softc *sc)
/* Fix broken Tx power entries. */
for (i = 0; i < 14; i++) {
if (sc->mac_ver >= 0x5390) {
- if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
+ if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39)
sc->txpow1[i] = 5;
} else {
if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
sc->txpow1[i] = 5;
}
if (sc->mac_ver > 0x5390) {
- if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
+ if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39)
sc->txpow2[i] = 5;
} else if (sc->mac_ver < 0x5390) {
if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
@@ -2157,7 +2179,8 @@ run_wme_update_cb(void *arg)
{
struct ieee80211com *ic = arg;
struct run_softc *sc = ic->ic_softc;
- struct ieee80211_wme_state *wmesp = &ic->ic_wme;
+ const struct wmeParams *ac =
+ ic->ic_wme.wme_chanParams.cap_wmeParams;
int aci, error = 0;
RUN_LOCK_ASSERT(sc, MA_OWNED);
@@ -2165,39 +2188,39 @@ run_wme_update_cb(void *arg)
/* update MAC TX configuration registers */
for (aci = 0; aci < WME_NUM_AC; aci++) {
error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
- wmesp->wme_params[aci].wmep_logcwmax << 16 |
- wmesp->wme_params[aci].wmep_logcwmin << 12 |
- wmesp->wme_params[aci].wmep_aifsn << 8 |
- wmesp->wme_params[aci].wmep_txopLimit);
+ ac[aci].wmep_logcwmax << 16 |
+ ac[aci].wmep_logcwmin << 12 |
+ ac[aci].wmep_aifsn << 8 |
+ ac[aci].wmep_txopLimit);
if (error) goto err;
}
/* update SCH/DMA registers too */
error = run_write(sc, RT2860_WMM_AIFSN_CFG,
- wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 |
- wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 |
- wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 |
- wmesp->wme_params[WME_AC_BE].wmep_aifsn);
+ ac[WME_AC_VO].wmep_aifsn << 12 |
+ ac[WME_AC_VI].wmep_aifsn << 8 |
+ ac[WME_AC_BK].wmep_aifsn << 4 |
+ ac[WME_AC_BE].wmep_aifsn);
if (error) goto err;
error = run_write(sc, RT2860_WMM_CWMIN_CFG,
- wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
- wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 |
- wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 |
- wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
+ ac[WME_AC_VO].wmep_logcwmin << 12 |
+ ac[WME_AC_VI].wmep_logcwmin << 8 |
+ ac[WME_AC_BK].wmep_logcwmin << 4 |
+ ac[WME_AC_BE].wmep_logcwmin);
if (error) goto err;
error = run_write(sc, RT2860_WMM_CWMAX_CFG,
- wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
- wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 |
- wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 |
- wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
+ ac[WME_AC_VO].wmep_logcwmax << 12 |
+ ac[WME_AC_VI].wmep_logcwmax << 8 |
+ ac[WME_AC_BK].wmep_logcwmax << 4 |
+ ac[WME_AC_BE].wmep_logcwmax);
if (error) goto err;
error = run_write(sc, RT2860_WMM_TXOP0_CFG,
- wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
- wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
+ ac[WME_AC_BK].wmep_txopLimit << 16 |
+ ac[WME_AC_BE].wmep_txopLimit);
if (error) goto err;
error = run_write(sc, RT2860_WMM_TXOP1_CFG,
- wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
- wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
+ ac[WME_AC_VO].wmep_txopLimit << 16 |
+ ac[WME_AC_VI].wmep_txopLimit);
err:
if (error)
@@ -2355,8 +2378,7 @@ run_key_set_cb(void *arg)
* return 0 on error
*/
static int
-run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
- const uint8_t mac[IEEE80211_ADDR_LEN])
+run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k)
{
struct ieee80211com *ic = vap->iv_ic;
struct run_softc *sc = ic->ic_softc;
@@ -2368,7 +2390,7 @@ run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
sc->cmdq[i].arg0 = NULL;
sc->cmdq[i].arg1 = vap;
sc->cmdq[i].k = k;
- IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
+ IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr);
ieee80211_runtask(ic, &sc->cmdq_task);
/*
@@ -2725,6 +2747,34 @@ run_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
}
static void
+run_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
+ const struct ieee80211_rx_stats *rxs, int rssi, int nf)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct run_softc *sc = vap->iv_ic->ic_softc;
+ struct run_vap *rvp = RUN_VAP(vap);
+ uint64_t ni_tstamp, rx_tstamp;
+
+ rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
+
+ if (vap->iv_state == IEEE80211_S_RUN &&
+ (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
+ subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
+ ni_tstamp = le64toh(ni->ni_tstamp.tsf);
+ RUN_LOCK(sc);
+ run_get_tsf(sc, &rx_tstamp);
+ RUN_UNLOCK(sc);
+ rx_tstamp = le64toh(rx_tstamp);
+
+ if (ni_tstamp >= rx_tstamp) {
+ DPRINTF("ibss merge, tsf %ju tstamp %ju\n",
+ (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp);
+ (void) ieee80211_ibss_merge(ni);
+ }
+ }
+}
+
+static void
run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -4834,11 +4884,11 @@ run_update_beacon(struct ieee80211vap *vap, int item)
setbit(bo->bo_flags, item);
if (rvp->beacon_mbuf == NULL) {
- rvp->beacon_mbuf = ieee80211_beacon_alloc(ni, bo);
+ rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
if (rvp->beacon_mbuf == NULL)
return;
}
- ieee80211_beacon_update(ni, bo, rvp->beacon_mbuf, mcast);
+ ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast);
i = RUN_CMDQ_GET(&sc->cmdq_store);
DPRINTF("cmdq_store=%d\n", i);
@@ -4872,8 +4922,7 @@ run_update_beacon_cb(void *arg)
* is taking care of apropriate calls.
*/
if (rvp->beacon_mbuf == NULL) {
- rvp->beacon_mbuf = ieee80211_beacon_alloc(ni,
- &vap->iv_bcn_off);
+ rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
if (rvp->beacon_mbuf == NULL)
return;
}
@@ -6140,6 +6189,8 @@ run_stop(void *arg)
RUN_LOCK(sc);
+ run_drain_mbufq(sc);
+
if (sc->rx_m != NULL) {
m_free(sc->rx_m);
sc->rx_m = NULL;
diff --git a/sys/dev/usb/wlan/if_runreg.h b/sys/dev/usb/wlan/if_runreg.h
index aa54a72..de71d5a 100644
--- a/sys/dev/usb/wlan/if_runreg.h
+++ b/sys/dev/usb/wlan/if_runreg.h
@@ -274,7 +274,6 @@
#define RT2860_USB_TXOP_HALT (1 << 20)
#define RT2860_USB_TX_CLEAR (1 << 19)
#define RT2860_USB_PHY_WD_EN (1 << 16)
-#define RT2860_USB_PHY_MAN_RST (1 << 15)
#define RT2860_USB_RX_AGG_LMT(x) ((x) << 8) /* in unit of 1KB */
#define RT2860_USB_RX_AGG_TO(x) ((x) & 0xff) /* in unit of 33ns */
diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h
index bbefbb0..3af5b22 100644
--- a/sys/dev/usb/wlan/if_runvar.h
+++ b/sys/dev/usb/wlan/if_runvar.h
@@ -123,6 +123,10 @@ struct run_vap {
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
+ void (*recv_mgmt)(struct ieee80211_node *,
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *,
+ int, int);
uint8_t rvp_id;
};
diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c
index b882fe3..516caf0 100644
--- a/sys/dev/usb/wlan/if_upgt.c
+++ b/sys/dev/usb/wlan/if_upgt.c
@@ -956,10 +956,7 @@ upgt_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
return NULL;
- uvp = (struct upgt_vap *) malloc(sizeof(struct upgt_vap),
- M_80211_VAP, M_NOWAIT | M_ZERO);
- if (uvp == NULL)
- return NULL;
+ uvp = malloc(sizeof(struct upgt_vap), M_80211_VAP, M_WAITOK | M_ZERO);
vap = &uvp->vap;
/* enable s/w bmiss handling for sta mode */
diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c
index bff4de5..6f6686f 100644
--- a/sys/dev/usb/wlan/if_ural.c
+++ b/sys/dev/usb/wlan/if_ural.c
@@ -698,12 +698,9 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
ni = ieee80211_ref_node(vap->iv_bss);
if (vap->iv_opmode != IEEE80211_M_MONITOR) {
- if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
- RAL_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- ieee80211_free_node(ni);
- return (-1);
- }
+ if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
+ goto fail;
+
ural_update_slot(sc);
ural_set_txpreamble(sc);
ural_set_basicrates(sc, ic->ic_bsschan);
@@ -713,23 +710,17 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
vap->iv_opmode == IEEE80211_M_IBSS) {
- m = ieee80211_beacon_alloc(ni, &vap->iv_bcn_off);
+ m = ieee80211_beacon_alloc(ni);
if (m == NULL) {
device_printf(sc->sc_dev,
"could not allocate beacon\n");
- RAL_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- ieee80211_free_node(ni);
- return (-1);
+ goto fail;
}
ieee80211_ref_node(ni);
if (ural_tx_bcn(sc, m, ni) != 0) {
device_printf(sc->sc_dev,
"could not send beacon\n");
- RAL_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- ieee80211_free_node(ni);
- return (-1);
+ goto fail;
}
}
@@ -755,6 +746,12 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
RAL_UNLOCK(sc);
IEEE80211_LOCK(ic);
return (uvp->newstate(vap, nstate, arg));
+
+fail:
+ RAL_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ ieee80211_free_node(ni);
+ return (-1);
}
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/usb/wlan/if_urtwn.c
index b1e3804..eb11f7b 100644
--- a/sys/dev/usb/wlan/if_urtwn.c
+++ b/sys/dev/usb/wlan/if_urtwn.c
@@ -1775,7 +1775,7 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
struct r92c_tx_desc *txd;
uint8_t raid, type;
uint16_t sum;
- int i, hasqos, xferlen;
+ int i, xferlen;
struct usb_xfer *urtwn_pipes[4] = {
sc->sc_xfer[URTWN_BULK_TX_BE],
sc->sc_xfer[URTWN_BULK_TX_BK],
@@ -1816,8 +1816,6 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
break;
}
- hasqos = 0;
-
/* Fill Tx descriptor. */
txd = (struct r92c_tx_desc *)data->buf;
memset(txd, 0, sizeof(*txd));
@@ -1873,7 +1871,7 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
/* Set sequence number (already little endian). */
txd->txdseq |= *(uint16_t *)wh->i_seq;
- if (!hasqos) {
+ if (!IEEE80211_QOS_HAS_SEQ(wh)) {
/* Use HW sequence numbering for non-QoS frames. */
txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ);
txd->txdseq |= htole16(0x8000);
diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c
index 5a59d37..ed70d19 100644
--- a/sys/dev/usb/wlan/if_zyd.c
+++ b/sys/dev/usb/wlan/if_zyd.c
@@ -420,6 +420,22 @@ detach:
return (ENXIO); /* failure */
}
+static void
+zyd_drain_mbufq(struct zyd_softc *sc)
+{
+ struct mbuf *m;
+ struct ieee80211_node *ni;
+
+ ZYD_LOCK_ASSERT(sc, MA_OWNED);
+ while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+ ieee80211_free_node(ni);
+ m_freem(m);
+ }
+}
+
+
static int
zyd_detach(device_t dev)
{
@@ -433,6 +449,7 @@ zyd_detach(device_t dev)
*/
ZYD_LOCK(sc);
sc->sc_flags |= ZYD_FLAG_DETACHED;
+ zyd_drain_mbufq(sc);
STAILQ_INIT(&sc->tx_q);
STAILQ_INIT(&sc->tx_free);
ZYD_UNLOCK(sc);
@@ -451,7 +468,6 @@ zyd_detach(device_t dev)
if (ic->ic_softc == sc)
ieee80211_ifdetach(ic);
- mbufq_drain(&sc->sc_snd);
mtx_destroy(&sc->sc_mtx);
return (0);
@@ -2443,7 +2459,6 @@ zyd_tx_start(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
k = ieee80211_crypto_encap(ni, m0);
if (k == NULL) {
- m_freem(m0);
return (ENOBUFS);
}
/* packet header may have moved, reset our local pointer */
@@ -2555,6 +2570,7 @@ zyd_start(struct zyd_softc *sc)
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
if (zyd_tx_start(sc, m, ni) != 0) {
ieee80211_free_node(ni);
+ m_freem(m);
if_inc_counter(ni->ni_vap->iv_ifp,
IFCOUNTER_OERRORS, 1);
break;
@@ -2592,6 +2608,7 @@ zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
if (zyd_tx_start(sc, m, ni) != 0) {
ZYD_UNLOCK(sc);
ieee80211_free_node(ni);
+ m_freem(m);
return (EIO);
}
ZYD_UNLOCK(sc);
@@ -2738,6 +2755,7 @@ zyd_stop(struct zyd_softc *sc)
ZYD_LOCK_ASSERT(sc, MA_OWNED);
sc->sc_flags &= ~ZYD_FLAG_RUNNING;
+ zyd_drain_mbufq(sc);
/*
* Drain all the transfers, if not already drained:
OpenPOWER on IntegriCloud