diff options
49 files changed, 373 insertions, 190 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b479160dc262..7a9c6f7cd7e1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
| @@ -1826,7 +1826,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) | |||
| 1826 | } | 1826 | } |
| 1827 | 1827 | ||
| 1828 | /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ | 1828 | /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ |
| 1829 | REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | 1829 | if (AR_SREV_9300_20_OR_LATER(ah)) |
| 1830 | REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | ||
| 1830 | } | 1831 | } |
| 1831 | 1832 | ||
| 1832 | /* | 1833 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 93fbe6f40898..d2348a5a7809 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
| @@ -286,7 +286,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
| 286 | ath_start_ani(common); | 286 | ath_start_ani(common); |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { | 289 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { |
| 290 | struct ath_hw_antcomb_conf div_ant_conf; | 290 | struct ath_hw_antcomb_conf div_ant_conf; |
| 291 | u8 lna_conf; | 291 | u8 lna_conf; |
| 292 | 292 | ||
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 8448281dd069..cc5703b853bc 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
| @@ -1270,7 +1270,9 @@ static void ath_rc_init(struct ath_softc *sc, | |||
| 1270 | 1270 | ||
| 1271 | ath_rc_priv->max_valid_rate = k; | 1271 | ath_rc_priv->max_valid_rate = k; |
| 1272 | ath_rc_sort_validrates(rate_table, ath_rc_priv); | 1272 | ath_rc_sort_validrates(rate_table, ath_rc_priv); |
| 1273 | ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; | 1273 | ath_rc_priv->rate_max_phy = (k > 4) ? |
| 1274 | ath_rc_priv->valid_rate_index[k-4] : | ||
| 1275 | ath_rc_priv->valid_rate_index[k-1]; | ||
| 1274 | ath_rc_priv->rate_table = rate_table; | 1276 | ath_rc_priv->rate_table = rate_table; |
| 1275 | 1277 | ||
| 1276 | ath_dbg(common, ATH_DBG_CONFIG, | 1278 | ath_dbg(common, ATH_DBG_CONFIG, |
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 028310f263c8..f1be57f0f5bb 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c | |||
| @@ -253,6 +253,8 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, | |||
| 253 | int r; | 253 | int r; |
| 254 | 254 | ||
| 255 | sband = wiphy->bands[IEEE80211_BAND_2GHZ]; | 255 | sband = wiphy->bands[IEEE80211_BAND_2GHZ]; |
| 256 | if (!sband) | ||
| 257 | return; | ||
| 256 | 258 | ||
| 257 | /* | 259 | /* |
| 258 | * If no country IE has been received always enable active scan | 260 | * If no country IE has been received always enable active scan |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 58ea0e5fabfd..5f77cbe0b6aa 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
| @@ -175,6 +175,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, | |||
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | /* TODO: verify if needed for SSLPN or LCN */ | ||
| 178 | static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) | 179 | static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) |
| 179 | { | 180 | { |
| 180 | const struct b43_phy *phy = &dev->phy; | 181 | const struct b43_phy *phy = &dev->phy; |
| @@ -256,6 +257,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, | |||
| 256 | unsigned int plcp_fragment_len; | 257 | unsigned int plcp_fragment_len; |
| 257 | u32 mac_ctl = 0; | 258 | u32 mac_ctl = 0; |
| 258 | u16 phy_ctl = 0; | 259 | u16 phy_ctl = 0; |
| 260 | bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP || | ||
| 261 | phy->type == B43_PHYTYPE_N || | ||
| 262 | phy->type == B43_PHYTYPE_HT); | ||
| 259 | u8 extra_ft = 0; | 263 | u8 extra_ft = 0; |
| 260 | struct ieee80211_rate *txrate; | 264 | struct ieee80211_rate *txrate; |
| 261 | struct ieee80211_tx_rate *rates; | 265 | struct ieee80211_tx_rate *rates; |
| @@ -531,7 +535,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, | |||
| 531 | extra_ft |= B43_TXH_EFT_RTSFB_CCK; | 535 | extra_ft |= B43_TXH_EFT_RTSFB_CCK; |
| 532 | 536 | ||
| 533 | if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS && | 537 | if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS && |
| 534 | phy->type == B43_PHYTYPE_N) { | 538 | fill_phy_ctl1) { |
| 535 | txhdr->phy_ctl1_rts = cpu_to_le16( | 539 | txhdr->phy_ctl1_rts = cpu_to_le16( |
| 536 | b43_generate_tx_phy_ctl1(dev, rts_rate)); | 540 | b43_generate_tx_phy_ctl1(dev, rts_rate)); |
| 537 | txhdr->phy_ctl1_rts_fb = cpu_to_le16( | 541 | txhdr->phy_ctl1_rts_fb = cpu_to_le16( |
| @@ -552,7 +556,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, | |||
| 552 | break; | 556 | break; |
| 553 | } | 557 | } |
| 554 | 558 | ||
| 555 | if (phy->type == B43_PHYTYPE_N) { | 559 | if (fill_phy_ctl1) { |
| 556 | txhdr->phy_ctl1 = | 560 | txhdr->phy_ctl1 = |
| 557 | cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate)); | 561 | cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate)); |
| 558 | txhdr->phy_ctl1_fb = | 562 | txhdr->phy_ctl1_fb = |
| @@ -736,7 +740,14 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) | |||
| 736 | 740 | ||
| 737 | /* Link quality statistics */ | 741 | /* Link quality statistics */ |
| 738 | switch (chanstat & B43_RX_CHAN_PHYTYPE) { | 742 | switch (chanstat & B43_RX_CHAN_PHYTYPE) { |
| 743 | case B43_PHYTYPE_HT: | ||
| 744 | /* TODO: is max the right choice? */ | ||
| 745 | status.signal = max_t(__s8, | ||
| 746 | max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1), | ||
| 747 | rxhdr->phy_ht_power2); | ||
| 748 | break; | ||
| 739 | case B43_PHYTYPE_N: | 749 | case B43_PHYTYPE_N: |
| 750 | /* Broadcom has code for min and avg, but always uses max */ | ||
| 740 | if (rxhdr->power0 == 16 || rxhdr->power0 == 32) | 751 | if (rxhdr->power0 == 16 || rxhdr->power0 == 32) |
| 741 | status.signal = max(rxhdr->power1, rxhdr->power2); | 752 | status.signal = max(rxhdr->power1, rxhdr->power2); |
| 742 | else | 753 | else |
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 16c514d54afa..98d90747836a 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h | |||
| @@ -249,6 +249,12 @@ struct b43_rxhdr_fw4 { | |||
| 249 | } __packed; | 249 | } __packed; |
| 250 | } __packed; | 250 | } __packed; |
| 251 | union { | 251 | union { |
| 252 | /* HT-PHY */ | ||
| 253 | struct { | ||
| 254 | PAD_BYTES(1); | ||
| 255 | __s8 phy_ht_power0; | ||
| 256 | } __packed; | ||
| 257 | |||
| 252 | /* RSSI for N-PHYs */ | 258 | /* RSSI for N-PHYs */ |
| 253 | struct { | 259 | struct { |
| 254 | __s8 power2; | 260 | __s8 power2; |
| @@ -257,7 +263,15 @@ struct b43_rxhdr_fw4 { | |||
| 257 | 263 | ||
| 258 | __le16 phy_status2; /* PHY RX Status 2 */ | 264 | __le16 phy_status2; /* PHY RX Status 2 */ |
| 259 | } __packed; | 265 | } __packed; |
| 260 | __le16 phy_status3; /* PHY RX Status 3 */ | 266 | union { |
| 267 | /* HT-PHY */ | ||
| 268 | struct { | ||
| 269 | __s8 phy_ht_power1; | ||
| 270 | __s8 phy_ht_power2; | ||
| 271 | } __packed; | ||
| 272 | |||
| 273 | __le16 phy_status3; /* PHY RX Status 3 */ | ||
| 274 | } __packed; | ||
| 261 | union { | 275 | union { |
| 262 | /* Tested with 598.314, 644.1001 and 666.2 */ | 276 | /* Tested with 598.314, 644.1001 and 666.2 */ |
| 263 | struct { | 277 | struct { |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index b56a30297c26..6ebec8f42846 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c | |||
| @@ -358,13 +358,14 @@ static uint nrxdactive(struct dma_info *di, uint h, uint t) | |||
| 358 | 358 | ||
| 359 | static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) | 359 | static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) |
| 360 | { | 360 | { |
| 361 | uint dmactrlflags = di->dma.dmactrlflags; | 361 | uint dmactrlflags; |
| 362 | 362 | ||
| 363 | if (di == NULL) { | 363 | if (di == NULL) { |
| 364 | DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name)); | 364 | DMA_ERROR(("_dma_ctrlflags: NULL dma handle\n")); |
| 365 | return 0; | 365 | return 0; |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | dmactrlflags = di->dma.dmactrlflags; | ||
| 368 | dmactrlflags &= ~mask; | 369 | dmactrlflags &= ~mask; |
| 369 | dmactrlflags |= flags; | 370 | dmactrlflags |= flags; |
| 370 | 371 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e12b48c2cff6..dd008b0e6417 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
| @@ -191,6 +191,7 @@ static struct iwl_base_params iwl1000_base_params = { | |||
| 191 | .chain_noise_scale = 1000, | 191 | .chain_noise_scale = 1000, |
| 192 | .wd_timeout = IWL_DEF_WD_TIMEOUT, | 192 | .wd_timeout = IWL_DEF_WD_TIMEOUT, |
| 193 | .max_event_log_size = 128, | 193 | .max_event_log_size = 128, |
| 194 | .wd_disable = true, | ||
| 194 | }; | 195 | }; |
| 195 | static struct iwl_ht_params iwl1000_ht_params = { | 196 | static struct iwl_ht_params iwl1000_ht_params = { |
| 196 | .ht_greenfield_support = true, | 197 | .ht_greenfield_support = true, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c511c98a89a8..f55fb2d1af52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
| @@ -364,6 +364,7 @@ static struct iwl_base_params iwl5000_base_params = { | |||
| 364 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | 364 | .wd_timeout = IWL_LONG_WD_TIMEOUT, |
| 365 | .max_event_log_size = 512, | 365 | .max_event_log_size = 512, |
| 366 | .no_idle_support = true, | 366 | .no_idle_support = true, |
| 367 | .wd_disable = true, | ||
| 367 | }; | 368 | }; |
| 368 | static struct iwl_ht_params iwl5000_ht_params = { | 369 | static struct iwl_ht_params iwl5000_ht_params = { |
| 369 | .ht_greenfield_support = true, | 370 | .ht_greenfield_support = true, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 58a381c01c89..5c7c17c7166a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
| @@ -528,6 +528,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
| 528 | return 0; | 528 | return 0; |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | void iwlagn_config_ht40(struct ieee80211_conf *conf, | ||
| 532 | struct iwl_rxon_context *ctx) | ||
| 533 | { | ||
| 534 | if (conf_is_ht40_minus(conf)) { | ||
| 535 | ctx->ht.extension_chan_offset = | ||
| 536 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 537 | ctx->ht.is_40mhz = true; | ||
| 538 | } else if (conf_is_ht40_plus(conf)) { | ||
| 539 | ctx->ht.extension_chan_offset = | ||
| 540 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 541 | ctx->ht.is_40mhz = true; | ||
| 542 | } else { | ||
| 543 | ctx->ht.extension_chan_offset = | ||
| 544 | IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 545 | ctx->ht.is_40mhz = false; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 531 | int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) | 549 | int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) |
| 532 | { | 550 | { |
| 533 | struct iwl_priv *priv = hw->priv; | 551 | struct iwl_priv *priv = hw->priv; |
| @@ -586,19 +604,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
| 586 | ctx->ht.enabled = conf_is_ht(conf); | 604 | ctx->ht.enabled = conf_is_ht(conf); |
| 587 | 605 | ||
| 588 | if (ctx->ht.enabled) { | 606 | if (ctx->ht.enabled) { |
| 589 | if (conf_is_ht40_minus(conf)) { | 607 | /* if HT40 is used, it should not change |
| 590 | ctx->ht.extension_chan_offset = | 608 | * after associated except channel switch */ |
| 591 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | 609 | if (!ctx->ht.is_40mhz || |
| 592 | ctx->ht.is_40mhz = true; | 610 | !iwl_is_associated_ctx(ctx)) |
| 593 | } else if (conf_is_ht40_plus(conf)) { | 611 | iwlagn_config_ht40(conf, ctx); |
| 594 | ctx->ht.extension_chan_offset = | ||
| 595 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 596 | ctx->ht.is_40mhz = true; | ||
| 597 | } else { | ||
| 598 | ctx->ht.extension_chan_offset = | ||
| 599 | IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 600 | ctx->ht.is_40mhz = false; | ||
| 601 | } | ||
| 602 | } else | 612 | } else |
| 603 | ctx->ht.is_40mhz = false; | 613 | ctx->ht.is_40mhz = false; |
| 604 | 614 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index ed6283623932..4b2aa1da0953 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c | |||
| @@ -1268,9 +1268,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, | |||
| 1268 | 1268 | ||
| 1269 | switch (keyconf->cipher) { | 1269 | switch (keyconf->cipher) { |
| 1270 | case WLAN_CIPHER_SUITE_TKIP: | 1270 | case WLAN_CIPHER_SUITE_TKIP: |
| 1271 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
| 1272 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
| 1273 | |||
| 1274 | if (sta) | 1271 | if (sta) |
| 1275 | addr = sta->addr; | 1272 | addr = sta->addr; |
| 1276 | else /* station mode case only */ | 1273 | else /* station mode case only */ |
| @@ -1283,8 +1280,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, | |||
| 1283 | seq.tkip.iv32, p1k, CMD_SYNC); | 1280 | seq.tkip.iv32, p1k, CMD_SYNC); |
| 1284 | break; | 1281 | break; |
| 1285 | case WLAN_CIPHER_SUITE_CCMP: | 1282 | case WLAN_CIPHER_SUITE_CCMP: |
| 1286 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
| 1287 | /* fall through */ | ||
| 1288 | case WLAN_CIPHER_SUITE_WEP40: | 1283 | case WLAN_CIPHER_SUITE_WEP40: |
| 1289 | case WLAN_CIPHER_SUITE_WEP104: | 1284 | case WLAN_CIPHER_SUITE_WEP104: |
| 1290 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, | 1285 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 35a6b71f358c..df1540ca6102 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
| @@ -91,7 +91,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | |||
| 91 | tx_cmd->tid_tspec = qc[0] & 0xf; | 91 | tx_cmd->tid_tspec = qc[0] & 0xf; |
| 92 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; | 92 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; |
| 93 | } else { | 93 | } else { |
| 94 | tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; | 94 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) |
| 95 | tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; | ||
| 96 | else | ||
| 97 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; | ||
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); | 100 | iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ccba69b7f8a7..e0e9a3dfbc00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
| @@ -2316,6 +2316,17 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
| 2316 | return -EOPNOTSUPP; | 2316 | return -EOPNOTSUPP; |
| 2317 | } | 2317 | } |
| 2318 | 2318 | ||
| 2319 | switch (key->cipher) { | ||
| 2320 | case WLAN_CIPHER_SUITE_TKIP: | ||
| 2321 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
| 2322 | /* fall through */ | ||
| 2323 | case WLAN_CIPHER_SUITE_CCMP: | ||
| 2324 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
| 2325 | break; | ||
| 2326 | default: | ||
| 2327 | break; | ||
| 2328 | } | ||
| 2329 | |||
| 2319 | /* | 2330 | /* |
| 2320 | * We could program these keys into the hardware as well, but we | 2331 | * We could program these keys into the hardware as well, but we |
| 2321 | * don't expect much multicast traffic in IBSS and having keys | 2332 | * don't expect much multicast traffic in IBSS and having keys |
| @@ -2599,21 +2610,9 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
| 2599 | 2610 | ||
| 2600 | /* Configure HT40 channels */ | 2611 | /* Configure HT40 channels */ |
| 2601 | ctx->ht.enabled = conf_is_ht(conf); | 2612 | ctx->ht.enabled = conf_is_ht(conf); |
| 2602 | if (ctx->ht.enabled) { | 2613 | if (ctx->ht.enabled) |
| 2603 | if (conf_is_ht40_minus(conf)) { | 2614 | iwlagn_config_ht40(conf, ctx); |
| 2604 | ctx->ht.extension_chan_offset = | 2615 | else |
| 2605 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 2606 | ctx->ht.is_40mhz = true; | ||
| 2607 | } else if (conf_is_ht40_plus(conf)) { | ||
| 2608 | ctx->ht.extension_chan_offset = | ||
| 2609 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 2610 | ctx->ht.is_40mhz = true; | ||
| 2611 | } else { | ||
| 2612 | ctx->ht.extension_chan_offset = | ||
| 2613 | IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 2614 | ctx->ht.is_40mhz = false; | ||
| 2615 | } | ||
| 2616 | } else | ||
| 2617 | ctx->ht.is_40mhz = false; | 2616 | ctx->ht.is_40mhz = false; |
| 2618 | 2617 | ||
| 2619 | if ((le16_to_cpu(ctx->staging.channel) != ch)) | 2618 | if ((le16_to_cpu(ctx->staging.channel) != ch)) |
| @@ -2851,6 +2850,9 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, | |||
| 2851 | int ret; | 2850 | int ret; |
| 2852 | u8 sta_id; | 2851 | u8 sta_id; |
| 2853 | 2852 | ||
| 2853 | if (ctx->ctxid != IWL_RXON_CTX_PAN) | ||
| 2854 | return 0; | ||
| 2855 | |||
| 2854 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 2856 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
| 2855 | mutex_lock(&priv->shrd->mutex); | 2857 | mutex_lock(&priv->shrd->mutex); |
| 2856 | 2858 | ||
| @@ -2899,6 +2901,9 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, | |||
| 2899 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | 2901 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; |
| 2900 | struct iwl_rxon_context *ctx = vif_priv->ctx; | 2902 | struct iwl_rxon_context *ctx = vif_priv->ctx; |
| 2901 | 2903 | ||
| 2904 | if (ctx->ctxid != IWL_RXON_CTX_PAN) | ||
| 2905 | return; | ||
| 2906 | |||
| 2902 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 2907 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
| 2903 | mutex_lock(&priv->shrd->mutex); | 2908 | mutex_lock(&priv->shrd->mutex); |
| 2904 | 2909 | ||
| @@ -3499,9 +3504,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); | |||
| 3499 | module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); | 3504 | module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); |
| 3500 | MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); | 3505 | MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); |
| 3501 | 3506 | ||
| 3502 | module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); | 3507 | module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO); |
| 3503 | MODULE_PARM_DESC(wd_disable, | 3508 | MODULE_PARM_DESC(wd_disable, |
| 3504 | "Disable stuck queue watchdog timer (default: 0 [enabled])"); | 3509 | "Disable stuck queue watchdog timer 0=system default, " |
| 3510 | "1=disable, 2=enable (default: 0)"); | ||
| 3505 | 3511 | ||
| 3506 | /* | 3512 | /* |
| 3507 | * set bt_coex_active to true, uCode will do kill/defer | 3513 | * set bt_coex_active to true, uCode will do kill/defer |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5b936ec1a541..3856abaea507 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
| @@ -86,6 +86,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
| 86 | struct ieee80211_vif *vif, | 86 | struct ieee80211_vif *vif, |
| 87 | struct ieee80211_bss_conf *bss_conf, | 87 | struct ieee80211_bss_conf *bss_conf, |
| 88 | u32 changes); | 88 | u32 changes); |
| 89 | void iwlagn_config_ht40(struct ieee80211_conf *conf, | ||
| 90 | struct iwl_rxon_context *ctx); | ||
| 89 | 91 | ||
| 90 | /* uCode */ | 92 | /* uCode */ |
| 91 | int iwlagn_rx_calib_result(struct iwl_priv *priv, | 93 | int iwlagn_rx_calib_result(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 001fdf140abb..fcf54160e4ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
| @@ -1810,11 +1810,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv) | |||
| 1810 | { | 1810 | { |
| 1811 | unsigned int timeout = priv->cfg->base_params->wd_timeout; | 1811 | unsigned int timeout = priv->cfg->base_params->wd_timeout; |
| 1812 | 1812 | ||
| 1813 | if (timeout && !iwlagn_mod_params.wd_disable) | 1813 | if (!iwlagn_mod_params.wd_disable) { |
| 1814 | mod_timer(&priv->watchdog, | 1814 | /* use system default */ |
| 1815 | jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); | 1815 | if (timeout && !priv->cfg->base_params->wd_disable) |
| 1816 | else | 1816 | mod_timer(&priv->watchdog, |
| 1817 | del_timer(&priv->watchdog); | 1817 | jiffies + |
| 1818 | msecs_to_jiffies(IWL_WD_TICK(timeout))); | ||
| 1819 | else | ||
| 1820 | del_timer(&priv->watchdog); | ||
| 1821 | } else { | ||
| 1822 | /* module parameter overwrite default configuration */ | ||
| 1823 | if (timeout && iwlagn_mod_params.wd_disable == 2) | ||
| 1824 | mod_timer(&priv->watchdog, | ||
| 1825 | jiffies + | ||
| 1826 | msecs_to_jiffies(IWL_WD_TICK(timeout))); | ||
| 1827 | else | ||
| 1828 | del_timer(&priv->watchdog); | ||
| 1829 | } | ||
| 1818 | } | 1830 | } |
| 1819 | 1831 | ||
| 1820 | /** | 1832 | /** |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 137da3380704..f2fc288f3dd3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
| @@ -113,6 +113,7 @@ struct iwl_lib_ops { | |||
| 113 | * @shadow_reg_enable: HW shadhow register bit | 113 | * @shadow_reg_enable: HW shadhow register bit |
| 114 | * @no_idle_support: do not support idle mode | 114 | * @no_idle_support: do not support idle mode |
| 115 | * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up | 115 | * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up |
| 116 | * wd_disable: disable watchdog timer | ||
| 116 | */ | 117 | */ |
| 117 | struct iwl_base_params { | 118 | struct iwl_base_params { |
| 118 | int eeprom_size; | 119 | int eeprom_size; |
| @@ -134,6 +135,7 @@ struct iwl_base_params { | |||
| 134 | const bool shadow_reg_enable; | 135 | const bool shadow_reg_enable; |
| 135 | const bool no_idle_support; | 136 | const bool no_idle_support; |
| 136 | const bool hd_v2; | 137 | const bool hd_v2; |
| 138 | const bool wd_disable; | ||
| 137 | }; | 139 | }; |
| 138 | /* | 140 | /* |
| 139 | * @advanced_bt_coexist: support advanced bt coexist | 141 | * @advanced_bt_coexist: support advanced bt coexist |
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 1f7a93c67c45..14eaf37ce3b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h | |||
| @@ -120,7 +120,7 @@ extern struct iwl_mod_params iwlagn_mod_params; | |||
| 120 | * @restart_fw: restart firmware, default = 1 | 120 | * @restart_fw: restart firmware, default = 1 |
| 121 | * @plcp_check: enable plcp health check, default = true | 121 | * @plcp_check: enable plcp health check, default = true |
| 122 | * @ack_check: disable ack health check, default = false | 122 | * @ack_check: disable ack health check, default = false |
| 123 | * @wd_disable: enable stuck queue check, default = false | 123 | * @wd_disable: enable stuck queue check, default = 0 |
| 124 | * @bt_coex_active: enable bt coex, default = true | 124 | * @bt_coex_active: enable bt coex, default = true |
| 125 | * @led_mode: system default, default = 0 | 125 | * @led_mode: system default, default = 0 |
| 126 | * @no_sleep_autoadjust: disable autoadjust, default = true | 126 | * @no_sleep_autoadjust: disable autoadjust, default = true |
| @@ -141,7 +141,7 @@ struct iwl_mod_params { | |||
| 141 | int restart_fw; | 141 | int restart_fw; |
| 142 | bool plcp_check; | 142 | bool plcp_check; |
| 143 | bool ack_check; | 143 | bool ack_check; |
| 144 | bool wd_disable; | 144 | int wd_disable; |
| 145 | bool bt_coex_active; | 145 | bool bt_coex_active; |
| 146 | int led_mode; | 146 | int led_mode; |
| 147 | bool no_sleep_autoadjust; | 147 | bool no_sleep_autoadjust; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index da3411057afc..5f17ab8e76ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | |||
| @@ -990,29 +990,16 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) | |||
| 990 | return 0; | 990 | return 0; |
| 991 | } | 991 | } |
| 992 | 992 | ||
| 993 | static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) | 993 | static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) |
| 994 | { | 994 | { |
| 995 | unsigned long flags; | 995 | unsigned long flags; |
| 996 | struct iwl_trans_pcie *trans_pcie = | 996 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 997 | IWL_TRANS_GET_PCIE_TRANS(trans); | ||
| 998 | 997 | ||
| 998 | /* tell the device to stop sending interrupts */ | ||
| 999 | spin_lock_irqsave(&trans->shrd->lock, flags); | 999 | spin_lock_irqsave(&trans->shrd->lock, flags); |
| 1000 | iwl_disable_interrupts(trans); | 1000 | iwl_disable_interrupts(trans); |
| 1001 | spin_unlock_irqrestore(&trans->shrd->lock, flags); | 1001 | spin_unlock_irqrestore(&trans->shrd->lock, flags); |
| 1002 | 1002 | ||
| 1003 | /* wait to make sure we flush pending tasklet*/ | ||
| 1004 | synchronize_irq(bus(trans)->irq); | ||
| 1005 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | ||
| 1009 | { | ||
| 1010 | /* stop and reset the on-board processor */ | ||
| 1011 | iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | ||
| 1012 | |||
| 1013 | /* tell the device to stop sending interrupts */ | ||
| 1014 | iwl_trans_pcie_disable_sync_irq(trans); | ||
| 1015 | |||
| 1016 | /* device going down, Stop using ICT table */ | 1003 | /* device going down, Stop using ICT table */ |
| 1017 | iwl_disable_ict(trans); | 1004 | iwl_disable_ict(trans); |
| 1018 | 1005 | ||
| @@ -1039,6 +1026,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
| 1039 | 1026 | ||
| 1040 | /* Stop the device, and put it in low power state */ | 1027 | /* Stop the device, and put it in low power state */ |
| 1041 | iwl_apm_stop(priv(trans)); | 1028 | iwl_apm_stop(priv(trans)); |
| 1029 | |||
| 1030 | /* Upon stop, the APM issues an interrupt if HW RF kill is set. | ||
| 1031 | * Clean again the interrupt here | ||
| 1032 | */ | ||
| 1033 | spin_lock_irqsave(&trans->shrd->lock, flags); | ||
| 1034 | iwl_disable_interrupts(trans); | ||
| 1035 | spin_unlock_irqrestore(&trans->shrd->lock, flags); | ||
| 1036 | |||
| 1037 | /* wait to make sure we flush pending tasklet*/ | ||
| 1038 | synchronize_irq(bus(trans)->irq); | ||
| 1039 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
| 1040 | |||
| 1041 | /* stop and reset the on-board processor */ | ||
| 1042 | iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | ||
| 1042 | } | 1043 | } |
| 1043 | 1044 | ||
| 1044 | static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | 1045 | static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, |
| @@ -1196,9 +1197,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
| 1196 | iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); | 1197 | iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); |
| 1197 | 1198 | ||
| 1198 | /* Set up entry for this TFD in Tx byte-count array */ | 1199 | /* Set up entry for this TFD in Tx byte-count array */ |
| 1199 | if (is_agg) | 1200 | iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); |
| 1200 | iwl_trans_txq_update_byte_cnt_tbl(trans, txq, | ||
| 1201 | le16_to_cpu(tx_cmd->len)); | ||
| 1202 | 1201 | ||
| 1203 | dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, | 1202 | dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, |
| 1204 | DMA_BIDIRECTIONAL); | 1203 | DMA_BIDIRECTIONAL); |
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 4fcd653bddc4..a7f1ab28940d 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c | |||
| @@ -634,7 +634,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, | |||
| 634 | if (channel && | 634 | if (channel && |
| 635 | !(channel->flags & IEEE80211_CHAN_DISABLED)) | 635 | !(channel->flags & IEEE80211_CHAN_DISABLED)) |
| 636 | cfg80211_inform_bss(wiphy, channel, | 636 | cfg80211_inform_bss(wiphy, channel, |
| 637 | bssid, le64_to_cpu(*(__le64 *)tsfdesc), | 637 | bssid, get_unaligned_le64(tsfdesc), |
| 638 | capa, intvl, ie, ielen, | 638 | capa, intvl, ie, ielen, |
| 639 | LBS_SCAN_RSSI_TO_MBM(rssi), | 639 | LBS_SCAN_RSSI_TO_MBM(rssi), |
| 640 | GFP_KERNEL); | 640 | GFP_KERNEL); |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 622ae6de0d8b..7059d9645dab 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
| @@ -995,6 +995,7 @@ static int if_spi_host_to_card(struct lbs_private *priv, | |||
| 995 | spin_unlock_irqrestore(&card->buffer_lock, flags); | 995 | spin_unlock_irqrestore(&card->buffer_lock, flags); |
| 996 | break; | 996 | break; |
| 997 | default: | 997 | default: |
| 998 | kfree(packet); | ||
| 998 | netdev_err(priv->dev, "can't transfer buffer of type %d\n", | 999 | netdev_err(priv->dev, "can't transfer buffer of type %d\n", |
| 999 | type); | 1000 | type); |
| 1000 | err = -EINVAL; | 1001 | err = -EINVAL; |
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index ac278156d390..6e0a3eaecf70 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
| @@ -939,7 +939,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) | |||
| 939 | { | 939 | { |
| 940 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; | 940 | struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; |
| 941 | unsigned long cmd_flags; | 941 | unsigned long cmd_flags; |
| 942 | unsigned long cmd_pending_q_flags; | ||
| 943 | unsigned long scan_pending_q_flags; | 942 | unsigned long scan_pending_q_flags; |
| 944 | uint16_t cancel_scan_cmd = false; | 943 | uint16_t cancel_scan_cmd = false; |
| 945 | 944 | ||
| @@ -949,12 +948,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) | |||
| 949 | cmd_node = adapter->curr_cmd; | 948 | cmd_node = adapter->curr_cmd; |
| 950 | cmd_node->wait_q_enabled = false; | 949 | cmd_node->wait_q_enabled = false; |
| 951 | cmd_node->cmd_flag |= CMD_F_CANCELED; | 950 | cmd_node->cmd_flag |= CMD_F_CANCELED; |
| 952 | spin_lock_irqsave(&adapter->cmd_pending_q_lock, | ||
| 953 | cmd_pending_q_flags); | ||
| 954 | list_del(&cmd_node->list); | ||
| 955 | spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, | ||
| 956 | cmd_pending_q_flags); | ||
| 957 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); | 951 | mwifiex_insert_cmd_to_free_q(adapter, cmd_node); |
| 952 | mwifiex_complete_cmd(adapter, adapter->curr_cmd); | ||
| 953 | adapter->curr_cmd = NULL; | ||
| 958 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | 954 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); |
| 959 | } | 955 | } |
| 960 | 956 | ||
| @@ -981,7 +977,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) | |||
| 981 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); | 977 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); |
| 982 | } | 978 | } |
| 983 | adapter->cmd_wait_q.status = -1; | 979 | adapter->cmd_wait_q.status = -1; |
| 984 | mwifiex_complete_cmd(adapter, adapter->curr_cmd); | ||
| 985 | } | 980 | } |
| 986 | 981 | ||
| 987 | /* | 982 | /* |
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index dae8dbb24a03..8d3ab378662b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
| @@ -819,8 +819,10 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, | |||
| 819 | wildcard_ssid_tlv->header.len = cpu_to_le16( | 819 | wildcard_ssid_tlv->header.len = cpu_to_le16( |
| 820 | (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> | 820 | (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> |
| 821 | max_ssid_length))); | 821 | max_ssid_length))); |
| 822 | wildcard_ssid_tlv->max_ssid_length = | 822 | |
| 823 | user_scan_in->ssid_list[ssid_idx].max_len; | 823 | /* max_ssid_length = 0 tells firmware to perform |
| 824 | specific scan for the SSID filled */ | ||
| 825 | wildcard_ssid_tlv->max_ssid_length = 0; | ||
| 824 | 826 | ||
| 825 | memcpy(wildcard_ssid_tlv->ssid, | 827 | memcpy(wildcard_ssid_tlv->ssid, |
| 826 | user_scan_in->ssid_list[ssid_idx].ssid, | 828 | user_scan_in->ssid_list[ssid_idx].ssid, |
| @@ -1469,7 +1471,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, | |||
| 1469 | s32 rssi, const u8 *ie_buf, size_t ie_len, | 1471 | s32 rssi, const u8 *ie_buf, size_t ie_len, |
| 1470 | u16 beacon_period, u16 cap_info_bitmap, u8 band) | 1472 | u16 beacon_period, u16 cap_info_bitmap, u8 band) |
| 1471 | { | 1473 | { |
| 1472 | struct mwifiex_bssdescriptor *bss_desc = NULL; | 1474 | struct mwifiex_bssdescriptor *bss_desc; |
| 1473 | int ret; | 1475 | int ret; |
| 1474 | unsigned long flags; | 1476 | unsigned long flags; |
| 1475 | u8 *beacon_ie; | 1477 | u8 *beacon_ie; |
| @@ -1484,6 +1486,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, | |||
| 1484 | 1486 | ||
| 1485 | beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); | 1487 | beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); |
| 1486 | if (!beacon_ie) { | 1488 | if (!beacon_ie) { |
| 1489 | kfree(bss_desc); | ||
| 1487 | dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); | 1490 | dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); |
| 1488 | return -ENOMEM; | 1491 | return -ENOMEM; |
| 1489 | } | 1492 | } |
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index f18df82eeb92..78d0d6988553 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c | |||
| @@ -588,8 +588,6 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) | |||
| 588 | 588 | ||
| 589 | WARN_ON(priv->fw_state != FW_STATE_READY); | 589 | WARN_ON(priv->fw_state != FW_STATE_READY); |
| 590 | 590 | ||
| 591 | cancel_work_sync(&priv->work); | ||
| 592 | |||
| 593 | p54spi_power_off(priv); | 591 | p54spi_power_off(priv); |
| 594 | spin_lock_irqsave(&priv->tx_lock, flags); | 592 | spin_lock_irqsave(&priv->tx_lock, flags); |
| 595 | INIT_LIST_HEAD(&priv->tx_pending); | 593 | INIT_LIST_HEAD(&priv->tx_pending); |
| @@ -597,6 +595,8 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) | |||
| 597 | 595 | ||
| 598 | priv->fw_state = FW_STATE_OFF; | 596 | priv->fw_state = FW_STATE_OFF; |
| 599 | mutex_unlock(&priv->mutex); | 597 | mutex_unlock(&priv->mutex); |
| 598 | |||
| 599 | cancel_work_sync(&priv->work); | ||
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | static int __devinit p54spi_probe(struct spi_device *spi) | 602 | static int __devinit p54spi_probe(struct spi_device *spi) |
| @@ -656,6 +656,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) | |||
| 656 | init_completion(&priv->fw_comp); | 656 | init_completion(&priv->fw_comp); |
| 657 | INIT_LIST_HEAD(&priv->tx_pending); | 657 | INIT_LIST_HEAD(&priv->tx_pending); |
| 658 | mutex_init(&priv->mutex); | 658 | mutex_init(&priv->mutex); |
| 659 | spin_lock_init(&priv->tx_lock); | ||
| 659 | SET_IEEE80211_DEV(hw, &spi->dev); | 660 | SET_IEEE80211_DEV(hw, &spi->dev); |
| 660 | priv->common.open = p54spi_op_start; | 661 | priv->common.open = p54spi_op_start; |
| 661 | priv->common.stop = p54spi_op_stop; | 662 | priv->common.stop = p54spi_op_stop; |
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index d97a2caf582b..bc2ba80c47bb 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c | |||
| @@ -778,7 +778,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, | |||
| 778 | dwrq->flags = 0; | 778 | dwrq->flags = 0; |
| 779 | dwrq->length = 0; | 779 | dwrq->length = 0; |
| 780 | } | 780 | } |
| 781 | essid->octets[essid->length] = '\0'; | 781 | essid->octets[dwrq->length] = '\0'; |
| 782 | memcpy(extra, essid->octets, dwrq->length); | 782 | memcpy(extra, essid->octets, dwrq->length); |
| 783 | kfree(essid); | 783 | kfree(essid); |
| 784 | 784 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3f183a15186e..1ba079dffb11 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
| @@ -3771,7 +3771,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) | |||
| 3771 | /* Apparently the data is read from end to start */ | 3771 | /* Apparently the data is read from end to start */ |
| 3772 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); | 3772 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); |
| 3773 | /* The returned value is in CPU order, but eeprom is le */ | 3773 | /* The returned value is in CPU order, but eeprom is le */ |
| 3774 | rt2x00dev->eeprom[i] = cpu_to_le32(reg); | 3774 | *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); |
| 3775 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); | 3775 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); |
| 3776 | *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); | 3776 | *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); |
| 3777 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); | 3777 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1565792f270..377876315b8d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
| @@ -919,6 +919,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
| 919 | { USB_DEVICE(0x050d, 0x935b) }, | 919 | { USB_DEVICE(0x050d, 0x935b) }, |
| 920 | /* Buffalo */ | 920 | /* Buffalo */ |
| 921 | { USB_DEVICE(0x0411, 0x00e8) }, | 921 | { USB_DEVICE(0x0411, 0x00e8) }, |
| 922 | { USB_DEVICE(0x0411, 0x0158) }, | ||
| 922 | { USB_DEVICE(0x0411, 0x016f) }, | 923 | { USB_DEVICE(0x0411, 0x016f) }, |
| 923 | { USB_DEVICE(0x0411, 0x01a2) }, | 924 | { USB_DEVICE(0x0411, 0x01a2) }, |
| 924 | /* Corega */ | 925 | /* Corega */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2ec5c00235e6..99ff12d0c29d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
| @@ -943,6 +943,7 @@ struct rt2x00_dev { | |||
| 943 | * Powersaving work | 943 | * Powersaving work |
| 944 | */ | 944 | */ |
| 945 | struct delayed_work autowakeup_work; | 945 | struct delayed_work autowakeup_work; |
| 946 | struct work_struct sleep_work; | ||
| 946 | 947 | ||
| 947 | /* | 948 | /* |
| 948 | * Data queue arrays for RX, TX, Beacon and ATIM. | 949 | * Data queue arrays for RX, TX, Beacon and ATIM. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1fb2a8569be..edd317fa7c0a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
| @@ -465,6 +465,23 @@ static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) | |||
| 465 | return NULL; | 465 | return NULL; |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | static void rt2x00lib_sleep(struct work_struct *work) | ||
| 469 | { | ||
| 470 | struct rt2x00_dev *rt2x00dev = | ||
| 471 | container_of(work, struct rt2x00_dev, sleep_work); | ||
| 472 | |||
| 473 | if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | ||
| 474 | return; | ||
| 475 | |||
| 476 | /* | ||
| 477 | * Check again is powersaving is enabled, to prevent races from delayed | ||
| 478 | * work execution. | ||
| 479 | */ | ||
| 480 | if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) | ||
| 481 | rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, | ||
| 482 | IEEE80211_CONF_CHANGE_PS); | ||
| 483 | } | ||
| 484 | |||
| 468 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, | 485 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, |
| 469 | struct sk_buff *skb, | 486 | struct sk_buff *skb, |
| 470 | struct rxdone_entry_desc *rxdesc) | 487 | struct rxdone_entry_desc *rxdesc) |
| @@ -512,8 +529,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, | |||
| 512 | cam |= (tim_ie->bitmap_ctrl & 0x01); | 529 | cam |= (tim_ie->bitmap_ctrl & 0x01); |
| 513 | 530 | ||
| 514 | if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) | 531 | if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) |
| 515 | rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, | 532 | queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work); |
| 516 | IEEE80211_CONF_CHANGE_PS); | ||
| 517 | } | 533 | } |
| 518 | 534 | ||
| 519 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, | 535 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, |
| @@ -1141,6 +1157,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
| 1141 | 1157 | ||
| 1142 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); | 1158 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); |
| 1143 | INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); | 1159 | INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); |
| 1160 | INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); | ||
| 1144 | 1161 | ||
| 1145 | /* | 1162 | /* |
| 1146 | * Let the driver probe the device to detect the capabilities. | 1163 | * Let the driver probe the device to detect the capabilities. |
| @@ -1197,6 +1214,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) | |||
| 1197 | */ | 1214 | */ |
| 1198 | cancel_work_sync(&rt2x00dev->intf_work); | 1215 | cancel_work_sync(&rt2x00dev->intf_work); |
| 1199 | cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); | 1216 | cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); |
| 1217 | cancel_work_sync(&rt2x00dev->sleep_work); | ||
| 1200 | if (rt2x00_is_usb(rt2x00dev)) { | 1218 | if (rt2x00_is_usb(rt2x00dev)) { |
| 1201 | del_timer_sync(&rt2x00dev->txstatus_timer); | 1219 | del_timer_sync(&rt2x00dev->txstatus_timer); |
| 1202 | cancel_work_sync(&rt2x00dev->rxdone_work); | 1220 | cancel_work_sync(&rt2x00dev->rxdone_work); |
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index a693feffbe72..0b04b2e7b597 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c | |||
| @@ -394,7 +394,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) | |||
| 394 | if (mac->link_state != MAC80211_LINKED) | 394 | if (mac->link_state != MAC80211_LINKED) |
| 395 | return; | 395 | return; |
| 396 | 396 | ||
| 397 | spin_lock(&rtlpriv->locks.lps_lock); | 397 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
| 398 | 398 | ||
| 399 | /* Idle for a while if we connect to AP a while ago. */ | 399 | /* Idle for a while if we connect to AP a while ago. */ |
| 400 | if (mac->cnt_after_linked >= 2) { | 400 | if (mac->cnt_after_linked >= 2) { |
| @@ -406,7 +406,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) | |||
| 406 | } | 406 | } |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | spin_unlock(&rtlpriv->locks.lps_lock); | 409 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | /*Leave the leisure power save mode.*/ | 412 | /*Leave the leisure power save mode.*/ |
| @@ -415,8 +415,9 @@ void rtl_lps_leave(struct ieee80211_hw *hw) | |||
| 415 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 415 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
| 416 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 416 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
| 417 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | 417 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); |
| 418 | unsigned long flags; | ||
| 418 | 419 | ||
| 419 | spin_lock(&rtlpriv->locks.lps_lock); | 420 | spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags); |
| 420 | 421 | ||
| 421 | if (ppsc->fwctrl_lps) { | 422 | if (ppsc->fwctrl_lps) { |
| 422 | if (ppsc->dot11_psmode != EACTIVE) { | 423 | if (ppsc->dot11_psmode != EACTIVE) { |
| @@ -437,7 +438,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw) | |||
| 437 | rtl_lps_set_psmode(hw, EACTIVE); | 438 | rtl_lps_set_psmode(hw, EACTIVE); |
| 438 | } | 439 | } |
| 439 | } | 440 | } |
| 440 | spin_unlock(&rtlpriv->locks.lps_lock); | 441 | spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags); |
| 441 | } | 442 | } |
| 442 | 443 | ||
| 443 | /* For sw LPS*/ | 444 | /* For sw LPS*/ |
| @@ -538,9 +539,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) | |||
| 538 | RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); | 539 | RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); |
| 539 | } | 540 | } |
| 540 | 541 | ||
| 541 | spin_lock(&rtlpriv->locks.lps_lock); | 542 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
| 542 | rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); | 543 | rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); |
| 543 | spin_unlock(&rtlpriv->locks.lps_lock); | 544 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
| 544 | } | 545 | } |
| 545 | 546 | ||
| 546 | void rtl_swlps_rfon_wq_callback(void *data) | 547 | void rtl_swlps_rfon_wq_callback(void *data) |
| @@ -573,9 +574,9 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) | |||
| 573 | if (rtlpriv->link_info.busytraffic) | 574 | if (rtlpriv->link_info.busytraffic) |
| 574 | return; | 575 | return; |
| 575 | 576 | ||
| 576 | spin_lock(&rtlpriv->locks.lps_lock); | 577 | spin_lock_irq(&rtlpriv->locks.lps_lock); |
| 577 | rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); | 578 | rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); |
| 578 | spin_unlock(&rtlpriv->locks.lps_lock); | 579 | spin_unlock_irq(&rtlpriv->locks.lps_lock); |
| 579 | 580 | ||
| 580 | if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && | 581 | if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && |
| 581 | !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { | 582 | !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 592a10ac5929..3b585aadabfc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c | |||
| @@ -569,7 +569,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, | |||
| 569 | } | 569 | } |
| 570 | case ERFSLEEP:{ | 570 | case ERFSLEEP:{ |
| 571 | if (ppsc->rfpwr_state == ERFOFF) | 571 | if (ppsc->rfpwr_state == ERFOFF) |
| 572 | break; | 572 | return false; |
| 573 | for (queue_id = 0, i = 0; | 573 | for (queue_id = 0, i = 0; |
| 574 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { | 574 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { |
| 575 | ring = &pcipriv->dev.tx_ring[queue_id]; | 575 | ring = &pcipriv->dev.tx_ring[queue_id]; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 72852900df84..e49cf2244c75 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c | |||
| @@ -548,7 +548,7 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, | |||
| 548 | break; | 548 | break; |
| 549 | case ERFSLEEP: | 549 | case ERFSLEEP: |
| 550 | if (ppsc->rfpwr_state == ERFOFF) | 550 | if (ppsc->rfpwr_state == ERFOFF) |
| 551 | break; | 551 | return false; |
| 552 | for (queue_id = 0, i = 0; | 552 | for (queue_id = 0, i = 0; |
| 553 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { | 553 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { |
| 554 | ring = &pcipriv->dev.tx_ring[queue_id]; | 554 | ring = &pcipriv->dev.tx_ring[queue_id]; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 3ac7af1c5509..0883349e1c83 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c | |||
| @@ -3374,7 +3374,7 @@ bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, | |||
| 3374 | break; | 3374 | break; |
| 3375 | case ERFSLEEP: | 3375 | case ERFSLEEP: |
| 3376 | if (ppsc->rfpwr_state == ERFOFF) | 3376 | if (ppsc->rfpwr_state == ERFOFF) |
| 3377 | break; | 3377 | return false; |
| 3378 | 3378 | ||
| 3379 | for (queue_id = 0, i = 0; | 3379 | for (queue_id = 0, i = 0; |
| 3380 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { | 3380 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index f27171af979c..f10ac1ad9087 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c | |||
| @@ -602,7 +602,7 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, | |||
| 602 | } | 602 | } |
| 603 | case ERFSLEEP: | 603 | case ERFSLEEP: |
| 604 | if (ppsc->rfpwr_state == ERFOFF) | 604 | if (ppsc->rfpwr_state == ERFOFF) |
| 605 | break; | 605 | return false; |
| 606 | 606 | ||
| 607 | for (queue_id = 0, i = 0; | 607 | for (queue_id = 0, i = 0; |
| 608 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { | 608 | queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { |
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 128ccb79318c..fc29c671cf3b 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c | |||
| @@ -559,7 +559,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, | |||
| 559 | break; | 559 | break; |
| 560 | } | 560 | } |
| 561 | /* Fail if SSID isn't present in the filters */ | 561 | /* Fail if SSID isn't present in the filters */ |
| 562 | if (j == req->n_ssids) { | 562 | if (j == cmd->n_ssids) { |
| 563 | ret = -EINVAL; | 563 | ret = -EINVAL; |
| 564 | goto out_free; | 564 | goto out_free; |
| 565 | } | 565 | } |
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index e6ac3177fbbe..32c535f5ce31 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c | |||
| @@ -516,10 +516,14 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) | |||
| 516 | 516 | ||
| 517 | static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) | 517 | static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) |
| 518 | { | 518 | { |
| 519 | ssb_pcicore_fix_sprom_core_index(pc); | 519 | struct ssb_device *pdev = pc->dev; |
| 520 | struct ssb_bus *bus = pdev->bus; | ||
| 521 | |||
| 522 | if (bus->bustype == SSB_BUSTYPE_PCI) | ||
| 523 | ssb_pcicore_fix_sprom_core_index(pc); | ||
| 520 | 524 | ||
| 521 | /* Disable PCI interrupts. */ | 525 | /* Disable PCI interrupts. */ |
| 522 | ssb_write32(pc->dev, SSB_INTVEC, 0); | 526 | ssb_write32(pdev, SSB_INTVEC, 0); |
| 523 | 527 | ||
| 524 | /* Additional PCIe always once-executed workarounds */ | 528 | /* Additional PCIe always once-executed workarounds */ |
| 525 | if (pc->dev->id.coreid == SSB_DEV_PCIE) { | 529 | if (pc->dev->id.coreid == SSB_DEV_PCIE) { |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 92cf1c2c30c9..95852e36713b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
| @@ -456,6 +456,9 @@ enum station_parameters_apply_mask { | |||
| 456 | * as the AC bitmap in the QoS info field | 456 | * as the AC bitmap in the QoS info field |
| 457 | * @max_sp: max Service Period. same format as the MAX_SP in the | 457 | * @max_sp: max Service Period. same format as the MAX_SP in the |
| 458 | * QoS info field (but already shifted down) | 458 | * QoS info field (but already shifted down) |
| 459 | * @sta_modify_mask: bitmap indicating which parameters changed | ||
| 460 | * (for those that don't have a natural "no change" value), | ||
| 461 | * see &enum station_parameters_apply_mask | ||
| 459 | */ | 462 | */ |
| 460 | struct station_parameters { | 463 | struct station_parameters { |
| 461 | u8 *supported_rates; | 464 | u8 *supported_rates; |
| @@ -615,6 +618,7 @@ struct sta_bss_parameters { | |||
| 615 | * user space MLME/SME implementation. The information is provided for | 618 | * user space MLME/SME implementation. The information is provided for |
| 616 | * the cfg80211_new_sta() calls to notify user space of the IEs. | 619 | * the cfg80211_new_sta() calls to notify user space of the IEs. |
| 617 | * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets. | 620 | * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets. |
| 621 | * @sta_flags: station flags mask & values | ||
| 618 | */ | 622 | */ |
| 619 | struct station_info { | 623 | struct station_info { |
| 620 | u32 filled; | 624 | u32 filled; |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dc1123aa8181..72eddd1b410b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -3567,8 +3567,9 @@ rate_lowest_index(struct ieee80211_supported_band *sband, | |||
| 3567 | return i; | 3567 | return i; |
| 3568 | 3568 | ||
| 3569 | /* warn when we cannot find a rate. */ | 3569 | /* warn when we cannot find a rate. */ |
| 3570 | WARN_ON(1); | 3570 | WARN_ON_ONCE(1); |
| 3571 | 3571 | ||
| 3572 | /* and return 0 (the lowest index) */ | ||
| 3572 | return 0; | 3573 | return 0; |
| 3573 | } | 3574 | } |
| 3574 | 3575 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 2ac033989e01..d448f7a3dbc0 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -160,6 +160,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 160 | return -ENOENT; | 160 | return -ENOENT; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* if we're already stopping ignore any new requests to stop */ | ||
| 164 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
| 165 | spin_unlock_bh(&sta->lock); | ||
| 166 | return -EALREADY; | ||
| 167 | } | ||
| 168 | |||
| 163 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 169 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
| 164 | /* not even started yet! */ | 170 | /* not even started yet! */ |
| 165 | ieee80211_assign_tid_tx(sta, tid, NULL); | 171 | ieee80211_assign_tid_tx(sta, tid, NULL); |
| @@ -168,6 +174,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 168 | return 0; | 174 | return 0; |
| 169 | } | 175 | } |
| 170 | 176 | ||
| 177 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
| 178 | |||
| 171 | spin_unlock_bh(&sta->lock); | 179 | spin_unlock_bh(&sta->lock); |
| 172 | 180 | ||
| 173 | #ifdef CONFIG_MAC80211_HT_DEBUG | 181 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| @@ -175,8 +183,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 175 | sta->sta.addr, tid); | 183 | sta->sta.addr, tid); |
| 176 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 184 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
| 177 | 185 | ||
| 178 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
| 179 | |||
| 180 | del_timer_sync(&tid_tx->addba_resp_timer); | 186 | del_timer_sync(&tid_tx->addba_resp_timer); |
| 181 | 187 | ||
| 182 | /* | 188 | /* |
| @@ -186,6 +192,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
| 186 | */ | 192 | */ |
| 187 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 193 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
| 188 | 194 | ||
| 195 | /* | ||
| 196 | * There might be a few packets being processed right now (on | ||
| 197 | * another CPU) that have already gotten past the aggregation | ||
| 198 | * check when it was still OPERATIONAL and consequently have | ||
| 199 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
| 200 | * call into the driver at the same time or even before the | ||
| 201 | * TX paths calls into it, which could confuse the driver. | ||
| 202 | * | ||
| 203 | * Wait for all currently running TX paths to finish before | ||
| 204 | * telling the driver. New packets will not go through since | ||
| 205 | * the aggregation session is no longer OPERATIONAL. | ||
| 206 | */ | ||
| 207 | synchronize_net(); | ||
| 208 | |||
| 189 | tid_tx->stop_initiator = initiator; | 209 | tid_tx->stop_initiator = initiator; |
| 190 | tid_tx->tx_stop = tx; | 210 | tid_tx->tx_stop = tx; |
| 191 | 211 | ||
| @@ -282,6 +302,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
| 282 | __release(agg_queue); | 302 | __release(agg_queue); |
| 283 | } | 303 | } |
| 284 | 304 | ||
| 305 | /* | ||
| 306 | * splice packets from the STA's pending to the local pending, | ||
| 307 | * requires a call to ieee80211_agg_splice_finish later | ||
| 308 | */ | ||
| 309 | static void __acquires(agg_queue) | ||
| 310 | ieee80211_agg_splice_packets(struct ieee80211_local *local, | ||
| 311 | struct tid_ampdu_tx *tid_tx, u16 tid) | ||
| 312 | { | ||
| 313 | int queue = ieee80211_ac_from_tid(tid); | ||
| 314 | unsigned long flags; | ||
| 315 | |||
| 316 | ieee80211_stop_queue_agg(local, tid); | ||
| 317 | |||
| 318 | if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" | ||
| 319 | " from the pending queue\n", tid)) | ||
| 320 | return; | ||
| 321 | |||
| 322 | if (!skb_queue_empty(&tid_tx->pending)) { | ||
| 323 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
| 324 | /* copy over remaining packets */ | ||
| 325 | skb_queue_splice_tail_init(&tid_tx->pending, | ||
| 326 | &local->pending[queue]); | ||
| 327 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | static void __releases(agg_queue) | ||
| 332 | ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | ||
| 333 | { | ||
| 334 | ieee80211_wake_queue_agg(local, tid); | ||
| 335 | } | ||
| 336 | |||
| 285 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 337 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
| 286 | { | 338 | { |
| 287 | struct tid_ampdu_tx *tid_tx; | 339 | struct tid_ampdu_tx *tid_tx; |
| @@ -293,19 +345,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
| 293 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 345 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
| 294 | 346 | ||
| 295 | /* | 347 | /* |
| 296 | * While we're asking the driver about the aggregation, | 348 | * Start queuing up packets for this aggregation session. |
| 297 | * stop the AC queue so that we don't have to worry | 349 | * We're going to release them once the driver is OK with |
| 298 | * about frames that came in while we were doing that, | 350 | * that. |
| 299 | * which would require us to put them to the AC pending | ||
| 300 | * afterwards which just makes the code more complex. | ||
| 301 | */ | 351 | */ |
| 302 | ieee80211_stop_queue_agg(local, tid); | ||
| 303 | |||
| 304 | clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); | 352 | clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); |
| 305 | 353 | ||
| 306 | /* | 354 | /* |
| 307 | * make sure no packets are being processed to get | 355 | * Make sure no packets are being processed. This ensures that |
| 308 | * valid starting sequence number | 356 | * we have a valid starting sequence number and that in-flight |
| 357 | * packets have been flushed out and no packets for this TID | ||
| 358 | * will go into the driver during the ampdu_action call. | ||
| 309 | */ | 359 | */ |
| 310 | synchronize_net(); | 360 | synchronize_net(); |
| 311 | 361 | ||
| @@ -319,17 +369,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
| 319 | " tid %d\n", tid); | 369 | " tid %d\n", tid); |
| 320 | #endif | 370 | #endif |
| 321 | spin_lock_bh(&sta->lock); | 371 | spin_lock_bh(&sta->lock); |
| 372 | ieee80211_agg_splice_packets(local, tid_tx, tid); | ||
| 322 | ieee80211_assign_tid_tx(sta, tid, NULL); | 373 | ieee80211_assign_tid_tx(sta, tid, NULL); |
| 374 | ieee80211_agg_splice_finish(local, tid); | ||
| 323 | spin_unlock_bh(&sta->lock); | 375 | spin_unlock_bh(&sta->lock); |
| 324 | 376 | ||
| 325 | ieee80211_wake_queue_agg(local, tid); | ||
| 326 | kfree_rcu(tid_tx, rcu_head); | 377 | kfree_rcu(tid_tx, rcu_head); |
| 327 | return; | 378 | return; |
| 328 | } | 379 | } |
| 329 | 380 | ||
| 330 | /* we can take packets again now */ | ||
| 331 | ieee80211_wake_queue_agg(local, tid); | ||
| 332 | |||
| 333 | /* activate the timer for the recipient's addBA response */ | 381 | /* activate the timer for the recipient's addBA response */ |
| 334 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); | 382 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); |
| 335 | #ifdef CONFIG_MAC80211_HT_DEBUG | 383 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| @@ -445,38 +493,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
| 445 | } | 493 | } |
| 446 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 494 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
| 447 | 495 | ||
| 448 | /* | ||
| 449 | * splice packets from the STA's pending to the local pending, | ||
| 450 | * requires a call to ieee80211_agg_splice_finish later | ||
| 451 | */ | ||
| 452 | static void __acquires(agg_queue) | ||
| 453 | ieee80211_agg_splice_packets(struct ieee80211_local *local, | ||
| 454 | struct tid_ampdu_tx *tid_tx, u16 tid) | ||
| 455 | { | ||
| 456 | int queue = ieee80211_ac_from_tid(tid); | ||
| 457 | unsigned long flags; | ||
| 458 | |||
| 459 | ieee80211_stop_queue_agg(local, tid); | ||
| 460 | |||
| 461 | if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" | ||
| 462 | " from the pending queue\n", tid)) | ||
| 463 | return; | ||
| 464 | |||
| 465 | if (!skb_queue_empty(&tid_tx->pending)) { | ||
| 466 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
| 467 | /* copy over remaining packets */ | ||
| 468 | skb_queue_splice_tail_init(&tid_tx->pending, | ||
| 469 | &local->pending[queue]); | ||
| 470 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | static void __releases(agg_queue) | ||
| 475 | ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | ||
| 476 | { | ||
| 477 | ieee80211_wake_queue_agg(local, tid); | ||
| 478 | } | ||
| 479 | |||
| 480 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 496 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
| 481 | struct sta_info *sta, u16 tid) | 497 | struct sta_info *sta, u16 tid) |
| 482 | { | 498 | { |
| @@ -756,11 +772,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
| 756 | goto out; | 772 | goto out; |
| 757 | } | 773 | } |
| 758 | 774 | ||
| 759 | del_timer(&tid_tx->addba_resp_timer); | 775 | del_timer_sync(&tid_tx->addba_resp_timer); |
| 760 | 776 | ||
| 761 | #ifdef CONFIG_MAC80211_HT_DEBUG | 777 | #ifdef CONFIG_MAC80211_HT_DEBUG |
| 762 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 778 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
| 763 | #endif | 779 | #endif |
| 780 | |||
| 781 | /* | ||
| 782 | * addba_resp_timer may have fired before we got here, and | ||
| 783 | * caused WANT_STOP to be set. If the stop then was already | ||
| 784 | * processed further, STOPPING might be set. | ||
| 785 | */ | ||
| 786 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
| 787 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
| 788 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
| 789 | printk(KERN_DEBUG | ||
| 790 | "got addBA resp for tid %d but we already gave up\n", | ||
| 791 | tid); | ||
| 792 | #endif | ||
| 793 | goto out; | ||
| 794 | } | ||
| 795 | |||
| 764 | /* | 796 | /* |
| 765 | * IEEE 802.11-2007 7.3.1.14: | 797 | * IEEE 802.11-2007 7.3.1.14: |
| 766 | * In an ADDBA Response frame, when the Status Code field | 798 | * In an ADDBA Response frame, when the Status Code field |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c5f341798c16..3110cbdc501b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -274,9 +274,9 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
| 274 | 274 | ||
| 275 | PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); | 275 | PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); |
| 276 | 276 | ||
| 277 | PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " | ||
| 278 | "3839 bytes"); | ||
| 279 | PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " | 277 | PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " |
| 278 | "3839 bytes"); | ||
| 279 | PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " | ||
| 280 | "7935 bytes"); | 280 | "7935 bytes"); |
| 281 | 281 | ||
| 282 | /* | 282 | /* |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d999bf3b84e1..cae443563ec9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -757,6 +757,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 757 | if (!local->int_scan_req) | 757 | if (!local->int_scan_req) |
| 758 | return -ENOMEM; | 758 | return -ENOMEM; |
| 759 | 759 | ||
| 760 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
| 761 | if (!local->hw.wiphy->bands[band]) | ||
| 762 | continue; | ||
| 763 | local->int_scan_req->rates[band] = (u32) -1; | ||
| 764 | } | ||
| 765 | |||
| 760 | /* if low-level driver supports AP, we also support VLAN */ | 766 | /* if low-level driver supports AP, we also support VLAN */ |
| 761 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { | 767 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
| 762 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 768 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 17258feaab9b..40db011da580 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -1485,6 +1485,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
| 1485 | int i, j, err; | 1485 | int i, j, err; |
| 1486 | bool have_higher_than_11mbit = false; | 1486 | bool have_higher_than_11mbit = false; |
| 1487 | u16 ap_ht_cap_flags; | 1487 | u16 ap_ht_cap_flags; |
| 1488 | int min_rate = INT_MAX, min_rate_index = -1; | ||
| 1488 | 1489 | ||
| 1489 | /* AssocResp and ReassocResp have identical structure */ | 1490 | /* AssocResp and ReassocResp have identical structure */ |
| 1490 | 1491 | ||
| @@ -1551,6 +1552,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
| 1551 | rates |= BIT(j); | 1552 | rates |= BIT(j); |
| 1552 | if (is_basic) | 1553 | if (is_basic) |
| 1553 | basic_rates |= BIT(j); | 1554 | basic_rates |= BIT(j); |
| 1555 | if (rate < min_rate) { | ||
| 1556 | min_rate = rate; | ||
| 1557 | min_rate_index = j; | ||
| 1558 | } | ||
| 1554 | break; | 1559 | break; |
| 1555 | } | 1560 | } |
| 1556 | } | 1561 | } |
| @@ -1568,11 +1573,25 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
| 1568 | rates |= BIT(j); | 1573 | rates |= BIT(j); |
| 1569 | if (is_basic) | 1574 | if (is_basic) |
| 1570 | basic_rates |= BIT(j); | 1575 | basic_rates |= BIT(j); |
| 1576 | if (rate < min_rate) { | ||
| 1577 | min_rate = rate; | ||
| 1578 | min_rate_index = j; | ||
| 1579 | } | ||
| 1571 | break; | 1580 | break; |
| 1572 | } | 1581 | } |
| 1573 | } | 1582 | } |
| 1574 | } | 1583 | } |
| 1575 | 1584 | ||
| 1585 | /* | ||
| 1586 | * some buggy APs don't advertise basic_rates. use the lowest | ||
| 1587 | * supported rate instead. | ||
| 1588 | */ | ||
| 1589 | if (unlikely(!basic_rates) && min_rate_index >= 0) { | ||
| 1590 | printk(KERN_DEBUG "%s: No basic rates in AssocResp. " | ||
| 1591 | "Using min supported rate instead.\n", sdata->name); | ||
| 1592 | basic_rates = BIT(min_rate_index); | ||
| 1593 | } | ||
| 1594 | |||
| 1576 | sta->sta.supp_rates[wk->chan->band] = rates; | 1595 | sta->sta.supp_rates[wk->chan->band] = rates; |
| 1577 | sdata->vif.bss_conf.basic_rates = basic_rates; | 1596 | sdata->vif.bss_conf.basic_rates = basic_rates; |
| 1578 | 1597 | ||
| @@ -2267,6 +2286,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
| 2267 | 2286 | ||
| 2268 | cancel_work_sync(&ifmgd->request_smps_work); | 2287 | cancel_work_sync(&ifmgd->request_smps_work); |
| 2269 | 2288 | ||
| 2289 | cancel_work_sync(&ifmgd->monitor_work); | ||
| 2270 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2290 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
| 2271 | if (del_timer_sync(&ifmgd->timer)) | 2291 | if (del_timer_sync(&ifmgd->timer)) |
| 2272 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2292 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
| @@ -2275,7 +2295,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
| 2275 | if (del_timer_sync(&ifmgd->chswitch_timer)) | 2295 | if (del_timer_sync(&ifmgd->chswitch_timer)) |
| 2276 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | 2296 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); |
| 2277 | 2297 | ||
| 2278 | cancel_work_sync(&ifmgd->monitor_work); | ||
| 2279 | /* these will just be re-established on connection */ | 2298 | /* these will just be re-established on connection */ |
| 2280 | del_timer_sync(&ifmgd->conn_mon_timer); | 2299 | del_timer_sync(&ifmgd->conn_mon_timer); |
| 2281 | del_timer_sync(&ifmgd->bcn_mon_timer); | 2300 | del_timer_sync(&ifmgd->bcn_mon_timer); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b867bd55de7a..097b42d286e2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -140,8 +140,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 140 | pos++; | 140 | pos++; |
| 141 | 141 | ||
| 142 | /* IEEE80211_RADIOTAP_RATE */ | 142 | /* IEEE80211_RADIOTAP_RATE */ |
| 143 | if (status->flag & RX_FLAG_HT) { | 143 | if (!rate || status->flag & RX_FLAG_HT) { |
| 144 | /* | 144 | /* |
| 145 | * Without rate information don't add it. If we have, | ||
| 145 | * MCS information is a separate field in radiotap, | 146 | * MCS information is a separate field in radiotap, |
| 146 | * added below. The byte here is needed as padding | 147 | * added below. The byte here is needed as padding |
| 147 | * for the channel though, so initialise it to 0. | 148 | * for the channel though, so initialise it to 0. |
| @@ -162,12 +163,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 162 | else if (status->flag & RX_FLAG_HT) | 163 | else if (status->flag & RX_FLAG_HT) |
| 163 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 164 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, |
| 164 | pos); | 165 | pos); |
| 165 | else if (rate->flags & IEEE80211_RATE_ERP_G) | 166 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
| 166 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, | 167 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, |
| 167 | pos); | 168 | pos); |
| 168 | else | 169 | else if (rate) |
| 169 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, | 170 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, |
| 170 | pos); | 171 | pos); |
| 172 | else | ||
| 173 | put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos); | ||
| 171 | pos += 2; | 174 | pos += 2; |
| 172 | 175 | ||
| 173 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ | 176 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ce962d2c8782..8eaa746ec7a2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -1354,12 +1354,12 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1354 | * Use MoreData flag to indicate whether there are | 1354 | * Use MoreData flag to indicate whether there are |
| 1355 | * more buffered frames for this STA | 1355 | * more buffered frames for this STA |
| 1356 | */ | 1356 | */ |
| 1357 | if (!more_data) | 1357 | if (more_data || !skb_queue_empty(&frames)) |
| 1358 | hdr->frame_control &= | ||
| 1359 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
| 1360 | else | ||
| 1361 | hdr->frame_control |= | 1358 | hdr->frame_control |= |
| 1362 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1359 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
| 1360 | else | ||
| 1361 | hdr->frame_control &= | ||
| 1362 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
| 1363 | 1363 | ||
| 1364 | if (ieee80211_is_data_qos(hdr->frame_control) || | 1364 | if (ieee80211_is_data_qos(hdr->frame_control) || |
| 1365 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | 1365 | ieee80211_is_qos_nullfunc(hdr->frame_control)) |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index df643cedf9b9..5533a74e9bb3 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -259,7 +259,7 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
| 259 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 259 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
| 260 | struct ieee80211_radiotap_header *rthdr; | 260 | struct ieee80211_radiotap_header *rthdr; |
| 261 | unsigned char *pos; | 261 | unsigned char *pos; |
| 262 | __le16 txflags; | 262 | u16 txflags; |
| 263 | 263 | ||
| 264 | rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len); | 264 | rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len); |
| 265 | 265 | ||
| @@ -289,13 +289,13 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
| 289 | txflags = 0; | 289 | txflags = 0; |
| 290 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 290 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
| 291 | !is_multicast_ether_addr(hdr->addr1)) | 291 | !is_multicast_ether_addr(hdr->addr1)) |
| 292 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); | 292 | txflags |= IEEE80211_RADIOTAP_F_TX_FAIL; |
| 293 | 293 | ||
| 294 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || | 294 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || |
| 295 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) | 295 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) |
| 296 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); | 296 | txflags |= IEEE80211_RADIOTAP_F_TX_CTS; |
| 297 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) | 297 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) |
| 298 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); | 298 | txflags |= IEEE80211_RADIOTAP_F_TX_RTS; |
| 299 | 299 | ||
| 300 | put_unaligned_le16(txflags, pos); | 300 | put_unaligned_le16(txflags, pos); |
| 301 | pos += 2; | 301 | pos += 2; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7439d26bf5f9..6719bce4a081 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -880,6 +880,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 880 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 880 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
| 881 | ssid, ssid_len, | 881 | ssid, ssid_len, |
| 882 | buf, buf_len); | 882 | buf, buf_len); |
| 883 | if (!skb) | ||
| 884 | goto out; | ||
| 883 | 885 | ||
| 884 | if (dst) { | 886 | if (dst) { |
| 885 | mgmt = (struct ieee80211_mgmt *) skb->data; | 887 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -888,6 +890,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 888 | } | 890 | } |
| 889 | 891 | ||
| 890 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 892 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 893 | |||
| 894 | out: | ||
| 891 | kfree(buf); | 895 | kfree(buf); |
| 892 | 896 | ||
| 893 | return skb; | 897 | return skb; |
| @@ -1034,7 +1038,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1034 | struct ieee80211_sub_if_data, | 1038 | struct ieee80211_sub_if_data, |
| 1035 | u.ap); | 1039 | u.ap); |
| 1036 | 1040 | ||
| 1037 | memset(&sta->sta.drv_priv, 0, hw->sta_data_size); | ||
| 1038 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); | 1041 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
| 1039 | } | 1042 | } |
| 1040 | } | 1043 | } |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 4047e29acb3b..25dae3f8f5c2 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
| @@ -68,7 +68,7 @@ static int __nci_request(struct nci_dev *ndev, | |||
| 68 | __u32 timeout) | 68 | __u32 timeout) |
| 69 | { | 69 | { |
| 70 | int rc = 0; | 70 | int rc = 0; |
| 71 | unsigned long completion_rc; | 71 | long completion_rc; |
| 72 | 72 | ||
| 73 | ndev->req_status = NCI_REQ_PEND; | 73 | ndev->req_status = NCI_REQ_PEND; |
| 74 | 74 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48260c2d092a..ffafda5022c2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -89,8 +89,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
| 90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
| 91 | 91 | ||
| 92 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 92 | [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, |
| 93 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 93 | [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, |
| 94 | 94 | ||
| 95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
| 96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
| @@ -132,8 +132,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, | 132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
| 133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, | 133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, |
| 134 | 134 | ||
| 135 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 135 | [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, |
| 136 | .len = NL80211_HT_CAPABILITY_LEN }, | ||
| 137 | 136 | ||
| 138 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 137 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
| 139 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 138 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
| @@ -1253,6 +1252,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 1253 | goto bad_res; | 1252 | goto bad_res; |
| 1254 | } | 1253 | } |
| 1255 | 1254 | ||
| 1255 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
| 1256 | netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
| 1257 | result = -EINVAL; | ||
| 1258 | goto bad_res; | ||
| 1259 | } | ||
| 1260 | |||
| 1256 | nla_for_each_nested(nl_txq_params, | 1261 | nla_for_each_nested(nl_txq_params, |
| 1257 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 1262 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
| 1258 | rem_txq_params) { | 1263 | rem_txq_params) { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2520a1b7e7db..074c1122ce42 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -55,8 +55,17 @@ | |||
| 55 | #define REG_DBG_PRINT(args...) | 55 | #define REG_DBG_PRINT(args...) |
| 56 | #endif | 56 | #endif |
| 57 | 57 | ||
| 58 | static struct regulatory_request core_request_world = { | ||
| 59 | .initiator = NL80211_REGDOM_SET_BY_CORE, | ||
| 60 | .alpha2[0] = '0', | ||
| 61 | .alpha2[1] = '0', | ||
| 62 | .intersect = false, | ||
| 63 | .processed = true, | ||
| 64 | .country_ie_env = ENVIRON_ANY, | ||
| 65 | }; | ||
| 66 | |||
| 58 | /* Receipt of information from last regulatory request */ | 67 | /* Receipt of information from last regulatory request */ |
| 59 | static struct regulatory_request *last_request; | 68 | static struct regulatory_request *last_request = &core_request_world; |
| 60 | 69 | ||
| 61 | /* To trigger userspace events */ | 70 | /* To trigger userspace events */ |
| 62 | static struct platform_device *reg_pdev; | 71 | static struct platform_device *reg_pdev; |
| @@ -148,7 +157,7 @@ static char user_alpha2[2]; | |||
| 148 | module_param(ieee80211_regdom, charp, 0444); | 157 | module_param(ieee80211_regdom, charp, 0444); |
| 149 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 158 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
| 150 | 159 | ||
| 151 | static void reset_regdomains(void) | 160 | static void reset_regdomains(bool full_reset) |
| 152 | { | 161 | { |
| 153 | /* avoid freeing static information or freeing something twice */ | 162 | /* avoid freeing static information or freeing something twice */ |
| 154 | if (cfg80211_regdomain == cfg80211_world_regdom) | 163 | if (cfg80211_regdomain == cfg80211_world_regdom) |
| @@ -163,6 +172,13 @@ static void reset_regdomains(void) | |||
| 163 | 172 | ||
| 164 | cfg80211_world_regdom = &world_regdom; | 173 | cfg80211_world_regdom = &world_regdom; |
| 165 | cfg80211_regdomain = NULL; | 174 | cfg80211_regdomain = NULL; |
| 175 | |||
| 176 | if (!full_reset) | ||
| 177 | return; | ||
| 178 | |||
| 179 | if (last_request != &core_request_world) | ||
| 180 | kfree(last_request); | ||
| 181 | last_request = &core_request_world; | ||
| 166 | } | 182 | } |
| 167 | 183 | ||
| 168 | /* | 184 | /* |
| @@ -173,7 +189,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd) | |||
| 173 | { | 189 | { |
| 174 | BUG_ON(!last_request); | 190 | BUG_ON(!last_request); |
| 175 | 191 | ||
| 176 | reset_regdomains(); | 192 | reset_regdomains(false); |
| 177 | 193 | ||
| 178 | cfg80211_world_regdom = rd; | 194 | cfg80211_world_regdom = rd; |
| 179 | cfg80211_regdomain = rd; | 195 | cfg80211_regdomain = rd; |
| @@ -1405,7 +1421,8 @@ static int __regulatory_hint(struct wiphy *wiphy, | |||
| 1405 | } | 1421 | } |
| 1406 | 1422 | ||
| 1407 | new_request: | 1423 | new_request: |
| 1408 | kfree(last_request); | 1424 | if (last_request != &core_request_world) |
| 1425 | kfree(last_request); | ||
| 1409 | 1426 | ||
| 1410 | last_request = pending_request; | 1427 | last_request = pending_request; |
| 1411 | last_request->intersect = intersect; | 1428 | last_request->intersect = intersect; |
| @@ -1575,9 +1592,6 @@ static int regulatory_hint_core(const char *alpha2) | |||
| 1575 | { | 1592 | { |
| 1576 | struct regulatory_request *request; | 1593 | struct regulatory_request *request; |
| 1577 | 1594 | ||
| 1578 | kfree(last_request); | ||
| 1579 | last_request = NULL; | ||
| 1580 | |||
| 1581 | request = kzalloc(sizeof(struct regulatory_request), | 1595 | request = kzalloc(sizeof(struct regulatory_request), |
| 1582 | GFP_KERNEL); | 1596 | GFP_KERNEL); |
| 1583 | if (!request) | 1597 | if (!request) |
| @@ -1775,7 +1789,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
| 1775 | mutex_lock(&cfg80211_mutex); | 1789 | mutex_lock(&cfg80211_mutex); |
| 1776 | mutex_lock(®_mutex); | 1790 | mutex_lock(®_mutex); |
| 1777 | 1791 | ||
| 1778 | reset_regdomains(); | 1792 | reset_regdomains(true); |
| 1779 | restore_alpha2(alpha2, reset_user); | 1793 | restore_alpha2(alpha2, reset_user); |
| 1780 | 1794 | ||
| 1781 | /* | 1795 | /* |
| @@ -2035,12 +2049,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2035 | } | 2049 | } |
| 2036 | 2050 | ||
| 2037 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2051 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
| 2052 | if (!request_wiphy && | ||
| 2053 | (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
| 2054 | last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { | ||
| 2055 | schedule_delayed_work(®_timeout, 0); | ||
| 2056 | return -ENODEV; | ||
| 2057 | } | ||
| 2038 | 2058 | ||
| 2039 | if (!last_request->intersect) { | 2059 | if (!last_request->intersect) { |
| 2040 | int r; | 2060 | int r; |
| 2041 | 2061 | ||
| 2042 | if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { | 2062 | if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { |
| 2043 | reset_regdomains(); | 2063 | reset_regdomains(false); |
| 2044 | cfg80211_regdomain = rd; | 2064 | cfg80211_regdomain = rd; |
| 2045 | return 0; | 2065 | return 0; |
| 2046 | } | 2066 | } |
| @@ -2061,7 +2081,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2061 | if (r) | 2081 | if (r) |
| 2062 | return r; | 2082 | return r; |
| 2063 | 2083 | ||
| 2064 | reset_regdomains(); | 2084 | reset_regdomains(false); |
| 2065 | cfg80211_regdomain = rd; | 2085 | cfg80211_regdomain = rd; |
| 2066 | return 0; | 2086 | return 0; |
| 2067 | } | 2087 | } |
| @@ -2086,7 +2106,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2086 | 2106 | ||
| 2087 | rd = NULL; | 2107 | rd = NULL; |
| 2088 | 2108 | ||
| 2089 | reset_regdomains(); | 2109 | reset_regdomains(false); |
| 2090 | cfg80211_regdomain = intersected_rd; | 2110 | cfg80211_regdomain = intersected_rd; |
| 2091 | 2111 | ||
| 2092 | return 0; | 2112 | return 0; |
| @@ -2106,7 +2126,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2106 | kfree(rd); | 2126 | kfree(rd); |
| 2107 | rd = NULL; | 2127 | rd = NULL; |
| 2108 | 2128 | ||
| 2109 | reset_regdomains(); | 2129 | reset_regdomains(false); |
| 2110 | cfg80211_regdomain = intersected_rd; | 2130 | cfg80211_regdomain = intersected_rd; |
| 2111 | 2131 | ||
| 2112 | return 0; | 2132 | return 0; |
| @@ -2259,9 +2279,9 @@ void /* __init_or_exit */ regulatory_exit(void) | |||
| 2259 | mutex_lock(&cfg80211_mutex); | 2279 | mutex_lock(&cfg80211_mutex); |
| 2260 | mutex_lock(®_mutex); | 2280 | mutex_lock(®_mutex); |
| 2261 | 2281 | ||
| 2262 | reset_regdomains(); | 2282 | reset_regdomains(true); |
| 2263 | 2283 | ||
| 2264 | kfree(last_request); | 2284 | dev_set_uevent_suppress(®_pdev->dev, true); |
| 2265 | 2285 | ||
| 2266 | platform_device_unregister(reg_pdev); | 2286 | platform_device_unregister(reg_pdev); |
| 2267 | 2287 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0fb142410404..dc23b31594e0 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -259,17 +259,20 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) | |||
| 259 | { | 259 | { |
| 260 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); | 260 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); |
| 261 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); | 261 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); |
| 262 | int r; | ||
| 263 | 262 | ||
| 263 | /* equal if both missing */ | ||
| 264 | if (!ie1 && !ie2) | 264 | if (!ie1 && !ie2) |
| 265 | return 0; | 265 | return 0; |
| 266 | if (!ie1 || !ie2) | 266 | /* sort missing IE before (left of) present IE */ |
| 267 | if (!ie1) | ||
| 267 | return -1; | 268 | return -1; |
| 269 | if (!ie2) | ||
| 270 | return 1; | ||
| 268 | 271 | ||
| 269 | r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1])); | 272 | /* sort by length first, then by contents */ |
| 270 | if (r == 0 && ie1[1] != ie2[1]) | 273 | if (ie1[1] != ie2[1]) |
| 271 | return ie2[1] - ie1[1]; | 274 | return ie2[1] - ie1[1]; |
| 272 | return r; | 275 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); |
| 273 | } | 276 | } |
| 274 | 277 | ||
| 275 | static bool is_bss(struct cfg80211_bss *a, | 278 | static bool is_bss(struct cfg80211_bss *a, |
