aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-10-14 10:58:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-31 19:00:16 -0400
commitae5eb02641233a4e9d1b92d22090f1b1afa14466 (patch)
tree117b7cb5efa3ff1cf714218098fc6db3820ed4e0
parentbda3933a8aceedd03e0dd410844bd310033ca756 (diff)
mac80211: rewrite HT handling
The HT handling has the following deficiencies, which I've (partially) fixed: * it always uses the AP info even if there is no AP, hence has no chance of working as an AP * it pretends to be HW config, but really is per-BSS * channel sanity checking is left to the drivers * it generally lets the driver control too much HT enabling is still wrong with this patch if you have more than one virtual STA mode interface, but that never happens currently. Once WDS, IBSS or AP/VLAN gets HT capabilities, it will also be wrong, see the comment in ieee80211_enable_ht(). Additionally, this fixes a number of bugs: * mac80211: ieee80211_set_disassoc doesn't notify the driver any more since the refactoring * iwl-agn-rs: always uses the HT capabilities from the wrong stuff mac80211 gives it rather than the actual peer STA * ath9k: a number of bugs resulting from the broken HT API I'm not entirely happy with putting the HT capabilities into struct ieee80211_sta as restricted to our own HT TX capabilities, but I see no cleaner solution for now. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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);