diff options
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r-- | net/mac80211/ht.c | 181 |
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 | ||
23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, | 23 | void 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 | |||
45 | void 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 | */ | ||
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 | 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 | */ | ||
92 | u32 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 |