Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

John W. Linville says:

====================
This pull request is intended for the 3.10 series.  It contains a
variety of fixes for problems discovered during the merge window and
after 3.10-rc1.

For the mac80211 bits, Johannes says the following:

"This is what I have:
 * a patch from Felix to fix RCU usage in his rate table code
 * a patch from Ilan to add the wdev id to some notifications so they can
   actually be used by userspace
 * Sasha Levin found an issue in how hwsim handles devices
 * a fix for a bug in the wiphy_register() error path that's been there forever
 * three fixes for WoWLAN
 * AP mode frame matching was erroneously giving frames to all virtual AP
   interfaces (reported by Jouni)
 * a fix for HT handling in my CSA changes, found by Sujith
 * a fix for some locking simplifications gone wrong
 * Ben Greear found more cfg80211/mac80211 state confusion
 * and a fix for another bug found by Jouni: local state changes need to be
   reported by mac80211 to cfg80211 so it disconnects properly."

And for the iwlwifi bits, he says:

"I have fixes for a firmware crash during resume, multicast RX,
aggregation and a workaround for a firmware scanning bug."

Along with those...

Albert Pool adds a USB ID to the rtl8192cu driver.

Arend van Spriel restores a driver option support flag that had been
removed from 3.9 due to a bug in that version of the driver.

Felix Fietkau fixes a trio of ath9k issues with a series of small
patches.

Geert Uytterhoeven provides a Kconfig fix for ath9k (which you also
merged, so it isn't in the diff here).

Larry Finger gives us a fix for a build warning on big-endian systems
for rtlwifi.

Rafał Miłecki adds some core IDs to the bcma driver.

Sujith Manoharan fixes a module unloading crash in ath9k, and corrects
some calibration settings for AR9485.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-05-20 14:05:22 -07:00
commit 3ccfc1b1d2
35 changed files with 314 additions and 109 deletions

View File

@ -84,6 +84,8 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
{ BCMA_CORE_I2S, "I2S" }, { BCMA_CORE_I2S, "I2S" },
{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
{ BCMA_CORE_SHIM, "SHIM" }, { BCMA_CORE_SHIM, "SHIM" },
{ BCMA_CORE_PCIE2, "PCIe Gen2" },
{ BCMA_CORE_ARM_CR4, "ARM CR4" },
{ BCMA_CORE_DEFAULT, "Default" }, { BCMA_CORE_DEFAULT, "Default" },
}; };

View File

@ -965,7 +965,7 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
{ {
int i; int i;
if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah)) if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
return; return;
for (i = 0; i < AR9300_MAX_CHAINS; i++) { for (i = 0; i < AR9300_MAX_CHAINS; i++) {

View File

@ -1020,7 +1020,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982}, {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},

View File

@ -254,6 +254,7 @@ struct ath_atx_tid {
int sched; int sched;
int paused; int paused;
u8 state; u8 state;
bool stop_cb;
}; };
struct ath_node { struct ath_node {
@ -351,7 +352,8 @@ void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc); void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn); u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
bool flush);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);

View File

@ -2008,6 +2008,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH9K_SSTATS_LEN); WARN_ON(i != ATH9K_SSTATS_LEN);
} }
void ath9k_deinit_debug(struct ath_softc *sc)
{
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
relay_close(sc->rfs_chan_spec_scan);
sc->rfs_chan_spec_scan = NULL;
}
}
int ath9k_init_debug(struct ath_hw *ah) int ath9k_init_debug(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);

View File

@ -304,6 +304,7 @@ struct ath9k_debug {
}; };
int ath9k_init_debug(struct ath_hw *ah); int ath9k_init_debug(struct ath_hw *ah);
void ath9k_deinit_debug(struct ath_softc *sc);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
@ -339,6 +340,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
return 0; return 0;
} }
static inline void ath9k_deinit_debug(struct ath_softc *sc)
{
}
static inline void ath_debug_stat_interrupt(struct ath_softc *sc, static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
enum ath9k_int status) enum ath9k_int status)
{ {

View File

@ -906,7 +906,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
if (!ath_is_world_regd(reg)) { if (!ath_is_world_regd(reg)) {
error = regulatory_hint(hw->wiphy, reg->alpha2); error = regulatory_hint(hw->wiphy, reg->alpha2);
if (error) if (error)
goto unregister; goto debug_cleanup;
} }
ath_init_leds(sc); ath_init_leds(sc);
@ -914,6 +914,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
return 0; return 0;
debug_cleanup:
ath9k_deinit_debug(sc);
unregister: unregister:
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
rx_cleanup: rx_cleanup:
@ -942,11 +944,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
sc->dfs_detector->exit(sc->dfs_detector); sc->dfs_detector->exit(sc->dfs_detector);
ath9k_eeprom_release(sc); ath9k_eeprom_release(sc);
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
relay_close(sc->rfs_chan_spec_scan);
sc->rfs_chan_spec_scan = NULL;
}
} }
void ath9k_deinit_device(struct ath_softc *sc) void ath9k_deinit_device(struct ath_softc *sc)
@ -960,6 +957,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
ath9k_deinit_debug(sc);
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc); ath_rx_cleanup(sc);
ath9k_deinit_softc(sc); ath9k_deinit_softc(sc);

View File

@ -1687,6 +1687,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
u16 tid, u16 *ssn, u8 buf_size) u16 tid, u16 *ssn, u8 buf_size)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
bool flush = false;
int ret = 0; int ret = 0;
local_bh_disable(); local_bh_disable();
@ -1703,12 +1704,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
break; break;
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
flush = true;
case IEEE80211_AMPDU_TX_STOP_CONT:
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
ath_tx_aggr_stop(sc, sta, tid); if (ath_tx_aggr_stop(sc, sta, tid, flush))
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
break; break;
case IEEE80211_AMPDU_TX_OPERATIONAL: case IEEE80211_AMPDU_TX_OPERATIONAL:

View File

@ -164,7 +164,20 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
ARRAY_SIZE(bf->rates)); ARRAY_SIZE(bf->rates));
} }
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
if (!tid->stop_cb)
return;
ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr,
tid->tidno);
tid->stop_cb = false;
}
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
bool flush_packets)
{ {
struct ath_txq *txq = tid->ac->txq; struct ath_txq *txq = tid->ac->txq;
struct sk_buff *skb; struct sk_buff *skb;
@ -181,16 +194,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while ((skb = __skb_dequeue(&tid->buf_q))) { while ((skb = __skb_dequeue(&tid->buf_q))) {
fi = get_frame_info(skb); fi = get_frame_info(skb);
bf = fi->bf; bf = fi->bf;
if (!bf && !flush_packets)
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) { if (!bf) {
bf = ath_tx_setup_buffer(sc, txq, tid, skb); ieee80211_free_txskb(sc->hw, skb);
if (!bf) { continue;
ieee80211_free_txskb(sc->hw, skb);
continue;
}
} }
if (fi->retries) { if (fi->retries || flush_packets) {
list_add_tail(&bf->list, &bf_head); list_add_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
@ -201,12 +213,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
} }
} }
if (tid->baw_head == tid->baw_tail) { if (tid->baw_head == tid->baw_tail)
tid->state &= ~AGGR_ADDBA_COMPLETE; ath_tx_clear_tid(sc, tid);
tid->state &= ~AGGR_CLEANUP;
}
if (sendbar) { if (sendbar && !flush_packets) {
ath_txq_unlock(sc, txq); ath_txq_unlock(sc, txq);
ath_send_bar(tid, tid->seq_start); ath_send_bar(tid, tid->seq_start);
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
@ -277,9 +287,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&bf->list, &bf_head); list_add_tail(&bf->list, &bf_head);
if (fi->retries) ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
} }
@ -602,7 +610,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
} }
if (tid->state & AGGR_CLEANUP) if (tid->state & AGGR_CLEANUP)
ath_tx_flush_tid(sc, tid); ath_tx_flush_tid(sc, tid, false);
rcu_read_unlock(); rcu_read_unlock();
@ -620,6 +628,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status *ts, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_buf *bf,
struct list_head *bf_head) struct list_head *bf_head)
{ {
struct ieee80211_tx_info *info;
bool txok, flush; bool txok, flush;
txok = !(ts->ts_status & ATH9K_TXERR_MASK); txok = !(ts->ts_status & ATH9K_TXERR_MASK);
@ -631,8 +640,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_ampdu_depth--; txq->axq_ampdu_depth--;
if (!bf_isampdu(bf)) { if (!bf_isampdu(bf)) {
if (!flush) if (!flush) {
info = IEEE80211_SKB_CB(bf->bf_mpdu);
memcpy(info->control.rates, bf->rates,
sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
}
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else } else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
@ -676,7 +689,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
rates = tx_info->control.rates; rates = bf->rates;
/* /*
* Find the lowest frame length among the rate series that will have a * Find the lowest frame length among the rate series that will have a
@ -1256,18 +1269,23 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
return 0; return 0;
} }
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid,
bool flush)
{ {
struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
struct ath_txq *txq = txtid->ac->txq; struct ath_txq *txq = txtid->ac->txq;
bool ret = !flush;
if (flush)
txtid->stop_cb = false;
if (txtid->state & AGGR_CLEANUP) if (txtid->state & AGGR_CLEANUP)
return; return false;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->state &= ~AGGR_ADDBA_PROGRESS;
return; return ret;
} }
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
@ -1279,13 +1297,17 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
* TID can only be reused after all in-progress subframes have been * TID can only be reused after all in-progress subframes have been
* completed. * completed.
*/ */
if (txtid->baw_head != txtid->baw_tail) if (txtid->baw_head != txtid->baw_tail) {
txtid->state |= AGGR_CLEANUP; txtid->state |= AGGR_CLEANUP;
else ret = false;
txtid->stop_cb = !flush;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE; txtid->state &= ~AGGR_ADDBA_COMPLETE;
}
ath_tx_flush_tid(sc, txtid); ath_tx_flush_tid(sc, txtid, flush);
ath_txq_unlock_complete(sc, txq); ath_txq_unlock_complete(sc, txq);
return ret;
} }
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@ -2415,6 +2437,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno]; tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS; tid->state &= ~AGGR_ADDBA_PROGRESS;
tid->stop_cb = false;
} }
for (acno = 0, ac = &an->ac[acno]; for (acno = 0, ac = &an->ac[acno];
@ -2451,8 +2474,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
} }
ath_tid_drain(sc, txq, tid); ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE; ath_tx_clear_tid(sc, tid);
tid->state &= ~AGGR_CLEANUP;
ath_txq_unlock(sc, txq); ath_txq_unlock(sc, txq);
} }

View File

@ -4140,6 +4140,10 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
.types = BIT(NL80211_IFTYPE_P2P_CLIENT) | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) BIT(NL80211_IFTYPE_P2P_GO)
}, },
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
}
}; };
static const struct ieee80211_iface_combination brcmf_iface_combos[] = { static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
{ {
@ -4197,7 +4201,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO); BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
wiphy->iface_combinations = brcmf_iface_combos; wiphy->iface_combinations = brcmf_iface_combos;
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;

View File

@ -1423,7 +1423,7 @@ il_setup_rx_scan_handlers(struct il_priv *il)
} }
EXPORT_SYMBOL(il_setup_rx_scan_handlers); EXPORT_SYMBOL(il_setup_rx_scan_handlers);
inline u16 u16
il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band, il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band,
u8 n_probes) u8 n_probes)
{ {

View File

@ -173,6 +173,8 @@ enum {
REPLY_DEBUG_CMD = 0xf0, REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7, DEBUG_LOG_MSG = 0xf7,
MCAST_FILTER_CMD = 0xd0,
/* D3 commands/notifications */ /* D3 commands/notifications */
D3_CONFIG_CMD = 0xd3, D3_CONFIG_CMD = 0xd3,
PROT_OFFLOAD_CONFIG_CMD = 0xd4, PROT_OFFLOAD_CONFIG_CMD = 0xd4,
@ -948,4 +950,29 @@ struct iwl_set_calib_default_cmd {
u8 data[0]; u8 data[0];
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
#define MAX_PORT_ID_NUM 2
/**
* struct iwl_mcast_filter_cmd - configure multicast filter.
* @filter_own: Set 1 to filter out multicast packets sent by station itself
* @port_id: Multicast MAC addresses array specifier. This is a strange way
* to identify network interface adopted in host-device IF.
* It is used by FW as index in array of addresses. This array has
* MAX_PORT_ID_NUM members.
* @count: Number of MAC addresses in the array
* @pass_all: Set 1 to pass all multicast packets.
* @bssid: current association BSSID.
* @addr_list: Place holder for array of MAC addresses.
* IMPORTANT: add padding if necessary to ensure DWORD alignment.
*/
struct iwl_mcast_filter_cmd {
u8 filter_own;
u8 port_id;
u8 count;
u8 pass_all;
u8 bssid[6];
u8 reserved[2];
u8 addr_list[0];
} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
#endif /* __fw_api_h__ */ #endif /* __fw_api_h__ */

View File

@ -586,10 +586,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
*/ */
static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct iwl_mac_data_sta *ctxt_sta) struct iwl_mac_data_sta *ctxt_sta,
bool force_assoc_off)
{ {
/* We need the dtim_period to set the MAC as associated */ /* We need the dtim_period to set the MAC as associated */
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) { if (vif->bss_conf.assoc && vif->bss_conf.dtim_period &&
!force_assoc_off) {
u32 dtim_offs; u32 dtim_offs;
/* /*
@ -659,7 +661,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
/* Fill the data specific for station mode */ /* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta,
action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
} }
@ -677,7 +680,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/* Fill the data specific for station mode */ /* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta,
action == FW_CTXT_ACTION_ADD);
cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow & cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
IEEE80211_P2P_OPPPS_CTWINDOW_MASK); IEEE80211_P2P_OPPPS_CTWINDOW_MASK);

View File

@ -701,6 +701,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
*total_flags = 0; *total_flags = 0;
} }
static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mcast_filter_cmd mcast_filter_cmd = {
.pass_all = 1,
};
memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
sizeof(mcast_filter_cmd),
&mcast_filter_cmd);
}
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
@ -722,6 +736,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
return; return;
} }
iwl_mvm_bt_coex_vif_assoc(mvm, vif); iwl_mvm_bt_coex_vif_assoc(mvm, vif);
iwl_mvm_configure_mcast_filter(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/* remove AP station now that the MAC is unassoc */ /* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@ -931,7 +946,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
switch (cmd) { switch (cmd) {
case STA_NOTIFY_SLEEP: case STA_NOTIFY_SLEEP:
if (atomic_read(&mvmsta->pending_frames) > 0) if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
ieee80211_sta_block_awake(hw, sta, true); ieee80211_sta_block_awake(hw, sta, true);
/* /*
* The fw updates the STA to be asleep. Tx packets on the Tx * The fw updates the STA to be asleep. Tx packets on the Tx

View File

@ -292,6 +292,7 @@ struct iwl_mvm {
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
struct work_struct sta_drained_wk; struct work_struct sta_drained_wk;
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
/* configured by mac80211 */ /* configured by mac80211 */
u32 rts_threshold; u32 rts_threshold;

View File

@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BT_COEX_PROT_ENV), CMD(BT_COEX_PROT_ENV),
CMD(BT_PROFILE_NOTIFICATION), CMD(BT_PROFILE_NOTIFICATION),
CMD(BT_CONFIG), CMD(BT_CONFIG),
CMD(MCAST_FILTER_CMD),
}; };
#undef CMD #undef CMD

View File

@ -298,6 +298,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
else else
cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
/*
* TODO: This is a WA due to a bug in the FW AUX framework that does not
* properly handle time events that fail to be scheduled
*/
cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
cmd->repeats = cpu_to_le32(1); cmd->repeats = cpu_to_le32(1);
/* /*

View File

@ -219,7 +219,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
/* HW restart, don't assume the memory has been zeroed */ /* HW restart, don't assume the memory has been zeroed */
atomic_set(&mvm_sta->pending_frames, 0); atomic_set(&mvm->pending_frames[sta_id], 0);
mvm_sta->tid_disable_agg = 0; mvm_sta->tid_disable_agg = 0;
mvm_sta->tfd_queue_msk = 0; mvm_sta->tfd_queue_msk = 0;
for (i = 0; i < IEEE80211_NUM_ACS; i++) for (i = 0; i < IEEE80211_NUM_ACS; i++)
@ -406,15 +406,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
} }
/*
* Make sure that the tx response code sees the station as -EBUSY and
* calls the drain worker.
*/
spin_lock_bh(&mvm_sta->lock);
/* /*
* There are frames pending on the AC queues for this station. * There are frames pending on the AC queues for this station.
* We need to wait until all the frames are drained... * We need to wait until all the frames are drained...
*/ */
if (atomic_read(&mvm_sta->pending_frames)) { if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
ERR_PTR(-EBUSY)); ERR_PTR(-EBUSY));
spin_unlock_bh(&mvm_sta->lock);
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
} else { } else {
spin_unlock_bh(&mvm_sta->lock);
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
} }

View File

@ -274,7 +274,6 @@ struct iwl_mvm_tid_data {
* @bt_reduced_txpower: is reduced tx power enabled for this station * @bt_reduced_txpower: is reduced tx power enabled for this station
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock. * and from Tx response flow, it needs a spinlock.
* @pending_frames: number of frames for this STA on the shared Tx queues.
* @tid_data: per tid data. Look at %iwl_mvm_tid_data. * @tid_data: per tid data. Look at %iwl_mvm_tid_data.
* *
* When mac80211 creates a station it reserves some space (hw->sta_data_size) * When mac80211 creates a station it reserves some space (hw->sta_data_size)
@ -290,7 +289,6 @@ struct iwl_mvm_sta {
u8 max_agg_bufsize; u8 max_agg_bufsize;
bool bt_reduced_txpower; bool bt_reduced_txpower;
spinlock_t lock; spinlock_t lock;
atomic_t pending_frames;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
struct iwl_lq_sta lq_sta; struct iwl_lq_sta lq_sta;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;

View File

@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock(&mvmsta->lock); spin_unlock(&mvmsta->lock);
if (mvmsta->vif->type == NL80211_IFTYPE_AP && if (txq_id < IWL_MVM_FIRST_AGG_QUEUE)
txq_id < IWL_MVM_FIRST_AGG_QUEUE) atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
atomic_inc(&mvmsta->pending_frames);
return 0; return 0;
@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* /*
* If the txq is not an AMPDU queue, there is no chance we freed * If the txq is not an AMPDU queue, there is no chance we freed
* several skbs. Check that out... * several skbs. Check that out...
* If there are no pending frames for this STA, notify mac80211 that
* this station can go to sleep in its STA table.
*/ */
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) &&
!WARN_ON(skb_freed > 1) && atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
mvmsta->vif->type == NL80211_IFTYPE_AP && if (mvmsta) {
atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { /*
ieee80211_sta_block_awake(mvm->hw, sta, false); * If there are no pending frames for this STA, notify
set_bit(sta_id, mvm->sta_drained); * mac80211 that this station can go to sleep in its
schedule_work(&mvm->sta_drained_wk); * STA table.
*/
if (mvmsta->vif->type == NL80211_IFTYPE_AP)
ieee80211_sta_block_awake(mvm->hw, sta, false);
/*
* We might very well have taken mvmsta pointer while
* the station was being removed. The remove flow might
* have seen a pending_frame (because we didn't take
* the lock) even if now the queues are drained. So make
* really sure now that this the station is not being
* removed. If it is, run the drain worker to remove it.
*/
spin_lock_bh(&mvmsta->lock);
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
if (IS_ERR_OR_NULL(sta)) {
/*
* Station disappeared in the meantime:
* so we are draining.
*/
set_bit(sta_id, mvm->sta_drained);
schedule_work(&mvm->sta_drained_wk);
}
spin_unlock_bh(&mvmsta->lock);
} else if (!mvmsta) {
/* Tx response without STA, so we are draining */
set_bit(sta_id, mvm->sta_drained);
schedule_work(&mvm->sta_drained_wk);
}
} }
rcu_read_unlock(); rcu_read_unlock();

View File

@ -1723,11 +1723,11 @@ static void mac80211_hwsim_free(void)
class_destroy(hwsim_class); class_destroy(hwsim_class);
} }
static struct platform_driver mac80211_hwsim_driver = {
static struct device_driver mac80211_hwsim_driver = { .driver = {
.name = "mac80211_hwsim", .name = "mac80211_hwsim",
.bus = &platform_bus_type, .owner = THIS_MODULE,
.owner = THIS_MODULE, },
}; };
static const struct net_device_ops hwsim_netdev_ops = { static const struct net_device_ops hwsim_netdev_ops = {
@ -2219,7 +2219,7 @@ static int __init init_mac80211_hwsim(void)
spin_lock_init(&hwsim_radio_lock); spin_lock_init(&hwsim_radio_lock);
INIT_LIST_HEAD(&hwsim_radios); INIT_LIST_HEAD(&hwsim_radios);
err = driver_register(&mac80211_hwsim_driver); err = platform_driver_register(&mac80211_hwsim_driver);
if (err) if (err)
return err; return err;
@ -2254,7 +2254,7 @@ static int __init init_mac80211_hwsim(void)
err = -ENOMEM; err = -ENOMEM;
goto failed_drvdata; goto failed_drvdata;
} }
data->dev->driver = &mac80211_hwsim_driver; data->dev->driver = &mac80211_hwsim_driver.driver;
err = device_bind_driver(data->dev); err = device_bind_driver(data->dev);
if (err != 0) { if (err != 0) {
printk(KERN_DEBUG printk(KERN_DEBUG
@ -2564,7 +2564,7 @@ failed_drvdata:
failed: failed:
mac80211_hwsim_free(); mac80211_hwsim_free();
failed_unregister_driver: failed_unregister_driver:
driver_unregister(&mac80211_hwsim_driver); platform_driver_unregister(&mac80211_hwsim_driver);
return err; return err;
} }
module_init(init_mac80211_hwsim); module_init(init_mac80211_hwsim);
@ -2577,6 +2577,6 @@ static void __exit exit_mac80211_hwsim(void)
mac80211_hwsim_free(); mac80211_hwsim_free();
unregister_netdev(hwsim_mon); unregister_netdev(hwsim_mon);
driver_unregister(&mac80211_hwsim_driver); platform_driver_unregister(&mac80211_hwsim_driver);
} }
module_exit(exit_mac80211_hwsim); module_exit(exit_mac80211_hwsim);

View File

@ -550,7 +550,7 @@ do { \
rxmcs == DESC92C_RATE11M) rxmcs == DESC92C_RATE11M)
struct phy_rx_agc_info_t { struct phy_rx_agc_info_t {
#if __LITTLE_ENDIAN #ifdef __LITTLE_ENDIAN
u8 gain:7, trsw:1; u8 gain:7, trsw:1;
#else #else
u8 trsw:1, gain:7; u8 trsw:1, gain:7;
@ -574,7 +574,7 @@ struct phy_status_rpt {
u8 stream_target_csi[2]; u8 stream_target_csi[2];
u8 sig_evm; u8 sig_evm;
u8 rsvd_3; u8 rsvd_3;
#if __LITTLE_ENDIAN #ifdef __LITTLE_ENDIAN
u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/
u8 sgi_en:1; u8 sgi_en:1;
u8 rxsc:2; u8 rxsc:2;

View File

@ -349,6 +349,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
{RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/ {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
{RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
{RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/ {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
{RTL_USB_DEVICE(0x0846, 0xf001, rtl92cu_hal_cfg)}, /*On Netwrks N300MA*/
{RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
{RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/ {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/
{RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/

View File

@ -134,7 +134,10 @@ struct bcma_host_ops {
#define BCMA_CORE_I2S 0x834 #define BCMA_CORE_I2S 0x834
#define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */ #define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */
#define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */ #define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */
#define BCMA_CORE_ARM_CR4 0x83e #define BCMA_CORE_PHY_AC 0x83B
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
#define BCMA_CORE_USB30_DEV 0x83D
#define BCMA_CORE_ARM_CR4 0x83E
#define BCMA_CORE_DEFAULT 0xFFF #define BCMA_CORE_DEFAULT 0xFFF
#define BCMA_MAX_NR_CORES 16 #define BCMA_MAX_NR_CORES 16

View File

@ -3043,7 +3043,8 @@ void ieee80211_napi_complete(struct ieee80211_hw *hw);
* This function may not be called in IRQ context. Calls to this function * This function may not be called in IRQ context. Calls to this function
* for a single hardware must be synchronized against each other. Calls to * for a single hardware must be synchronized against each other. Calls to
* this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be
* mixed for a single hardware. * mixed for a single hardware. Must not run concurrently with
* ieee80211_tx_status() or ieee80211_tx_status_ni().
* *
* In process context use instead ieee80211_rx_ni(). * In process context use instead ieee80211_rx_ni().
* *
@ -3059,7 +3060,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
* (internally defers to a tasklet.) * (internally defers to a tasklet.)
* *
* Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not * Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not
* be mixed for a single hardware. * be mixed for a single hardware.Must not run concurrently with
* ieee80211_tx_status() or ieee80211_tx_status_ni().
* *
* @hw: the hardware this frame came in on * @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call * @skb: the buffer to receive, owned by mac80211 after this call
@ -3073,7 +3075,8 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
* (internally disables bottom halves). * (internally disables bottom halves).
* *
* Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may * Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may
* not be mixed for a single hardware. * not be mixed for a single hardware. Must not run concurrently with
* ieee80211_tx_status() or ieee80211_tx_status_ni().
* *
* @hw: the hardware this frame came in on * @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call * @skb: the buffer to receive, owned by mac80211 after this call
@ -3196,7 +3199,8 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
* This function may not be called in IRQ context. Calls to this function * This function may not be called in IRQ context. Calls to this function
* for a single hardware must be synchronized against each other. Calls * for a single hardware must be synchronized against each other. Calls
* to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe() * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
* may not be mixed for a single hardware. * may not be mixed for a single hardware. Must not run concurrently with
* ieee80211_rx() or ieee80211_rx_ni().
* *
* @hw: the hardware the frame was transmitted by * @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call * @skb: the frame that was transmitted, owned by mac80211 after this call

View File

@ -1267,6 +1267,7 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
__le16 fc, bool acked); __le16 fc, bool acked);
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
/* IBSS code */ /* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);

View File

@ -1015,7 +1015,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
static void static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
u64 timestamp, struct ieee802_11_elems *elems) u64 timestamp, struct ieee802_11_elems *elems,
bool beacon)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@ -1032,6 +1033,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def new_vht_chandef = {}; struct cfg80211_chan_def new_vht_chandef = {};
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const struct ieee80211_ht_operation *ht_oper;
int secondary_channel_offset = -1; int secondary_channel_offset = -1;
ASSERT_MGD_MTX(ifmgd); ASSERT_MGD_MTX(ifmgd);
@ -1048,11 +1050,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sec_chan_offs = elems->sec_chan_offs; sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie; wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
ht_oper = elems->ht_operation;
if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_40MHZ)) { IEEE80211_STA_DISABLE_40MHZ)) {
sec_chan_offs = NULL; sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL; wide_bw_chansw_ie = NULL;
/* only used for bandwidth here */
ht_oper = NULL;
} }
if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
@ -1094,10 +1099,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return; return;
} }
if (sec_chan_offs) { if (!beacon && sec_chan_offs) {
secondary_channel_offset = sec_chan_offs->sec_chan_offs; secondary_channel_offset = sec_chan_offs->sec_chan_offs;
} else if (beacon && ht_oper) {
secondary_channel_offset =
ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
} else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
/* if HT is enabled and the IE not present, it's still HT */ /*
* If it's not a beacon, HT is enabled and the IE not present,
* it's 20 MHz, 802.11-2012 8.5.2.6:
* This element [the Secondary Channel Offset Element] is
* present when switching to a 40 MHz channel. It may be
* present when switching to a 20 MHz channel (in which
* case the secondary channel offset is set to SCN).
*/
secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
} }
@ -2796,7 +2811,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
} }
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems); ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
elems, true);
} }
@ -3210,7 +3226,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_process_chanswitch(sdata, ieee80211_sta_process_chanswitch(sdata,
rx_status->mactime, rx_status->mactime,
&elems); &elems, false);
} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
ies_len = skb->len - ies_len = skb->len -
offsetof(struct ieee80211_mgmt, offsetof(struct ieee80211_mgmt,
@ -3232,7 +3248,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_process_chanswitch(sdata, ieee80211_sta_process_chanswitch(sdata,
rx_status->mactime, rx_status->mactime,
&elems); &elems, false);
} }
break; break;
} }
@ -3623,6 +3639,31 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
} }
} }
#ifdef CONFIG_PM
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
mutex_lock(&ifmgd->mtx);
if (!ifmgd->associated) {
mutex_unlock(&ifmgd->mtx);
return;
}
if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
mlme_dbg(sdata, "driver requested disconnect after resume\n");
ieee80211_sta_connection_lost(sdata,
ifmgd->associated->bssid,
WLAN_REASON_UNSPECIFIED,
true);
mutex_unlock(&ifmgd->mtx);
return;
}
mutex_unlock(&ifmgd->mtx);
}
#endif
/* interface setup */ /* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{ {
@ -4329,7 +4370,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
bool tx = !req->local_state_change; bool tx = !req->local_state_change;
bool sent_frame = false; bool report_frame = false;
mutex_lock(&ifmgd->mtx); mutex_lock(&ifmgd->mtx);
@ -4346,7 +4387,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
sent_frame = tx; report_frame = true;
goto out; goto out;
} }
@ -4354,12 +4395,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf); req->reason_code, tx, frame_buf);
sent_frame = tx; report_frame = true;
} }
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
out: out:
if (sent_frame) if (report_frame)
__cfg80211_send_deauth(sdata->dev, frame_buf, __cfg80211_send_deauth(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN); IEEE80211_DEAUTH_FRAME_LEN);

View File

@ -688,8 +688,15 @@ int rate_control_set_rates(struct ieee80211_hw *hw,
struct ieee80211_sta *pubsta, struct ieee80211_sta *pubsta,
struct ieee80211_sta_rates *rates) struct ieee80211_sta_rates *rates)
{ {
struct ieee80211_sta_rates *old = rcu_dereference(pubsta->rates); struct ieee80211_sta_rates *old;
/*
* mac80211 guarantees that this function will not be called
* concurrently, so the following RCU access is safe, even without
* extra locking. This can not be checked easily, so we just set
* the condition to true.
*/
old = rcu_dereference_protected(pubsta->rates, true);
rcu_assign_pointer(pubsta->rates, rates); rcu_assign_pointer(pubsta->rates, rates);
if (old) if (old)
kfree_rcu(old, rcu_head); kfree_rcu(old, rcu_head);

View File

@ -3036,6 +3036,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
* and location updates. Note that mac80211 * and location updates. Note that mac80211
* itself never looks at these frames. * itself never looks at these frames.
*/ */
if (!multicast &&
!ether_addr_equal(sdata->vif.addr, hdr->addr1))
return 0;
if (ieee80211_is_public_action(hdr, skb->len)) if (ieee80211_is_public_action(hdr, skb->len))
return 1; return 1;
if (!ieee80211_is_beacon(hdr->frame_control)) if (!ieee80211_is_beacon(hdr->frame_control))

View File

@ -208,10 +208,10 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
u32 iv32 = get_unaligned_le32(&data[4]); u32 iv32 = get_unaligned_le32(&data[4]);
u16 iv16 = data[2] | (data[0] << 8); u16 iv16 = data[2] | (data[0] << 8);
spin_lock_bh(&key->u.tkip.txlock); spin_lock(&key->u.tkip.txlock);
ieee80211_compute_tkip_p1k(key, iv32); ieee80211_compute_tkip_p1k(key, iv32);
tkip_mixing_phase2(tk, ctx, iv16, p2k); tkip_mixing_phase2(tk, ctx, iv16, p2k);
spin_unlock_bh(&key->u.tkip.txlock); spin_unlock(&key->u.tkip.txlock);
} }
EXPORT_SYMBOL(ieee80211_get_tkip_p2k); EXPORT_SYMBOL(ieee80211_get_tkip_p2k);

View File

@ -1740,6 +1740,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mb(); mb();
local->resuming = false; local->resuming = false;
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_restart(sdata);
}
mod_timer(&local->sta_cleanup, jiffies + 1); mod_timer(&local->sta_cleanup, jiffies + 1);
#else #else
WARN_ON(1); WARN_ON(1);

View File

@ -638,17 +638,21 @@ int wiphy_register(struct wiphy *wiphy)
* cfg80211_mutex lock * cfg80211_mutex lock
*/ */
res = rfkill_register(rdev->rfkill); res = rfkill_register(rdev->rfkill);
if (res) if (res) {
goto out_rm_dev; device_del(&rdev->wiphy.dev);
mutex_lock(&cfg80211_mutex);
debugfs_remove_recursive(rdev->wiphy.debugfsdir);
list_del_rcu(&rdev->list);
wiphy_regulatory_deregister(wiphy);
mutex_unlock(&cfg80211_mutex);
return res;
}
rtnl_lock(); rtnl_lock();
rdev->wiphy.registered = true; rdev->wiphy.registered = true;
rtnl_unlock(); rtnl_unlock();
return 0; return 0;
out_rm_dev:
device_del(&rdev->wiphy.dev);
return res;
} }
EXPORT_SYMBOL(wiphy_register); EXPORT_SYMBOL(wiphy_register);
@ -866,7 +870,6 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
#endif #endif
__cfg80211_disconnect(rdev, dev, __cfg80211_disconnect(rdev, dev,
WLAN_REASON_DEAUTH_LEAVING, true); WLAN_REASON_DEAUTH_LEAVING, true);
cfg80211_mlme_down(rdev, dev);
wdev_unlock(wdev); wdev_unlock(wdev);
break; break;
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:

View File

@ -7577,6 +7577,8 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
&tcp->payload_tok)) &tcp->payload_tok))
return -ENOBUFS; return -ENOBUFS;
nla_nest_end(msg, nl_tcp);
return 0; return 0;
} }
@ -9970,6 +9972,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) || netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
(sig_dbm && (sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
@ -10010,6 +10013,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) || netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) || nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
(ack && nla_put_flag(msg, NL80211_ATTR_ACK))) (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))

View File

@ -961,7 +961,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
/* was it connected by userspace SME? */ /* was it connected by userspace SME? */
if (!wdev->conn) { if (!wdev->conn) {
cfg80211_mlme_down(rdev, dev); cfg80211_mlme_down(rdev, dev);
return 0; goto disconnect;
} }
if (wdev->sme_state == CFG80211_SME_CONNECTING && if (wdev->sme_state == CFG80211_SME_CONNECTING &&
@ -987,6 +987,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
return err; return err;
} }
disconnect:
if (wdev->sme_state == CFG80211_SME_CONNECTED) if (wdev->sme_state == CFG80211_SME_CONNECTED)
__cfg80211_disconnected(dev, NULL, 0, 0, false); __cfg80211_disconnected(dev, NULL, 0, 0, false);
else if (wdev->sme_state == CFG80211_SME_CONNECTING) else if (wdev->sme_state == CFG80211_SME_CONNECTING)

View File

@ -2441,6 +2441,7 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
WDEV_ENTRY WDEV_ENTRY
__field(bool, non_wireless)
__field(bool, disconnect) __field(bool, disconnect)
__field(bool, magic_pkt) __field(bool, magic_pkt)
__field(bool, gtk_rekey_failure) __field(bool, gtk_rekey_failure)
@ -2449,20 +2450,22 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
__field(bool, rfkill_release) __field(bool, rfkill_release)
__field(s32, pattern_idx) __field(s32, pattern_idx)
__field(u32, packet_len) __field(u32, packet_len)
__dynamic_array(u8, packet, wakeup->packet_present_len) __dynamic_array(u8, packet,
wakeup ? wakeup->packet_present_len : 0)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
WDEV_ASSIGN; WDEV_ASSIGN;
__entry->disconnect = wakeup->disconnect; __entry->non_wireless = !wakeup;
__entry->magic_pkt = wakeup->magic_pkt; __entry->disconnect = wakeup ? wakeup->disconnect : false;
__entry->gtk_rekey_failure = wakeup->gtk_rekey_failure; __entry->magic_pkt = wakeup ? wakeup->magic_pkt : false;
__entry->eap_identity_req = wakeup->eap_identity_req; __entry->gtk_rekey_failure = wakeup ? wakeup->gtk_rekey_failure : false;
__entry->four_way_handshake = wakeup->four_way_handshake; __entry->eap_identity_req = wakeup ? wakeup->eap_identity_req : false;
__entry->rfkill_release = wakeup->rfkill_release; __entry->four_way_handshake = wakeup ? wakeup->four_way_handshake : false;
__entry->pattern_idx = wakeup->pattern_idx; __entry->rfkill_release = wakeup ? wakeup->rfkill_release : false;
__entry->packet_len = wakeup->packet_len; __entry->pattern_idx = wakeup ? wakeup->pattern_idx : false;
if (wakeup->packet && wakeup->packet_present_len) __entry->packet_len = wakeup ? wakeup->packet_len : false;
if (wakeup && wakeup->packet && wakeup->packet_present_len)
memcpy(__get_dynamic_array(packet), wakeup->packet, memcpy(__get_dynamic_array(packet), wakeup->packet,
wakeup->packet_present_len); wakeup->packet_present_len);
), ),