aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
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 /net/mac80211/ht.c
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>
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c181
1 files changed, 75 insertions, 106 deletions
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