diff options
author | Ben Greear <greearb@candelatech.com> | 2011-11-18 14:32:00 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-21 16:22:06 -0500 |
commit | ef96a84202ccfb48a4569256ffba45e32308f7ee (patch) | |
tree | 708275d21455ecbf3b5408241b73f95fa4c484e0 /net/mac80211 | |
parent | 7e7c8926b2f4e3453b8aeb39cd814d2af3fec24f (diff) |
mac80211: Support ht-cap over-rides.
This implements ht-cap over-rides for mac80211 drivers.
HT may be disabled, making an /a/b/g/n station act like an
a/b/g station. HT40 may be disabled forcing the station to
be HT20 even if the AP and local hardware support HT40.
MAX-AMSDU may be disabled.
AMPDU-Density may be increased.
AMPDU-Factor may be decreased.
This has been successfully tested with ath9k using patched
wpa_supplicant and iw.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/ht.c | 83 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 11 | ||||
-rw-r--r-- | net/mac80211/main.c | 14 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 14 | ||||
-rw-r--r-- | net/mac80211/util.c | 13 | ||||
-rw-r--r-- | net/mac80211/work.c | 16 |
9 files changed, 140 insertions, 18 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1063a7e57d62..2577c45069e5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -832,7 +832,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
832 | } | 832 | } |
833 | 833 | ||
834 | if (params->ht_capa) | 834 | if (params->ht_capa) |
835 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 835 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
836 | params->ht_capa, | 836 | params->ht_capa, |
837 | &sta->sta.ht_cap); | 837 | &sta->sta.ht_cap); |
838 | 838 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 988c7ec0898c..7e0ac9791fd6 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -18,7 +18,82 @@ | |||
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "rate.h" | 19 | #include "rate.h" |
20 | 20 | ||
21 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 21 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata) |
22 | { | ||
23 | const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
24 | if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) && | ||
25 | !(sdata->u.mgd.ht_capa.cap_info & flg)) | ||
26 | return true; | ||
27 | return false; | ||
28 | } | ||
29 | |||
30 | void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, | ||
31 | struct ieee80211_sta_ht_cap *ht_cap, | ||
32 | u16 flag) | ||
33 | { | ||
34 | __le16 le_flag = cpu_to_le16(flag); | ||
35 | if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) { | ||
36 | if (!(sdata->u.mgd.ht_capa.cap_info & le_flag)) | ||
37 | ht_cap->cap &= ~flag; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
42 | struct ieee80211_sta_ht_cap *ht_cap) | ||
43 | { | ||
44 | u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask); | ||
45 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | ||
46 | int i; | ||
47 | |||
48 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | ||
49 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | /* NOTE: If you add more over-rides here, update register_hw | ||
54 | * ht_capa_mod_msk logic in main.c as well. | ||
55 | * And, if this method can ever change ht_cap.ht_supported, fix | ||
56 | * the check in ieee80211_add_ht_ie. | ||
57 | */ | ||
58 | |||
59 | /* check for HT over-rides, MCS rates first. */ | ||
60 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { | ||
61 | u8 m = smask[i]; | ||
62 | ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */ | ||
63 | /* Add back rates that are supported */ | ||
64 | ht_cap->mcs.rx_mask[i] |= (m & scaps[i]); | ||
65 | } | ||
66 | |||
67 | /* Force removal of HT-40 capabilities? */ | ||
68 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
69 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40); | ||
70 | |||
71 | /* Allow user to disable the max-AMSDU bit. */ | ||
72 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU); | ||
73 | |||
74 | /* Allow user to decrease AMPDU factor */ | ||
75 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | ||
76 | IEEE80211_HT_AMPDU_PARM_FACTOR) { | ||
77 | u8 n = sdata->u.mgd.ht_capa.ampdu_params_info | ||
78 | & IEEE80211_HT_AMPDU_PARM_FACTOR; | ||
79 | if (n < ht_cap->ampdu_factor) | ||
80 | ht_cap->ampdu_factor = n; | ||
81 | } | ||
82 | |||
83 | /* Allow the user to increase AMPDU density. */ | ||
84 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | ||
85 | IEEE80211_HT_AMPDU_PARM_DENSITY) { | ||
86 | u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info & | ||
87 | IEEE80211_HT_AMPDU_PARM_DENSITY) | ||
88 | >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; | ||
89 | if (n > ht_cap->ampdu_density) | ||
90 | ht_cap->ampdu_density = n; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | |||
95 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | ||
96 | struct ieee80211_supported_band *sband, | ||
22 | struct ieee80211_ht_cap *ht_cap_ie, | 97 | struct ieee80211_ht_cap *ht_cap_ie, |
23 | struct ieee80211_sta_ht_cap *ht_cap) | 98 | struct ieee80211_sta_ht_cap *ht_cap) |
24 | { | 99 | { |
@@ -102,6 +177,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
102 | /* handle MCS rate 32 too */ | 177 | /* handle MCS rate 32 too */ |
103 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 178 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
104 | ht_cap->mcs.rx_mask[32/8] |= 1; | 179 | ht_cap->mcs.rx_mask[32/8] |= 1; |
180 | |||
181 | /* | ||
182 | * If user has specified capability over-rides, take care | ||
183 | * of that here. | ||
184 | */ | ||
185 | ieee80211_apply_htcap_overrides(sdata, ht_cap); | ||
105 | } | 186 | } |
106 | 187 | ||
107 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) | 188 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 17661df1515f..762243e469df 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -449,6 +449,9 @@ struct ieee80211_if_managed { | |||
449 | */ | 449 | */ |
450 | int rssi_min_thold, rssi_max_thold; | 450 | int rssi_min_thold, rssi_max_thold; |
451 | int last_ave_beacon_signal; | 451 | int last_ave_beacon_signal; |
452 | |||
453 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | ||
454 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | ||
452 | }; | 455 | }; |
453 | 456 | ||
454 | struct ieee80211_if_ibss { | 457 | struct ieee80211_if_ibss { |
@@ -1252,7 +1255,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1252 | struct net_device *dev); | 1255 | struct net_device *dev); |
1253 | 1256 | ||
1254 | /* HT */ | 1257 | /* HT */ |
1255 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 1258 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata); |
1259 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
1260 | struct ieee80211_sta_ht_cap *ht_cap); | ||
1261 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | ||
1262 | struct ieee80211_supported_band *sband, | ||
1256 | struct ieee80211_ht_cap *ht_cap_ie, | 1263 | struct ieee80211_ht_cap *ht_cap_ie, |
1257 | struct ieee80211_sta_ht_cap *ht_cap); | 1264 | struct ieee80211_sta_ht_cap *ht_cap); |
1258 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1265 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
@@ -1407,7 +1414,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local); | |||
1407 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1414 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1408 | const u8 *ids, int n_ids, size_t offset); | 1415 | const u8 *ids, int n_ids, size_t offset); |
1409 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1416 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1410 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | 1417 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1411 | u16 cap); | 1418 | u16 cap); |
1412 | u8 *ieee80211_ie_build_ht_info(u8 *pos, | 1419 | u8 *ieee80211_ie_build_ht_info(u8 *pos, |
1413 | struct ieee80211_sta_ht_cap *ht_cap, | 1420 | struct ieee80211_sta_ht_cap *ht_cap, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f0106d331938..dddedfad5404 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -558,6 +558,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
558 | }, | 558 | }, |
559 | }; | 559 | }; |
560 | 560 | ||
561 | static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | ||
562 | .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR | | ||
563 | IEEE80211_HT_AMPDU_PARM_DENSITY, | ||
564 | |||
565 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
566 | IEEE80211_HT_CAP_MAX_AMSDU | | ||
567 | IEEE80211_HT_CAP_SGI_40), | ||
568 | .mcs = { | ||
569 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, | ||
570 | 0xff, 0xff, 0xff, 0xff, 0xff, }, | ||
571 | }, | ||
572 | }; | ||
573 | |||
561 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 574 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
562 | const struct ieee80211_ops *ops) | 575 | const struct ieee80211_ops *ops) |
563 | { | 576 | { |
@@ -631,6 +644,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
631 | local->user_power_level = -1; | 644 | local->user_power_level = -1; |
632 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | 645 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; |
633 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | 646 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; |
647 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | ||
634 | 648 | ||
635 | INIT_LIST_HEAD(&local->interfaces); | 649 | INIT_LIST_HEAD(&local->interfaces); |
636 | 650 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b3a125f60347..ee82d2f7f114 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -366,7 +366,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
366 | return -ENOMEM; | 366 | return -ENOMEM; |
367 | 367 | ||
368 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); | 368 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); |
369 | ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); | 369 | ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); |
370 | 370 | ||
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0140e88a8220..7314372b12ba 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -101,7 +101,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
101 | set_sta_flag(sta, WLAN_STA_WME); | 101 | set_sta_flag(sta, WLAN_STA_WME); |
102 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 102 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
103 | if (elems->ht_cap_elem) | 103 | if (elems->ht_cap_elem) |
104 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem, | 104 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
105 | elems->ht_cap_elem, | ||
105 | &sta->sta.ht_cap); | 106 | &sta->sta.ht_cap); |
106 | rate_control_rate_init(sta); | 107 | rate_control_rate_init(sta); |
107 | 108 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0f58122edffa..8925138736ef 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -207,6 +207,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
207 | channel_type = NL80211_CHAN_HT20; | 207 | channel_type = NL80211_CHAN_HT20; |
208 | 208 | ||
209 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | 209 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && |
210 | !ieee80111_cfg_override_disables_ht40(sdata) && | ||
210 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | 211 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && |
211 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | 212 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { |
212 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 213 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
@@ -1118,6 +1119,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1118 | 1119 | ||
1119 | /* on the next assoc, re-program HT parameters */ | 1120 | /* on the next assoc, re-program HT parameters */ |
1120 | sdata->ht_opmode_valid = false; | 1121 | sdata->ht_opmode_valid = false; |
1122 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | ||
1123 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | ||
1121 | 1124 | ||
1122 | local->power_constr_level = 0; | 1125 | local->power_constr_level = 0; |
1123 | 1126 | ||
@@ -1611,7 +1614,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1611 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 1614 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
1612 | 1615 | ||
1613 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1616 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1614 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1617 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1615 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1618 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1616 | 1619 | ||
1617 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1620 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -1980,7 +1983,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1980 | 1983 | ||
1981 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1984 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1982 | 1985 | ||
1983 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1986 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1984 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1987 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1985 | 1988 | ||
1986 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1989 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -2640,6 +2643,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2640 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 2643 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2641 | 2644 | ||
2642 | 2645 | ||
2646 | if (req->flags & ASSOC_REQ_DISABLE_HT) | ||
2647 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||
2648 | |||
2649 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | ||
2650 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | ||
2651 | sizeof(ifmgd->ht_capa_mask)); | ||
2652 | |||
2643 | if (req->ie && req->ie_len) { | 2653 | if (req->ie && req->ie_len) { |
2644 | memcpy(wk->ie, req->ie, req->ie_len); | 2654 | memcpy(wk->ie, req->ie, req->ie_len); |
2645 | wk->ie_len = req->ie_len; | 2655 | wk->ie_len = req->ie_len; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e2cb00df8c36..1118393d79de 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -979,7 +979,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
979 | } | 979 | } |
980 | 980 | ||
981 | if (sband->ht_cap.ht_supported) | 981 | if (sband->ht_cap.ht_supported) |
982 | pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); | 982 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
983 | sband->ht_cap.cap); | ||
983 | 984 | ||
984 | /* | 985 | /* |
985 | * If adding more here, adjust code in main.c | 986 | * If adding more here, adjust code in main.c |
@@ -1518,7 +1519,7 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) | |||
1518 | } | 1519 | } |
1519 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); | 1520 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); |
1520 | 1521 | ||
1521 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | 1522 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1522 | u16 cap) | 1523 | u16 cap) |
1523 | { | 1524 | { |
1524 | __le16 tmp; | 1525 | __le16 tmp; |
@@ -1533,13 +1534,13 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | |||
1533 | pos += sizeof(u16); | 1534 | pos += sizeof(u16); |
1534 | 1535 | ||
1535 | /* AMPDU parameters */ | 1536 | /* AMPDU parameters */ |
1536 | *pos++ = sband->ht_cap.ampdu_factor | | 1537 | *pos++ = ht_cap->ampdu_factor | |
1537 | (sband->ht_cap.ampdu_density << | 1538 | (ht_cap->ampdu_density << |
1538 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | 1539 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); |
1539 | 1540 | ||
1540 | /* MCS set */ | 1541 | /* MCS set */ |
1541 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 1542 | memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs)); |
1542 | pos += sizeof(sband->ht_cap.mcs); | 1543 | pos += sizeof(ht_cap->mcs); |
1543 | 1544 | ||
1544 | /* extended capabilities */ | 1545 | /* extended capabilities */ |
1545 | pos += sizeof(__le16); | 1546 | pos += sizeof(__le16); |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 3dd5a89e99a7..6884a2d986dc 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | |||
94 | 94 | ||
95 | /* frame sending functions */ | 95 | /* frame sending functions */ |
96 | 96 | ||
97 | static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | 97 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, |
98 | struct sk_buff *skb, const u8 *ht_info_ie, | ||
98 | struct ieee80211_supported_band *sband, | 99 | struct ieee80211_supported_band *sband, |
99 | struct ieee80211_channel *channel, | 100 | struct ieee80211_channel *channel, |
100 | enum ieee80211_smps_mode smps) | 101 | enum ieee80211_smps_mode smps) |
@@ -102,7 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
102 | struct ieee80211_ht_info *ht_info; | 103 | struct ieee80211_ht_info *ht_info; |
103 | u8 *pos; | 104 | u8 *pos; |
104 | u32 flags = channel->flags; | 105 | u32 flags = channel->flags; |
105 | u16 cap = sband->ht_cap.cap; | 106 | u16 cap; |
107 | struct ieee80211_sta_ht_cap ht_cap; | ||
108 | |||
109 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | ||
106 | 110 | ||
107 | if (!sband->ht_cap.ht_supported) | 111 | if (!sband->ht_cap.ht_supported) |
108 | return; | 112 | return; |
@@ -113,9 +117,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
113 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | 117 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) |
114 | return; | 118 | return; |
115 | 119 | ||
120 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
121 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
122 | |||
116 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | 123 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); |
117 | 124 | ||
118 | /* determine capability flags */ | 125 | /* determine capability flags */ |
126 | cap = ht_cap.cap; | ||
119 | 127 | ||
120 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 128 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
121 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 129 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
@@ -154,7 +162,7 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
154 | 162 | ||
155 | /* reserve and fill IE */ | 163 | /* reserve and fill IE */ |
156 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | 164 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); |
157 | ieee80211_ie_build_ht_cap(pos, sband, cap); | 165 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); |
158 | } | 166 | } |
159 | 167 | ||
160 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | 168 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
@@ -329,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
329 | 337 | ||
330 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | 338 | if (wk->assoc.use_11n && wk->assoc.wmm_used && |
331 | local->hw.queues >= 4) | 339 | local->hw.queues >= 4) |
332 | ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, | 340 | ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie, |
333 | sband, wk->chan, wk->assoc.smps); | 341 | sband, wk->chan, wk->assoc.smps); |
334 | 342 | ||
335 | /* if present, add any custom non-vendor IEs that go after HT */ | 343 | /* if present, add any custom non-vendor IEs that go after HT */ |