diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-10-09 06:13:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-31 19:00:06 -0400 |
commit | d9fe60dea7779d412b34679f1177c5ca1940ea8d (patch) | |
tree | a51e16b013f7c1d16ded502cb32c03872bcbfcaa /net/mac80211/ht.c | |
parent | 40333e4fb476014cdd939d27e20eb54573172b32 (diff) |
802.11: clean up/fix HT support
This patch cleans up a number of things:
* the unusable definition of the HT capabilities/HT information
information elements
* variable names that are hard to understand
* mac80211: move ieee80211_handle_ht to ht.c and remove the unused
enable_ht parameter
* mac80211: fix bug with MCS rate 32 in ieee80211_handle_ht
* mac80211: fix bug with casting the result of ieee80211_bss_get_ie
to an information element _contents_ rather than the
whole element, add size checking (another out-of-bounds
access bug fixed!)
* mac80211: remove some unused return values in favour of BUG_ON
checking
* a few minor other things
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.c | 151 |
1 files changed, 129 insertions, 22 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index b854483cf23f..e2d121bf2745 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -20,37 +20,33 @@ | |||
20 | #include "sta_info.h" | 20 | #include "sta_info.h" |
21 | #include "wme.h" | 21 | #include "wme.h" |
22 | 22 | ||
23 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | 23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, |
24 | struct ieee80211_ht_info *ht_info) | 24 | struct ieee80211_sta_ht_cap *ht_cap) |
25 | { | 25 | { |
26 | 26 | ||
27 | if (ht_info == NULL) | 27 | BUG_ON(!ht_cap); |
28 | return -EINVAL; | ||
29 | 28 | ||
30 | memset(ht_info, 0, sizeof(*ht_info)); | 29 | memset(ht_cap, 0, sizeof(*ht_cap)); |
31 | 30 | ||
32 | if (ht_cap_ie) { | 31 | if (ht_cap_ie) { |
33 | u8 ampdu_info = ht_cap_ie->ampdu_params_info; | 32 | u8 ampdu_info = ht_cap_ie->ampdu_params_info; |
34 | 33 | ||
35 | ht_info->ht_supported = 1; | 34 | ht_cap->ht_supported = true; |
36 | ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); | 35 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info); |
37 | ht_info->ampdu_factor = | 36 | ht_cap->ampdu_factor = |
38 | ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; | 37 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; |
39 | ht_info->ampdu_density = | 38 | ht_cap->ampdu_density = |
40 | (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; | 39 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
41 | memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); | 40 | memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs)); |
42 | } else | 41 | } else |
43 | ht_info->ht_supported = 0; | 42 | ht_cap->ht_supported = false; |
44 | |||
45 | return 0; | ||
46 | } | 43 | } |
47 | 44 | ||
48 | int ieee80211_ht_addt_info_ie_to_ht_bss_info( | 45 | void ieee80211_ht_info_ie_to_ht_bss_info( |
49 | struct ieee80211_ht_addt_info *ht_add_info_ie, | 46 | struct ieee80211_ht_info *ht_add_info_ie, |
50 | struct ieee80211_ht_bss_info *bss_info) | 47 | struct ieee80211_ht_bss_info *bss_info) |
51 | { | 48 | { |
52 | if (bss_info == NULL) | 49 | BUG_ON(!bss_info); |
53 | return -EINVAL; | ||
54 | 50 | ||
55 | memset(bss_info, 0, sizeof(*bss_info)); | 51 | memset(bss_info, 0, sizeof(*bss_info)); |
56 | 52 | ||
@@ -62,8 +58,119 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_info( | |||
62 | bss_info->bss_cap = ht_add_info_ie->ht_param; | 58 | bss_info->bss_cap = ht_add_info_ie->ht_param; |
63 | bss_info->bss_op_mode = (u8)(op_mode & 0xff); | 59 | bss_info->bss_op_mode = (u8)(op_mode & 0xff); |
64 | } | 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 | |||
107 | ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap; | ||
108 | ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
109 | ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; | ||
110 | |||
111 | ht_bss_conf.primary_channel = req_bss_cap->primary_channel; | ||
112 | ht_bss_conf.bss_cap = req_bss_cap->bss_cap; | ||
113 | ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; | ||
114 | |||
115 | ht_cap.ampdu_factor = req_ht_cap->ampdu_factor; | ||
116 | ht_cap.ampdu_density = req_ht_cap->ampdu_density; | ||
117 | |||
118 | /* own MCS TX capabilities */ | ||
119 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | ||
120 | |||
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? */ | ||
129 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | ||
130 | goto check_changed; | ||
131 | |||
132 | /* Counting from 0, therefore +1 */ | ||
133 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | ||
134 | max_tx_streams = | ||
135 | ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | ||
136 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | ||
137 | else | ||
138 | max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; | ||
139 | |||
140 | /* | ||
141 | * 802.11n D5.0 20.3.5 / 20.6 says: | ||
142 | * - indices 0 to 7 and 32 are single spatial stream | ||
143 | * - 8 to 31 are multiple spatial streams using equal modulation | ||
144 | * [8..15 for two streams, 16..23 for three and 24..31 for four] | ||
145 | * - remainder are multiple spatial streams using unequal modulation | ||
146 | */ | ||
147 | for (i = 0; i < max_tx_streams; i++) | ||
148 | ht_cap.mcs.rx_mask[i] = | ||
149 | sband->ht_cap.mcs.rx_mask[i] & | ||
150 | req_ht_cap->mcs.rx_mask[i]; | ||
151 | |||
152 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | ||
153 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | ||
154 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||
155 | ht_cap.mcs.rx_mask[i] = | ||
156 | sband->ht_cap.mcs.rx_mask[i] & | ||
157 | req_ht_cap->mcs.rx_mask[i]; | ||
158 | |||
159 | /* handle MCS rate 32 too */ | ||
160 | if (sband->ht_cap.mcs.rx_mask[32/8] & | ||
161 | req_ht_cap->mcs.rx_mask[32/8] & 1) | ||
162 | ht_cap.mcs.rx_mask[32/8] |= 1; | ||
163 | |||
164 | check_changed: | ||
165 | /* if bss configuration changed store the new one */ | ||
166 | if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) || | ||
167 | memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { | ||
168 | changed |= BSS_CHANGED_HT; | ||
169 | memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap)); | ||
170 | memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); | ||
171 | } | ||
65 | 172 | ||
66 | return 0; | 173 | return changed; |
67 | } | 174 | } |
68 | 175 | ||
69 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | 176 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, |
@@ -794,7 +901,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
794 | * check if configuration can support the BA policy | 901 | * check if configuration can support the BA policy |
795 | * and if buffer size does not exceeds max value */ | 902 | * and if buffer size does not exceeds max value */ |
796 | if (((ba_policy != 1) | 903 | if (((ba_policy != 1) |
797 | && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) | 904 | && (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) |
798 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | 905 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { |
799 | status = WLAN_STATUS_INVALID_QOS_PARAM; | 906 | status = WLAN_STATUS_INVALID_QOS_PARAM; |
800 | #ifdef CONFIG_MAC80211_HT_DEBUG | 907 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -812,7 +919,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
812 | 919 | ||
813 | sband = local->hw.wiphy->bands[conf->channel->band]; | 920 | sband = local->hw.wiphy->bands[conf->channel->band]; |
814 | buf_size = IEEE80211_MIN_AMPDU_BUF; | 921 | buf_size = IEEE80211_MIN_AMPDU_BUF; |
815 | buf_size = buf_size << sband->ht_info.ampdu_factor; | 922 | buf_size = buf_size << sband->ht_cap.ampdu_factor; |
816 | } | 923 | } |
817 | 924 | ||
818 | 925 | ||