diff options
-rw-r--r-- | drivers/net/wireless/ath9k/core.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/rc.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/recv.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/xmit.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 33 | ||||
-rw-r--r-- | include/net/mac80211.h | 59 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
-rw-r--r-- | net/mac80211/ht.c | 181 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 12 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 88 |
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); | |||
380 | int ath_rx_tasklet(struct ath_softc *sc, int flush); | 380 | int ath_rx_tasklet(struct ath_softc *sc, int flush); |
381 | int ath_rx_input(struct ath_softc *sc, | 381 | int 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 | ||
655 | void ath_tx_resume_tid(struct ath_softc *sc, | 657 | void ath_tx_resume_tid(struct ath_softc *sc, |
@@ -919,8 +921,6 @@ enum RATE_TYPE { | |||
919 | 921 | ||
920 | struct ath_ht_info { | 922 | struct 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 | ||
721 | int ath_rx_input(struct ath_softc *sc, | 721 | int 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 | ||
1452 | static u32 ath_lookup_rate(struct ath_softc *sc, | 1453 | static 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 | ||
1520 | static int ath_compute_num_delims(struct ath_softc *sc, | 1522 | static 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) | |||
552 | static void iwl4965_ht_conf(struct iwl_priv *priv, | 552 | static 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 | } |
643 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); | 643 | EXPORT_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 | } |
705 | EXPORT_SYMBOL(iwl_set_rxon_ht); | 696 | EXPORT_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 | */ |
891 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | 891 | int 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 | */ | ||
94 | struct 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 | */ | ||
165 | struct 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 | */ |
453 | enum ieee80211_conf_flags { | 444 | enum 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 | ||
456 | struct 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 | */ |
478 | enum ieee80211_conf_changed { | 473 | enum 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 | ||
23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, | 23 | void 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 | |||
45 | void 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 | */ | ||
68 | u32 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 | */ | ||
92 | u32 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); | |||
955 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); | 955 | int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); |
956 | 956 | ||
957 | /* HT */ | 957 | /* HT */ |
958 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, | 958 | void 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); |
960 | void ieee80211_ht_info_ie_to_ht_bss_info( | 961 | u32 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); |
963 | u32 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); | ||
966 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | 964 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); |
967 | 965 | ||
968 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | 966 | void 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 | ||
702 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 702 | static 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 | ||
872 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | 865 | static 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); |