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.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