aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath9k/core.h6
-rw-r--r--drivers/net/wireless/ath9k/main.c41
-rw-r--r--drivers/net/wireless/ath9k/rc.c8
-rw-r--r--drivers/net/wireless/ath9k/recv.c3
-rw-r--r--drivers/net/wireless/ath9k/xmit.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c33
-rw-r--r--include/net/mac80211.h59
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/ht.c181
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/mlme.c88
15 files changed, 260 insertions, 274 deletions
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index cb3e61e57c4d..59d835b72cd8 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -380,7 +380,6 @@ void ath_rx_cleanup(struct ath_softc *sc);
380int ath_rx_tasklet(struct ath_softc *sc, int flush); 380int ath_rx_tasklet(struct ath_softc *sc, int flush);
381int ath_rx_input(struct ath_softc *sc, 381int ath_rx_input(struct ath_softc *sc,
382 struct ath_node *node, 382 struct ath_node *node,
383 int is_ampdu,
384 struct sk_buff *skb, 383 struct sk_buff *skb,
385 struct ath_recv_status *rx_status, 384 struct ath_recv_status *rx_status,
386 enum ATH_RX_TYPE *status); 385 enum ATH_RX_TYPE *status);
@@ -650,6 +649,9 @@ struct ath_node {
650 u8 an_smmode; /* SM Power save mode */ 649 u8 an_smmode; /* SM Power save mode */
651 u8 an_flags; 650 u8 an_flags;
652 u8 an_addr[ETH_ALEN]; 651 u8 an_addr[ETH_ALEN];
652
653 u16 maxampdu;
654 u8 mpdudensity;
653}; 655};
654 656
655void ath_tx_resume_tid(struct ath_softc *sc, 657void ath_tx_resume_tid(struct ath_softc *sc,
@@ -919,8 +921,6 @@ enum RATE_TYPE {
919 921
920struct ath_ht_info { 922struct ath_ht_info {
921 enum ath9k_ht_macmode tx_chan_width; 923 enum ath9k_ht_macmode tx_chan_width;
922 u16 maxampdu;
923 u8 mpdudensity;
924 u8 ext_chan_offset; 924 u8 ext_chan_offset;
925}; 925};
926 926
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 41cd114c438c..7555c3413384 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -330,25 +330,15 @@ static void ath9k_ht_conf(struct ath_softc *sc,
330{ 330{
331 struct ath_ht_info *ht_info = &sc->sc_ht_info; 331 struct ath_ht_info *ht_info = &sc->sc_ht_info;
332 332
333 if (bss_conf->assoc_ht) { 333 if (sc->hw->conf.ht.enabled) {
334 ht_info->ext_chan_offset = 334 ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset;
335 bss_conf->ht_bss_conf->bss_cap & 335
336 IEEE80211_HT_PARAM_CHA_SEC_OFFSET; 336 if (bss_conf->ht.width_40_ok)
337
338 if (!(bss_conf->ht_cap->cap &
339 IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
340 (bss_conf->ht_bss_conf->bss_cap &
341 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
342 ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; 337 ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
343 else 338 else
344 ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; 339 ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
345 340
346 ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); 341 ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
347 ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
348 bss_conf->ht_cap->ampdu_factor);
349 ht_info->mpdudensity =
350 parse_mpdudensity(bss_conf->ht_cap->ampdu_density);
351
352 } 342 }
353} 343}
354 344
@@ -390,7 +380,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
390 sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; 380 sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
391 381
392 /* Update chainmask */ 382 /* Update chainmask */
393 ath_update_chainmask(sc, bss_conf->assoc_ht); 383 ath_update_chainmask(sc, hw->conf.ht.enabled);
394 384
395 DPRINTF(sc, ATH_DBG_CONFIG, 385 DPRINTF(sc, ATH_DBG_CONFIG,
396 "%s: bssid %pM aid 0x%x\n", 386 "%s: bssid %pM aid 0x%x\n",
@@ -408,7 +398,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
408 return; 398 return;
409 } 399 }
410 400
411 if (hw->conf.ht_cap.ht_supported) 401 if (hw->conf.ht.enabled)
412 sc->sc_ah->ah_channels[pos].chanmode = 402 sc->sc_ah->ah_channels[pos].chanmode =
413 ath_get_extchanmode(sc, curchan); 403 ath_get_extchanmode(sc, curchan);
414 else 404 else
@@ -531,7 +521,6 @@ int _ath_rx_indicate(struct ath_softc *sc,
531 521
532 if (an) { 522 if (an) {
533 ath_rx_input(sc, an, 523 ath_rx_input(sc, an,
534 hw->conf.ht_cap.ht_supported,
535 skb, status, &st); 524 skb, status, &st);
536 } 525 }
537 if (!an || (st != ATH_RX_CONSUMED)) 526 if (!an || (st != ATH_RX_CONSUMED))
@@ -1241,6 +1230,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1241 __func__, 1230 __func__,
1242 curchan->center_freq); 1231 curchan->center_freq);
1243 1232
1233 /* Update chainmask */
1234 ath_update_chainmask(sc, conf->ht.enabled);
1235
1244 pos = ath_get_channel(sc, curchan); 1236 pos = ath_get_channel(sc, curchan);
1245 if (pos == -1) { 1237 if (pos == -1) {
1246 DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); 1238 DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
@@ -1251,7 +1243,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1251 (curchan->band == IEEE80211_BAND_2GHZ) ? 1243 (curchan->band == IEEE80211_BAND_2GHZ) ?
1252 CHANNEL_G : CHANNEL_A; 1244 CHANNEL_G : CHANNEL_A;
1253 1245
1254 if (sc->sc_curaid && hw->conf.ht_cap.ht_supported) 1246 if (sc->sc_curaid && hw->conf.ht.enabled)
1255 sc->sc_ah->ah_channels[pos].chanmode = 1247 sc->sc_ah->ah_channels[pos].chanmode =
1256 ath_get_extchanmode(sc, curchan); 1248 ath_get_extchanmode(sc, curchan);
1257 1249
@@ -1434,6 +1426,14 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
1434 } else { 1426 } else {
1435 ath_node_get(sc, sta->addr); 1427 ath_node_get(sc, sta->addr);
1436 } 1428 }
1429
1430 /* XXX: Is this right? Can the capabilities change? */
1431 an = ath_node_find(sc, sta->addr);
1432 an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
1433 sta->ht_cap.ampdu_factor);
1434 an->mpdudensity =
1435 parse_mpdudensity(sta->ht_cap.ampdu_density);
1436
1437 spin_unlock_irqrestore(&sc->node_lock, flags); 1437 spin_unlock_irqrestore(&sc->node_lock, flags);
1438 break; 1438 break;
1439 case STA_NOTIFY_REMOVE: 1439 case STA_NOTIFY_REMOVE:
@@ -1552,9 +1552,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1552 } 1552 }
1553 1553
1554 if (changed & BSS_CHANGED_HT) { 1554 if (changed & BSS_CHANGED_HT) {
1555 DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", 1555 DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n",
1556 __func__, 1556 __func__);
1557 bss_conf->assoc_ht);
1558 ath9k_ht_conf(sc, bss_conf); 1557 ath9k_ht_conf(sc, bss_conf);
1559 } 1558 }
1560 1559
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index ee2dbce42b4d..9b2526030965 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
1838 struct ath_softc *sc = hw->priv; 1838 struct ath_softc *sc = hw->priv;
1839 u32 capflag = 0; 1839 u32 capflag = 0;
1840 1840
1841 if (hw->conf.ht_cap.ht_supported) { 1841 if (hw->conf.ht.enabled) {
1842 capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; 1842 capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
1843 if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) 1843 if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
1844 capflag |= ATH_RC_CW40_FLAG; 1844 capflag |= ATH_RC_CW40_FLAG;
@@ -1979,7 +1979,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
1979 1979
1980 /* Check if aggregation has to be enabled for this tid */ 1980 /* Check if aggregation has to be enabled for this tid */
1981 1981
1982 if (hw->conf.ht_cap.ht_supported) { 1982 if (hw->conf.ht.enabled) {
1983 if (ieee80211_is_data_qos(fc)) { 1983 if (ieee80211_is_data_qos(fc)) {
1984 qc = ieee80211_get_qos_ctl(hdr); 1984 qc = ieee80211_get_qos_ctl(hdr);
1985 tid = qc[0] & 0xf; 1985 tid = qc[0] & 0xf;
@@ -2026,9 +2026,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
2026 DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); 2026 DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
2027 2027
2028 ath_setup_rates(sc, sband, sta, ath_rc_priv); 2028 ath_setup_rates(sc, sband, sta, ath_rc_priv);
2029 if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { 2029 if (sc->hw->conf.ht.enabled) {
2030 for (i = 0; i < 77; i++) { 2030 for (i = 0; i < 77; i++) {
2031 if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) 2031 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
2032 ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; 2032 ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
2033 if (j == ATH_RATE_MAX) 2033 if (j == ATH_RATE_MAX)
2034 break; 2034 break;
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 010fcdfec3f6..828322840a86 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -720,12 +720,11 @@ void ath_flushrecv(struct ath_softc *sc)
720 720
721int ath_rx_input(struct ath_softc *sc, 721int ath_rx_input(struct ath_softc *sc,
722 struct ath_node *an, 722 struct ath_node *an,
723 int is_ampdu,
724 struct sk_buff *skb, 723 struct sk_buff *skb,
725 struct ath_recv_status *rx_status, 724 struct ath_recv_status *rx_status,
726 enum ATH_RX_TYPE *status) 725 enum ATH_RX_TYPE *status)
727{ 726{
728 if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { 727 if (sc->sc_flags & SC_OP_RXAGGR) {
729 *status = ATH_RX_CONSUMED; 728 *status = ATH_RX_CONSUMED;
730 return ath_ampdu_input(sc, an, skb, rx_status); 729 return ath_ampdu_input(sc, an, skb, rx_status);
731 } else { 730 } else {
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3770fbe84fce..ba818cc2fb5c 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -300,7 +300,8 @@ static int ath_tx_prepare(struct ath_softc *sc,
300 if (ieee80211_is_data(fc) && !txctl->use_minrate) { 300 if (ieee80211_is_data(fc) && !txctl->use_minrate) {
301 301
302 /* Enable HT only for DATA frames and not for EAPOL */ 302 /* Enable HT only for DATA frames and not for EAPOL */
303 txctl->ht = (hw->conf.ht_cap.ht_supported && 303 /* XXX why AMPDU only?? */
304 txctl->ht = (hw->conf.ht.enabled &&
304 (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); 305 (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
305 306
306 if (is_multicast_ether_addr(hdr->addr1)) { 307 if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1450,7 +1451,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
1450 */ 1451 */
1451 1452
1452static u32 ath_lookup_rate(struct ath_softc *sc, 1453static u32 ath_lookup_rate(struct ath_softc *sc,
1453 struct ath_buf *bf) 1454 struct ath_buf *bf,
1455 struct ath_atx_tid *tid)
1454{ 1456{
1455 const struct ath9k_rate_table *rt = sc->sc_currates; 1457 const struct ath9k_rate_table *rt = sc->sc_currates;
1456 struct sk_buff *skb; 1458 struct sk_buff *skb;
@@ -1504,7 +1506,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
1504 * The IE, however can hold upto 65536, which shows up here 1506 * The IE, however can hold upto 65536, which shows up here
1505 * as zero. Ignore 65536 since we are constrained by hw. 1507 * as zero. Ignore 65536 since we are constrained by hw.
1506 */ 1508 */
1507 maxampdu = sc->sc_ht_info.maxampdu; 1509 maxampdu = tid->an->maxampdu;
1508 if (maxampdu) 1510 if (maxampdu)
1509 aggr_limit = min(aggr_limit, maxampdu); 1511 aggr_limit = min(aggr_limit, maxampdu);
1510 1512
@@ -1518,6 +1520,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
1518 */ 1520 */
1519 1521
1520static int ath_compute_num_delims(struct ath_softc *sc, 1522static int ath_compute_num_delims(struct ath_softc *sc,
1523 struct ath_atx_tid *tid,
1521 struct ath_buf *bf, 1524 struct ath_buf *bf,
1522 u16 frmlen) 1525 u16 frmlen)
1523{ 1526{
@@ -1545,7 +1548,7 @@ static int ath_compute_num_delims(struct ath_softc *sc,
1545 * required minimum length for subframe. Take into account 1548 * required minimum length for subframe. Take into account
1546 * whether high rate is 20 or 40Mhz and half or full GI. 1549 * whether high rate is 20 or 40Mhz and half or full GI.
1547 */ 1550 */
1548 mpdudensity = sc->sc_ht_info.mpdudensity; 1551 mpdudensity = tid->an->mpdudensity;
1549 1552
1550 /* 1553 /*
1551 * If there is no mpdu density restriction, no further calculation 1554 * If there is no mpdu density restriction, no further calculation
@@ -1619,7 +1622,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
1619 } 1622 }
1620 1623
1621 if (!rl) { 1624 if (!rl) {
1622 aggr_limit = ath_lookup_rate(sc, bf); 1625 aggr_limit = ath_lookup_rate(sc, bf, tid);
1623 rl = 1; 1626 rl = 1;
1624 /* 1627 /*
1625 * Is rate dual stream 1628 * Is rate dual stream
@@ -1657,7 +1660,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
1657 * Get the delimiters needed to meet the MPDU 1660 * Get the delimiters needed to meet the MPDU
1658 * density for this node. 1661 * density for this node.
1659 */ 1662 */
1660 ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen); 1663 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
1661 1664
1662 bpad = PADBYTES(al_delta) + (ndelim << 2); 1665 bpad = PADBYTES(al_delta) + (ndelim << 2);
1663 1666
@@ -2629,7 +2632,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2629 struct ath_atx_ac *ac; 2632 struct ath_atx_ac *ac;
2630 int tidno, acno; 2633 int tidno, acno;
2631 2634
2632 sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; 2635 an->maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
2633 2636
2634 /* 2637 /*
2635 * Init per tid tx state 2638 * Init per tid tx state
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cd1bff590491..e10e0ca09ce9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1133,8 +1133,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
1133 s32 rate; 1133 s32 rate;
1134 s8 is_green = lq_sta->is_green; 1134 s8 is_green = lq_sta->is_green;
1135 1135
1136 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || 1136 if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
1137 !sta->ht_cap.ht_supported)
1138 return -1; 1137 return -1;
1139 1138
1140 if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) 1139 if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
@@ -1201,8 +1200,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
1201 u8 is_green = lq_sta->is_green; 1200 u8 is_green = lq_sta->is_green;
1202 s32 rate; 1201 s32 rate;
1203 1202
1204 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || 1203 if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
1205 !sta->ht_cap.ht_supported)
1206 return -1; 1204 return -1;
1207 1205
1208 IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); 1206 IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@@ -2001,9 +1999,8 @@ lq_update:
2001 * stay with best antenna legacy modulation for a while 1999 * stay with best antenna legacy modulation for a while
2002 * before next round of mode comparisons. */ 2000 * before next round of mode comparisons. */
2003 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); 2001 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
2004 if (is_legacy(tbl1->lq_type) && 2002 if (is_legacy(tbl1->lq_type) && !conf->ht.enabled &&
2005 (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && 2003 lq_sta->action_counter >= 1) {
2006 (lq_sta->action_counter >= 1)) {
2007 lq_sta->action_counter = 0; 2004 lq_sta->action_counter = 0;
2008 IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); 2005 IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
2009 rs_set_stay_in_table(priv, 1, lq_sta); 2006 rs_set_stay_in_table(priv, 1, lq_sta);
@@ -2238,19 +2235,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
2238 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), 2235 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
2239 * supp_rates[] does not; shift to convert format, force 9 MBits off. 2236 * supp_rates[] does not; shift to convert format, force 9 MBits off.
2240 */ 2237 */
2241 lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1; 2238 lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
2242 lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1; 2239 lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
2243 lq_sta->active_siso_rate &= ~((u16)0x2); 2240 lq_sta->active_siso_rate &= ~((u16)0x2);
2244 lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; 2241 lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
2245 2242
2246 /* Same here */ 2243 /* Same here */
2247 lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1; 2244 lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
2248 lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1; 2245 lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
2249 lq_sta->active_mimo2_rate &= ~((u16)0x2); 2246 lq_sta->active_mimo2_rate &= ~((u16)0x2);
2250 lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; 2247 lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
2251 2248
2252 lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1; 2249 lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
2253 lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1; 2250 lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
2254 lq_sta->active_mimo3_rate &= ~((u16)0x2); 2251 lq_sta->active_mimo3_rate &= ~((u16)0x2);
2255 lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; 2252 lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
2256 2253
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 79a24410dd0a..7c3eb3d8f7e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -552,17 +552,30 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
552static void iwl4965_ht_conf(struct iwl_priv *priv, 552static void iwl4965_ht_conf(struct iwl_priv *priv,
553 struct ieee80211_bss_conf *bss_conf) 553 struct ieee80211_bss_conf *bss_conf)
554{ 554{
555 struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap; 555 struct ieee80211_sta_ht_cap *ht_conf;
556 struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
557 struct iwl_ht_info *iwl_conf = &priv->current_ht_config; 556 struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
557 struct ieee80211_sta *sta;
558 558
559 IWL_DEBUG_MAC80211("enter: \n"); 559 IWL_DEBUG_MAC80211("enter: \n");
560 560
561 iwl_conf->is_ht = bss_conf->assoc_ht;
562
563 if (!iwl_conf->is_ht) 561 if (!iwl_conf->is_ht)
564 return; 562 return;
565 563
564
565 /*
566 * It is totally wrong to base global information on something
567 * that is valid only when associated, alas, this driver works
568 * that way and I don't know how to fix it.
569 */
570
571 rcu_read_lock();
572 sta = ieee80211_find_sta(priv->hw, priv->bssid);
573 if (!sta) {
574 rcu_read_unlock();
575 return;
576 }
577 ht_conf = &sta->ht_cap;
578
566 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) 579 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
567 iwl_conf->sgf |= HT_SHORT_GI_20MHZ; 580 iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
568 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) 581 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
@@ -574,8 +587,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
574 587
575 iwl_conf->supported_chan_width = 588 iwl_conf->supported_chan_width =
576 !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); 589 !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
577 iwl_conf->extension_chan_offset = 590
578 ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; 591 iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset;
579 /* If no above or below channel supplied disable FAT channel */ 592 /* If no above or below channel supplied disable FAT channel */
580 if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && 593 if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
581 iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { 594 iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) {
@@ -587,15 +600,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
587 600
588 memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); 601 memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
589 602
590 iwl_conf->control_channel = ht_bss_conf->primary_channel; 603 iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok;
591 iwl_conf->tx_chan_width =
592 !!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
593 iwl_conf->ht_protection = 604 iwl_conf->ht_protection =
594 ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION; 605 bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
595 iwl_conf->non_GF_STA_present = 606 iwl_conf->non_GF_STA_present =
596 !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 607 !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
608
609 rcu_read_unlock();
597 610
598 IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
599 IWL_DEBUG_MAC80211("leave\n"); 611 IWL_DEBUG_MAC80211("leave\n");
600} 612}
601 613
@@ -2746,6 +2758,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
2746 mutex_lock(&priv->mutex); 2758 mutex_lock(&priv->mutex);
2747 IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); 2759 IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
2748 2760
2761 priv->current_ht_config.is_ht = conf->ht.enabled;
2762
2749 if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { 2763 if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
2750 IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); 2764 IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
2751 goto out; 2765 goto out;
@@ -3104,7 +3118,6 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
3104 } 3118 }
3105 3119
3106 if (changes & BSS_CHANGED_HT) { 3120 if (changes & BSS_CHANGED_HT) {
3107 IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
3108 iwl4965_ht_conf(priv, bss_conf); 3121 iwl4965_ht_conf(priv, bss_conf);
3109 iwl_set_rxon_chain(priv); 3122 iwl_set_rxon_chain(priv);
3110 } 3123 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 4678da447ff6..10f5a0a233fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -637,8 +637,8 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
637 } 637 }
638 638
639 return iwl_is_channel_extension(priv, priv->band, 639 return iwl_is_channel_extension(priv, priv->band,
640 iwl_ht_conf->control_channel, 640 le16_to_cpu(priv->staging_rxon.channel),
641 iwl_ht_conf->extension_chan_offset); 641 iwl_ht_conf->extension_chan_offset);
642} 642}
643EXPORT_SYMBOL(iwl_is_fat_tx_allowed); 643EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
644 644
@@ -663,13 +663,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
663 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | 663 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
664 RXON_FLG_CHANNEL_MODE_PURE_40_MSK); 664 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
665 665
666 if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
667 IWL_DEBUG_ASSOC("control diff than current %d %d\n",
668 le16_to_cpu(rxon->channel),
669 ht_info->control_channel);
670 return;
671 }
672
673 /* Note: control channel is opposite of extension channel */ 666 /* Note: control channel is opposite of extension channel */
674 switch (ht_info->extension_chan_offset) { 667 switch (ht_info->extension_chan_offset) {
675 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 668 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -692,14 +685,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
692 685
693 IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " 686 IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
694 "rxon flags 0x%X operation mode :0x%X " 687 "rxon flags 0x%X operation mode :0x%X "
695 "extension channel offset 0x%x " 688 "extension channel offset 0x%x\n",
696 "control chan %d\n",
697 ht_info->mcs.rx_mask[0], 689 ht_info->mcs.rx_mask[0],
698 ht_info->mcs.rx_mask[1], 690 ht_info->mcs.rx_mask[1],
699 ht_info->mcs.rx_mask[2], 691 ht_info->mcs.rx_mask[2],
700 le32_to_cpu(rxon->flags), ht_info->ht_protection, 692 le32_to_cpu(rxon->flags), ht_info->ht_protection,
701 ht_info->extension_chan_offset, 693 ht_info->extension_chan_offset);
702 ht_info->control_channel);
703 return; 694 return;
704} 695}
705EXPORT_SYMBOL(iwl_set_rxon_ht); 696EXPORT_SYMBOL(iwl_set_rxon_ht);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 572250ee9d58..2e9514933970 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -413,7 +413,6 @@ struct iwl_ht_info {
413 u8 mpdu_density; 413 u8 mpdu_density;
414 struct ieee80211_mcs_info mcs; 414 struct ieee80211_mcs_info mcs;
415 /* BSS related data */ 415 /* BSS related data */
416 u8 control_channel;
417 u8 extension_chan_offset; 416 u8 extension_chan_offset;
418 u8 tx_chan_width; 417 u8 tx_chan_width;
419 u8 ht_protection; 418 u8 ht_protection;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index b9b8554433a6..218483d096cc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -890,20 +890,31 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
890 */ 890 */
891int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) 891int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
892{ 892{
893 struct ieee80211_sta *sta;
894 struct ieee80211_sta_ht_cap ht_config;
895 struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
893 u8 sta_id; 896 u8 sta_id;
894 897
895 /* Add station to device's station table */ 898 /* Add station to device's station table */
896 struct ieee80211_conf *conf = &priv->hw->conf; 899
897 struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap; 900 /*
898 901 * XXX: This check is definitely not correct, if we're an AP
899 if ((is_ap) && 902 * it'll always be false which is not what we want, but
900 (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && 903 * it doesn't look like iwlagn is prepared to be an HT
901 (priv->iw_mode == NL80211_IFTYPE_STATION)) 904 * AP anyway.
902 sta_id = iwl_add_station_flags(priv, addr, is_ap, 905 */
903 0, cur_ht_config); 906 if (priv->current_ht_config.is_ht) {
904 else 907 rcu_read_lock();
905 sta_id = iwl_add_station_flags(priv, addr, is_ap, 908 sta = ieee80211_find_sta(priv->hw, addr);
906 0, NULL); 909 if (sta) {
910 memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
911 cur_ht_config = &ht_config;
912 }
913 rcu_read_unlock();
914 }
915
916 sta_id = iwl_add_station_flags(priv, addr, is_ap,
917 0, cur_ht_config);
907 918
908 /* Set up default rate scaling table in device's station table */ 919 /* Set up default rate scaling table in device's station table */
909 iwl_sta_init_lq(priv, addr, is_ap); 920 iwl_sta_init_lq(priv, addr, is_ap);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 94ff3eface49..9801afb62545 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright 2002-2005, Devicescape Software, Inc. 4 * Copyright 2002-2005, Devicescape Software, Inc.
5 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 5 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
6 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 6 * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -82,22 +82,6 @@ enum ieee80211_notification_types {
82}; 82};
83 83
84/** 84/**
85 * struct ieee80211_ht_bss_info - describing BSS's HT characteristics
86 *
87 * This structure describes most essential parameters needed
88 * to describe 802.11n HT characteristics in a BSS.
89 *
90 * @primary_channel: channel number of primery channel
91 * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width)
92 * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection)
93 */
94struct ieee80211_ht_bss_info {
95 u8 primary_channel;
96 u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */
97 u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
98};
99
100/**
101 * enum ieee80211_max_queues - maximum number of queues 85 * enum ieee80211_max_queues - maximum number of queues
102 * 86 *
103 * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. 87 * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
@@ -172,6 +156,19 @@ enum ieee80211_bss_change {
172}; 156};
173 157
174/** 158/**
159 * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
160 * @secondary_channel_offset: secondary channel offset, uses
161 * %IEEE80211_HT_PARAM_CHA_SEC_ values
162 * @width_40_ok: indicates that 40 MHz bandwidth may be used for TX
163 * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
164 */
165struct ieee80211_bss_ht_conf {
166 u8 secondary_channel_offset;
167 bool width_40_ok;
168 u16 operation_mode;
169};
170
171/**
175 * struct ieee80211_bss_conf - holds the BSS's changing parameters 172 * struct ieee80211_bss_conf - holds the BSS's changing parameters
176 * 173 *
177 * This structure keeps information about a BSS (and an association 174 * This structure keeps information about a BSS (and an association
@@ -190,9 +187,7 @@ enum ieee80211_bss_change {
190 * @timestamp: beacon timestamp 187 * @timestamp: beacon timestamp
191 * @beacon_int: beacon interval 188 * @beacon_int: beacon interval
192 * @assoc_capability: capabilities taken from assoc resp 189 * @assoc_capability: capabilities taken from assoc resp
193 * @assoc_ht: association in HT mode 190 * @ht: BSS's HT configuration
194 * @ht_cap: ht capabilities
195 * @ht_bss_conf: ht extended capabilities
196 * @basic_rates: bitmap of basic rates, each bit stands for an 191 * @basic_rates: bitmap of basic rates, each bit stands for an
197 * index into the rate table configured by the driver in 192 * index into the rate table configured by the driver in
198 * the current band. 193 * the current band.
@@ -210,10 +205,7 @@ struct ieee80211_bss_conf {
210 u16 assoc_capability; 205 u16 assoc_capability;
211 u64 timestamp; 206 u64 timestamp;
212 u64 basic_rates; 207 u64 basic_rates;
213 /* ht related data */ 208 struct ieee80211_bss_ht_conf ht;
214 bool assoc_ht;
215 struct ieee80211_sta_ht_cap *ht_cap;
216 struct ieee80211_ht_bss_info *ht_bss_conf;
217}; 209};
218 210
219/** 211/**
@@ -447,13 +439,11 @@ struct ieee80211_rx_status {
447 * Flags to define PHY configuration options 439 * Flags to define PHY configuration options
448 * 440 *
449 * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) 441 * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
450 * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
451 * @IEEE80211_CONF_PS: Enable 802.11 power save mode 442 * @IEEE80211_CONF_PS: Enable 802.11 power save mode
452 */ 443 */
453enum ieee80211_conf_flags { 444enum ieee80211_conf_flags {
454 IEEE80211_CONF_RADIOTAP = (1<<0), 445 IEEE80211_CONF_RADIOTAP = (1<<0),
455 IEEE80211_CONF_SUPPORT_HT_MODE = (1<<1), 446 IEEE80211_CONF_PS = (1<<1),
456 IEEE80211_CONF_PS = (1<<2),
457}; 447};
458 448
459/* XXX: remove all this once drivers stop trying to use it */ 449/* XXX: remove all this once drivers stop trying to use it */
@@ -463,6 +453,10 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
463} 453}
464#define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME()) 454#define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME())
465 455
456struct ieee80211_ht_conf {
457 bool enabled;
458};
459
466/** 460/**
467 * enum ieee80211_conf_changed - denotes which configuration changed 461 * enum ieee80211_conf_changed - denotes which configuration changed
468 * 462 *
@@ -474,6 +468,7 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
474 * @IEEE80211_CONF_CHANGE_POWER: the TX power changed 468 * @IEEE80211_CONF_CHANGE_POWER: the TX power changed
475 * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed 469 * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed
476 * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed 470 * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
471 * @IEEE80211_CONF_CHANGE_HT: HT configuration changed
477 */ 472 */
478enum ieee80211_conf_changed { 473enum ieee80211_conf_changed {
479 IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), 474 IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0),
@@ -484,6 +479,7 @@ enum ieee80211_conf_changed {
484 IEEE80211_CONF_CHANGE_POWER = BIT(5), 479 IEEE80211_CONF_CHANGE_POWER = BIT(5),
485 IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), 480 IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
486 IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), 481 IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
482 IEEE80211_CONF_CHANGE_HT = BIT(8),
487}; 483};
488 484
489/** 485/**
@@ -496,9 +492,8 @@ enum ieee80211_conf_changed {
496 * @listen_interval: listen interval in units of beacon interval 492 * @listen_interval: listen interval in units of beacon interval
497 * @flags: configuration flags defined above 493 * @flags: configuration flags defined above
498 * @power_level: requested transmit power (in dBm) 494 * @power_level: requested transmit power (in dBm)
499 * @ht_cap: describes current self configuration of 802.11n HT capabilities
500 * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
501 * @channel: the channel to tune to 495 * @channel: the channel to tune to
496 * @ht: the HT configuration for the device
502 * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame 497 * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
503 * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, 498 * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
504 * but actually means the number of transmissions not the number of retries 499 * but actually means the number of transmissions not the number of retries
@@ -517,9 +512,7 @@ struct ieee80211_conf {
517 u8 long_frame_max_tx_count, short_frame_max_tx_count; 512 u8 long_frame_max_tx_count, short_frame_max_tx_count;
518 513
519 struct ieee80211_channel *channel; 514 struct ieee80211_channel *channel;
520 515 struct ieee80211_ht_conf ht;
521 struct ieee80211_sta_ht_cap ht_cap;
522 struct ieee80211_ht_bss_info ht_bss_conf;
523}; 516};
524 517
525/** 518/**
@@ -715,7 +708,7 @@ enum set_key_cmd {
715 * @addr: MAC address 708 * @addr: MAC address
716 * @aid: AID we assigned to the station if we're an AP 709 * @aid: AID we assigned to the station if we're an AP
717 * @supp_rates: Bitmap of supported rates (per band) 710 * @supp_rates: Bitmap of supported rates (per band)
718 * @ht_cap: HT capabilities of this STA 711 * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
719 * @drv_priv: data area for driver use, will always be aligned to 712 * @drv_priv: data area for driver use, will always be aligned to
720 * sizeof(void *), size is determined in hw information. 713 * sizeof(void *), size is determined in hw information.
721 */ 714 */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 28382b5c7c25..55e3a26510ed 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -582,6 +582,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
582 struct ieee80211_supported_band *sband; 582 struct ieee80211_supported_band *sband;
583 struct ieee80211_sub_if_data *sdata = sta->sdata; 583 struct ieee80211_sub_if_data *sdata = sta->sdata;
584 584
585 sband = local->hw.wiphy->bands[local->oper_channel->band];
586
585 /* 587 /*
586 * FIXME: updating the flags is racy when this function is 588 * FIXME: updating the flags is racy when this function is
587 * called from ieee80211_change_station(), this will 589 * called from ieee80211_change_station(), this will
@@ -622,7 +624,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
622 624
623 if (params->supported_rates) { 625 if (params->supported_rates) {
624 rates = 0; 626 rates = 0;
625 sband = local->hw.wiphy->bands[local->oper_channel->band];
626 627
627 for (i = 0; i < params->supported_rates_len; i++) { 628 for (i = 0; i < params->supported_rates_len; i++) {
628 int rate = (params->supported_rates[i] & 0x7f) * 5; 629 int rate = (params->supported_rates[i] & 0x7f) * 5;
@@ -635,7 +636,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
635 } 636 }
636 637
637 if (params->ht_capa) 638 if (params->ht_capa)
638 ieee80211_ht_cap_ie_to_sta_ht_cap(params->ht_capa, 639 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
640 params->ht_capa,
639 &sta->sta.ht_cap); 641 &sta->sta.ht_cap);
640 642
641 if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { 643 if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index e2d121bf2745..42c3e590df98 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -20,114 +20,38 @@
20#include "sta_info.h" 20#include "sta_info.h"
21#include "wme.h" 21#include "wme.h"
22 22
23void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, 23void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
24 struct ieee80211_ht_cap *ht_cap_ie,
24 struct ieee80211_sta_ht_cap *ht_cap) 25 struct ieee80211_sta_ht_cap *ht_cap)
25{ 26{
27 u8 ampdu_info, tx_mcs_set_cap;
28 int i, max_tx_streams;
26 29
27 BUG_ON(!ht_cap); 30 BUG_ON(!ht_cap);
28 31
29 memset(ht_cap, 0, sizeof(*ht_cap)); 32 memset(ht_cap, 0, sizeof(*ht_cap));
30 33
31 if (ht_cap_ie) { 34 if (!ht_cap_ie)
32 u8 ampdu_info = ht_cap_ie->ampdu_params_info; 35 return;
33
34 ht_cap->ht_supported = true;
35 ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info);
36 ht_cap->ampdu_factor =
37 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
38 ht_cap->ampdu_density =
39 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
40 memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs));
41 } else
42 ht_cap->ht_supported = false;
43}
44
45void ieee80211_ht_info_ie_to_ht_bss_info(
46 struct ieee80211_ht_info *ht_add_info_ie,
47 struct ieee80211_ht_bss_info *bss_info)
48{
49 BUG_ON(!bss_info);
50
51 memset(bss_info, 0, sizeof(*bss_info));
52
53 if (ht_add_info_ie) {
54 u16 op_mode;
55 op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
56
57 bss_info->primary_channel = ht_add_info_ie->control_chan;
58 bss_info->bss_cap = ht_add_info_ie->ht_param;
59 bss_info->bss_op_mode = (u8)(op_mode & 0xff);
60 }
61}
62
63/*
64 * ieee80211_handle_ht should be called only after the operating band
65 * has been determined as ht configuration depends on the hw's
66 * HT abilities for a specific band.
67 */
68u32 ieee80211_handle_ht(struct ieee80211_local *local,
69 struct ieee80211_sta_ht_cap *req_ht_cap,
70 struct ieee80211_ht_bss_info *req_bss_cap)
71{
72 struct ieee80211_conf *conf = &local->hw.conf;
73 struct ieee80211_supported_band *sband;
74 struct ieee80211_sta_ht_cap ht_cap;
75 struct ieee80211_ht_bss_info ht_bss_conf;
76 u32 changed = 0;
77 int i;
78 u8 max_tx_streams;
79 u8 tx_mcs_set_cap;
80 bool enable_ht = true;
81
82 sband = local->hw.wiphy->bands[conf->channel->band];
83
84 memset(&ht_cap, 0, sizeof(ht_cap));
85 memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
86
87 /* HT is not supported */
88 if (!sband->ht_cap.ht_supported)
89 enable_ht = false;
90
91 /* disable HT */
92 if (!enable_ht) {
93 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
94 changed |= BSS_CHANGED_HT;
95 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
96 conf->ht_cap.ht_supported = false;
97 return changed;
98 }
99
100
101 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
102 changed |= BSS_CHANGED_HT;
103
104 conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
105 ht_cap.ht_supported = true;
106 36
107 ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap; 37 ht_cap->ht_supported = true;
108 ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
109 ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
110 38
111 ht_bss_conf.primary_channel = req_bss_cap->primary_channel; 39 ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
112 ht_bss_conf.bss_cap = req_bss_cap->bss_cap; 40 ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
113 ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; 41 ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
114 42
115 ht_cap.ampdu_factor = req_ht_cap->ampdu_factor; 43 ampdu_info = ht_cap_ie->ampdu_params_info;
116 ht_cap.ampdu_density = req_ht_cap->ampdu_density; 44 ht_cap->ampdu_factor =
45 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
46 ht_cap->ampdu_density =
47 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
117 48
118 /* own MCS TX capabilities */ 49 /* own MCS TX capabilities */
119 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; 50 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
120 51
121 /*
122 * configure supported Tx MCS according to requested MCS
123 * (based in most cases on Rx capabilities of peer) and self
124 * Tx MCS capabilities (as defined by low level driver HW
125 * Tx capabilities)
126 */
127
128 /* can we TX with MCS rates? */ 52 /* can we TX with MCS rates? */
129 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) 53 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
130 goto check_changed; 54 return;
131 55
132 /* Counting from 0, therefore +1 */ 56 /* Counting from 0, therefore +1 */
133 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) 57 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
@@ -145,29 +69,73 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local,
145 * - remainder are multiple spatial streams using unequal modulation 69 * - remainder are multiple spatial streams using unequal modulation
146 */ 70 */
147 for (i = 0; i < max_tx_streams; i++) 71 for (i = 0; i < max_tx_streams; i++)
148 ht_cap.mcs.rx_mask[i] = 72 ht_cap->mcs.rx_mask[i] =
149 sband->ht_cap.mcs.rx_mask[i] & 73 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
150 req_ht_cap->mcs.rx_mask[i];
151 74
152 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) 75 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
153 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; 76 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
154 i < IEEE80211_HT_MCS_MASK_LEN; i++) 77 i < IEEE80211_HT_MCS_MASK_LEN; i++)
155 ht_cap.mcs.rx_mask[i] = 78 ht_cap->mcs.rx_mask[i] =
156 sband->ht_cap.mcs.rx_mask[i] & 79 sband->ht_cap.mcs.rx_mask[i] &
157 req_ht_cap->mcs.rx_mask[i]; 80 ht_cap_ie->mcs.rx_mask[i];
158 81
159 /* handle MCS rate 32 too */ 82 /* handle MCS rate 32 too */
160 if (sband->ht_cap.mcs.rx_mask[32/8] & 83 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
161 req_ht_cap->mcs.rx_mask[32/8] & 1) 84 ht_cap->mcs.rx_mask[32/8] |= 1;
162 ht_cap.mcs.rx_mask[32/8] |= 1; 85}
86
87/*
88 * ieee80211_enable_ht should be called only after the operating band
89 * has been determined as ht configuration depends on the hw's
90 * HT abilities for a specific band.
91 */
92u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
93 struct ieee80211_ht_info *hti,
94 u16 ap_ht_cap_flags)
95{
96 struct ieee80211_local *local = sdata->local;
97 struct ieee80211_supported_band *sband;
98 struct ieee80211_bss_ht_conf ht;
99 u32 changed = 0;
100 bool enable_ht = true, ht_changed;
101
102 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
103
104 memset(&ht, 0, sizeof(ht));
105
106 /* HT is not supported */
107 if (!sband->ht_cap.ht_supported)
108 enable_ht = false;
109
110 /* check that channel matches the right operating channel */
111 if (local->hw.conf.channel->center_freq !=
112 ieee80211_channel_to_frequency(hti->control_chan))
113 enable_ht = false;
114
115 /*
116 * XXX: This is totally incorrect when there are multiple virtual
117 * interfaces, needs to be fixed later.
118 */
119 ht_changed = local->hw.conf.ht.enabled != enable_ht;
120 local->hw.conf.ht.enabled = enable_ht;
121 if (ht_changed)
122 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
123
124 /* disable HT */
125 if (!enable_ht)
126 return 0;
127 ht.secondary_channel_offset =
128 hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
129 ht.width_40_ok =
130 !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
131 (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
132 (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
133 ht.operation_mode = le16_to_cpu(hti->operation_mode);
163 134
164 check_changed:
165 /* if bss configuration changed store the new one */ 135 /* if bss configuration changed store the new one */
166 if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) || 136 if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
167 memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
168 changed |= BSS_CHANGED_HT; 137 changed |= BSS_CHANGED_HT;
169 memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap)); 138 sdata->vif.bss_conf.ht = ht;
170 memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
171 } 139 }
172 140
173 return changed; 141 return changed;
@@ -900,8 +868,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
900 /* sanity check for incoming parameters: 868 /* sanity check for incoming parameters:
901 * check if configuration can support the BA policy 869 * check if configuration can support the BA policy
902 * and if buffer size does not exceeds max value */ 870 * and if buffer size does not exceeds max value */
871 /* XXX: check own ht delayed BA capability?? */
903 if (((ba_policy != 1) 872 if (((ba_policy != 1)
904 && (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) 873 && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
905 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { 874 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
906 status = WLAN_STATUS_INVALID_QOS_PARAM; 875 status = WLAN_STATUS_INVALID_QOS_PARAM;
907#ifdef CONFIG_MAC80211_HT_DEBUG 876#ifdef CONFIG_MAC80211_HT_DEBUG
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 859b5b001f22..6f8756d26a93 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -955,14 +955,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
955int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); 955int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
956 956
957/* HT */ 957/* HT */
958void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, 958void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
959 struct ieee80211_ht_cap *ht_cap_ie,
959 struct ieee80211_sta_ht_cap *ht_cap); 960 struct ieee80211_sta_ht_cap *ht_cap);
960void ieee80211_ht_info_ie_to_ht_bss_info( 961u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
961 struct ieee80211_ht_info *ht_add_info_ie, 962 struct ieee80211_ht_info *hti,
962 struct ieee80211_ht_bss_info *bss_info); 963 u16 ap_ht_cap_flags);
963u32 ieee80211_handle_ht(struct ieee80211_local *local,
964 struct ieee80211_sta_ht_cap *req_ht_cap,
965 struct ieee80211_ht_bss_info *req_bss_cap);
966void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); 964void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
967 965
968void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, 966void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9c5f5c37a49e..39bc9c69893b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -700,14 +700,15 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
700 700
701 701
702static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, 702static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
703 struct ieee80211_if_sta *ifsta) 703 struct ieee80211_if_sta *ifsta,
704 u32 bss_info_changed)
704{ 705{
705 struct ieee80211_local *local = sdata->local; 706 struct ieee80211_local *local = sdata->local;
706 struct ieee80211_conf *conf = &local_to_hw(local)->conf; 707 struct ieee80211_conf *conf = &local_to_hw(local)->conf;
707 u32 changed = BSS_CHANGED_ASSOC;
708 708
709 struct ieee80211_bss *bss; 709 struct ieee80211_bss *bss;
710 710
711 bss_info_changed |= BSS_CHANGED_ASSOC;
711 ifsta->flags |= IEEE80211_STA_ASSOCIATED; 712 ifsta->flags |= IEEE80211_STA_ASSOCIATED;
712 713
713 if (sdata->vif.type != NL80211_IFTYPE_STATION) 714 if (sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -722,19 +723,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
722 sdata->vif.bss_conf.timestamp = bss->timestamp; 723 sdata->vif.bss_conf.timestamp = bss->timestamp;
723 sdata->vif.bss_conf.dtim_period = bss->dtim_period; 724 sdata->vif.bss_conf.dtim_period = bss->dtim_period;
724 725
725 changed |= ieee80211_handle_bss_capability(sdata, 726 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
726 bss->capability, bss->has_erp_value, bss->erp_value); 727 bss->capability, bss->has_erp_value, bss->erp_value);
727 728
728 ieee80211_rx_bss_put(local, bss); 729 ieee80211_rx_bss_put(local, bss);
729 } 730 }
730 731
731 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
732 changed |= BSS_CHANGED_HT;
733 sdata->vif.bss_conf.assoc_ht = 1;
734 sdata->vif.bss_conf.ht_cap = &conf->ht_cap;
735 sdata->vif.bss_conf.ht_bss_conf = &conf->ht_bss_conf;
736 }
737
738 ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; 732 ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
739 memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); 733 memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
740 ieee80211_sta_send_associnfo(sdata, ifsta); 734 ieee80211_sta_send_associnfo(sdata, ifsta);
@@ -748,8 +742,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
748 * when we have associated, we aren't checking whether it actually 742 * when we have associated, we aren't checking whether it actually
749 * changed or not. 743 * changed or not.
750 */ 744 */
751 changed |= BSS_CHANGED_BASIC_RATES; 745 bss_info_changed |= BSS_CHANGED_BASIC_RATES;
752 ieee80211_bss_info_change_notify(sdata, changed); 746 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
753 747
754 netif_tx_start_all_queues(sdata->dev); 748 netif_tx_start_all_queues(sdata->dev);
755 netif_carrier_on(sdata->dev); 749 netif_carrier_on(sdata->dev);
@@ -813,7 +807,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
813{ 807{
814 struct ieee80211_local *local = sdata->local; 808 struct ieee80211_local *local = sdata->local;
815 struct sta_info *sta; 809 struct sta_info *sta;
816 u32 changed = BSS_CHANGED_ASSOC; 810 u32 changed = 0;
817 811
818 rcu_read_lock(); 812 rcu_read_lock();
819 813
@@ -847,15 +841,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
847 ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; 841 ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
848 changed |= ieee80211_reset_erp_info(sdata); 842 changed |= ieee80211_reset_erp_info(sdata);
849 843
850 if (sdata->vif.bss_conf.assoc_ht)
851 changed |= BSS_CHANGED_HT;
852
853 sdata->vif.bss_conf.assoc_ht = 0;
854 sdata->vif.bss_conf.ht_cap = NULL;
855 sdata->vif.bss_conf.ht_bss_conf = NULL;
856
857 ieee80211_led_assoc(local, 0); 844 ieee80211_led_assoc(local, 0);
858 sdata->vif.bss_conf.assoc = 0; 845 changed |= BSS_CHANGED_ASSOC;
846 sdata->vif.bss_conf.assoc = false;
859 847
860 ieee80211_sta_send_apinfo(sdata, ifsta); 848 ieee80211_sta_send_apinfo(sdata, ifsta);
861 849
@@ -867,6 +855,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
867 rcu_read_unlock(); 855 rcu_read_unlock();
868 856
869 sta_info_destroy(sta); 857 sta_info_destroy(sta);
858
859 local->hw.conf.ht.enabled = false;
860 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
861
862 ieee80211_bss_info_change_notify(sdata, changed);
870} 863}
871 864
872static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) 865static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
@@ -1184,8 +1177,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1184 struct ieee802_11_elems elems; 1177 struct ieee802_11_elems elems;
1185 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; 1178 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
1186 u8 *pos; 1179 u8 *pos;
1180 u32 changed = 0;
1187 int i, j; 1181 int i, j;
1188 bool have_higher_than_11mbit = false; 1182 bool have_higher_than_11mbit = false;
1183 u16 ap_ht_cap_flags;
1189 1184
1190 /* AssocResp and ReassocResp have identical structure, so process both 1185 /* AssocResp and ReassocResp have identical structure, so process both
1191 * of them in this function. */ 1186 * of them in this function. */
@@ -1333,15 +1328,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1333 else 1328 else
1334 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 1329 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
1335 1330
1336 if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && 1331 if (elems.ht_cap_elem)
1337 (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { 1332 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
1338 struct ieee80211_ht_bss_info bss_info;
1339 ieee80211_ht_cap_ie_to_sta_ht_cap(
1340 elems.ht_cap_elem, &sta->sta.ht_cap); 1333 elems.ht_cap_elem, &sta->sta.ht_cap);
1341 ieee80211_ht_info_ie_to_ht_bss_info( 1334
1342 elems.ht_info_elem, &bss_info); 1335 ap_ht_cap_flags = sta->sta.ht_cap.cap;
1343 ieee80211_handle_ht(local, &sta->sta.ht_cap, &bss_info);
1344 }
1345 1336
1346 rate_control_rate_init(sta); 1337 rate_control_rate_init(sta);
1347 1338
@@ -1353,11 +1344,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1353 } else 1344 } else
1354 rcu_read_unlock(); 1345 rcu_read_unlock();
1355 1346
1347 if (elems.ht_info_elem && elems.wmm_param &&
1348 (ifsta->flags & IEEE80211_STA_WMM_ENABLED))
1349 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
1350 ap_ht_cap_flags);
1351
1356 /* set AID and assoc capability, 1352 /* set AID and assoc capability,
1357 * ieee80211_set_associated() will tell the driver */ 1353 * ieee80211_set_associated() will tell the driver */
1358 bss_conf->aid = aid; 1354 bss_conf->aid = aid;
1359 bss_conf->assoc_capability = capab_info; 1355 bss_conf->assoc_capability = capab_info;
1360 ieee80211_set_associated(sdata, ifsta); 1356 ieee80211_set_associated(sdata, ifsta, changed);
1361 1357
1362 ieee80211_associated(sdata, ifsta); 1358 ieee80211_associated(sdata, ifsta);
1363} 1359}
@@ -1657,7 +1653,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1657 size_t baselen; 1653 size_t baselen;
1658 struct ieee802_11_elems elems; 1654 struct ieee802_11_elems elems;
1659 struct ieee80211_local *local = sdata->local; 1655 struct ieee80211_local *local = sdata->local;
1660 struct ieee80211_conf *conf = &local->hw.conf;
1661 u32 changed = 0; 1656 u32 changed = 0;
1662 bool erp_valid; 1657 bool erp_valid;
1663 u8 erp_value = 0; 1658 u8 erp_value = 0;
@@ -1693,14 +1688,31 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1693 le16_to_cpu(mgmt->u.beacon.capab_info), 1688 le16_to_cpu(mgmt->u.beacon.capab_info),
1694 erp_valid, erp_value); 1689 erp_valid, erp_value);
1695 1690
1696 if (elems.ht_cap_elem && elems.ht_info_elem &&
1697 elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
1698 struct ieee80211_ht_bss_info bss_info;
1699 1691
1700 ieee80211_ht_info_ie_to_ht_bss_info( 1692 if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
1701 elems.ht_info_elem, &bss_info); 1693 struct sta_info *sta;
1702 changed |= ieee80211_handle_ht(local, &conf->ht_cap, 1694 struct ieee80211_supported_band *sband;
1703 &bss_info); 1695 u16 ap_ht_cap_flags;
1696
1697 rcu_read_lock();
1698
1699 sta = sta_info_get(local, ifsta->bssid);
1700 if (!sta) {
1701 rcu_read_unlock();
1702 return;
1703 }
1704
1705 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
1706
1707 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
1708 elems.ht_cap_elem, &sta->sta.ht_cap);
1709
1710 ap_ht_cap_flags = sta->sta.ht_cap.cap;
1711
1712 rcu_read_unlock();
1713
1714 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
1715 ap_ht_cap_flags);
1704 } 1716 }
1705 1717
1706 ieee80211_bss_info_change_notify(sdata, changed); 1718 ieee80211_bss_info_change_notify(sdata, changed);