aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c151
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
23int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, 23void 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
48int ieee80211_ht_addt_info_ie_to_ht_bss_info( 45void 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 */
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
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
69static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, 176static 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