Commit | Line | Data |
---|---|---|
18056f34 GKH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
94a79942 LF |
3 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. |
4 | * | |
18056f34 GKH |
5 | * Contact Information: wlanfae <wlanfae@realtek.com> |
6 | */ | |
94a79942 LF |
7 | #include "rtllib.h" |
8 | #include "rtl819x_HT.h" | |
831cb9db LF |
9 | u8 MCS_FILTER_ALL[16] = { |
10 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
11 | 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
12 | }; | |
13 | ||
14 | u8 MCS_FILTER_1SS[16] = { | |
15 | 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | |
16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} | |
17 | ; | |
18 | ||
19 | u16 MCS_DATA_RATE[2][2][77] = { | |
20 | {{13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, | |
21 | 260, 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, | |
22 | 468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, | |
23 | 182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156, | |
24 | 181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273, | |
31f1c464 | 25 | 312, 351, 312, 351, 390, 390, 429}, |
831cb9db LF |
26 | {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289, |
27 | 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, | |
28 | 578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, | |
29 | 173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, | |
30 | 231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, | |
31f1c464 | 31 | 433, 433, 477} }, |
831cb9db LF |
32 | {{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, |
33 | 540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, | |
34 | 864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, | |
35 | 378, 378, 432, 324, 405, 405, 486, 567, 567, 648, 270, 324, 378, 324, | |
36 | 378, 432, 486, 432, 486, 540, 540, 594, 405, 486, 567, 486, 567, 648, | |
37 | 729, 648, 729, 810, 810, 891}, | |
38 | {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, | |
39 | 600, 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, | |
40 | 960, 1080, 1200, 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, | |
41 | 420, 420, 480, 360, 450, 450, 540, 630, 630, 720, 300, 360, 420, 360, | |
42 | 420, 480, 540, 480, 540, 600, 600, 660, 450, 540, 630, 540, 630, 720, | |
43 | 810, 720, 810, 900, 900, 990} } | |
44 | }; | |
94a79942 LF |
45 | |
46 | static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf}; | |
831cb9db | 47 | |
94a79942 | 48 | static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70}; |
831cb9db | 49 | |
94a79942 | 50 | static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e}; |
831cb9db | 51 | |
94a79942 | 52 | static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; |
831cb9db | 53 | |
94a79942 | 54 | static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf}; |
831cb9db | 55 | |
94a79942 | 56 | static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc}; |
831cb9db | 57 | |
94a79942 | 58 | static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e}; |
831cb9db | 59 | |
94a79942 | 60 | static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02}; |
831cb9db | 61 | |
94a79942 | 62 | static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0}; |
831cb9db | 63 | |
94a79942 | 64 | static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91}; |
831cb9db | 65 | |
94a79942 | 66 | static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94}; |
831cb9db | 67 | |
94a79942 | 68 | static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4}; |
831cb9db | 69 | |
218f1c14 | 70 | void ht_update_default_setting(struct rtllib_device *ieee) |
94a79942 | 71 | { |
ccdbe14b | 72 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
a6f100aa | 73 | |
e97f14e9 | 74 | ht_info->ampdu_enable = 1; |
1d7ce986 | 75 | ht_info->ampdu_factor = 2; |
94a79942 | 76 | |
b397fc48 PH |
77 | ieee->tx_dis_rate_fallback = 0; |
78 | ieee->tx_use_drv_assinged_rate = 0; | |
94a79942 | 79 | |
445bdee3 | 80 | ieee->tx_enable_fw_calc_dur = 1; |
94a79942 | 81 | |
ccdbe14b PH |
82 | ht_info->rx_reorder_win_size = 64; |
83 | ht_info->rx_reorder_pending_time = 30; | |
94a79942 | 84 | } |
831cb9db | 85 | |
d9443ac5 | 86 | static u16 ht_mcs_to_data_rate(struct rtllib_device *ieee, u8 mcs_rate) |
94a79942 | 87 | { |
ccdbe14b | 88 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
94a79942 | 89 | |
213702c8 GR |
90 | u8 is40MHz = (ht_info->cur_bw_40mhz) ? 1 : 0; |
91 | u8 isShortGI = (ht_info->cur_bw_40mhz) ? | |
da811655 | 92 | ((ht_info->cur_short_gi_40mhz) ? 1 : 0) : |
5ca1e3c9 | 93 | ((ht_info->cur_short_gi_20mhz) ? 1 : 0); |
d9443ac5 | 94 | return MCS_DATA_RATE[is40MHz][isShortGI][(mcs_rate & 0x7f)]; |
94a79942 LF |
95 | } |
96 | ||
ad96610a | 97 | u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 data_rate) |
94a79942 | 98 | { |
fd19bb05 | 99 | u16 cck_of_dm_rate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, |
831cb9db | 100 | 0x24, 0x30, 0x48, 0x60, 0x6c}; |
94a79942 LF |
101 | u8 is40MHz = 0; |
102 | u8 isShortGI = 0; | |
103 | ||
ad96610a | 104 | if (data_rate < 12) |
fd19bb05 | 105 | return cck_of_dm_rate[data_rate]; |
ad96610a | 106 | if (data_rate >= 0x10 && data_rate <= 0x1f) { |
285b7c00 MK |
107 | is40MHz = 0; |
108 | isShortGI = 0; | |
ad96610a | 109 | } else if (data_rate >= 0x20 && data_rate <= 0x2f) { |
285b7c00 MK |
110 | is40MHz = 1; |
111 | isShortGI = 0; | |
ad96610a | 112 | } else if (data_rate >= 0x30 && data_rate <= 0x3f) { |
285b7c00 MK |
113 | is40MHz = 0; |
114 | isShortGI = 1; | |
ad96610a | 115 | } else if (data_rate >= 0x40 && data_rate <= 0x4f) { |
285b7c00 MK |
116 | is40MHz = 1; |
117 | isShortGI = 1; | |
94a79942 | 118 | } |
ad96610a | 119 | return MCS_DATA_RATE[is40MHz][isShortGI][data_rate & 0xf]; |
94a79942 LF |
120 | } |
121 | ||
ea6df150 | 122 | bool is_ht_half_nmode_aps(struct rtllib_device *ieee) |
94a79942 LF |
123 | { |
124 | bool retValue = false; | |
831cb9db LF |
125 | struct rtllib_network *net = &ieee->current_network; |
126 | ||
127 | if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || | |
128 | (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || | |
129 | (memcmp(net->bssid, PCI_RALINK, 3) == 0) || | |
130 | (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || | |
131 | (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || | |
132 | (net->ralink_cap_exist)) | |
133 | retValue = true; | |
134 | else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || | |
354989f7 AL |
135 | !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || |
136 | !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) || | |
831cb9db | 137 | (net->broadcom_cap_exist)) |
94a79942 | 138 | retValue = true; |
3f1f39fb | 139 | else if (net->bssht.bd_rt2rt_aggregation) |
94a79942 LF |
140 | retValue = true; |
141 | else | |
142 | retValue = false; | |
143 | ||
144 | return retValue; | |
145 | } | |
146 | ||
d6171fe9 | 147 | static void ht_iot_peer_determine(struct rtllib_device *ieee) |
94a79942 | 148 | { |
ccdbe14b | 149 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
831cb9db | 150 | struct rtllib_network *net = &ieee->current_network; |
3a6b70c3 | 151 | |
3f1f39fb | 152 | if (net->bssht.bd_rt2rt_aggregation) { |
345586fe | 153 | ht_info->iot_peer = HT_IOT_PEER_REALTEK; |
6628c674 | 154 | if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_92SE) |
345586fe | 155 | ht_info->iot_peer = HT_IOT_PEER_REALTEK_92SE; |
6628c674 | 156 | if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_SOFTAP) |
345586fe | 157 | ht_info->iot_peer = HT_IOT_PEER_92U_SOFTAP; |
8b5b1b81 | 158 | } else if (net->broadcom_cap_exist) { |
345586fe | 159 | ht_info->iot_peer = HT_IOT_PEER_BROADCOM; |
8b5b1b81 | 160 | } else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || |
831cb9db | 161 | !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || |
8b5b1b81 | 162 | !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) { |
345586fe | 163 | ht_info->iot_peer = HT_IOT_PEER_BROADCOM; |
8b5b1b81 | 164 | } else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || |
831cb9db LF |
165 | (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || |
166 | (memcmp(net->bssid, PCI_RALINK, 3) == 0) || | |
167 | (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || | |
168 | (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || | |
8b5b1b81 | 169 | net->ralink_cap_exist) { |
345586fe | 170 | ht_info->iot_peer = HT_IOT_PEER_RALINK; |
8b5b1b81 | 171 | } else if ((net->atheros_cap_exist) || |
831cb9db | 172 | (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) || |
8b5b1b81 | 173 | (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) { |
345586fe | 174 | ht_info->iot_peer = HT_IOT_PEER_ATHEROS; |
8b5b1b81 EV |
175 | } else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) || |
176 | net->cisco_cap_exist) { | |
345586fe | 177 | ht_info->iot_peer = HT_IOT_PEER_CISCO; |
8b5b1b81 EV |
178 | } else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || |
179 | net->marvell_cap_exist) { | |
345586fe | 180 | ht_info->iot_peer = HT_IOT_PEER_MARVELL; |
8b5b1b81 | 181 | } else if (net->airgo_cap_exist) { |
345586fe | 182 | ht_info->iot_peer = HT_IOT_PEER_AIRGO; |
8b5b1b81 | 183 | } else { |
345586fe | 184 | ht_info->iot_peer = HT_IOT_PEER_UNKNOWN; |
8b5b1b81 | 185 | } |
94a79942 | 186 | |
345586fe | 187 | netdev_dbg(ieee->dev, "IOTPEER: %x\n", ht_info->iot_peer); |
94a79942 LF |
188 | } |
189 | ||
32992c40 | 190 | static u8 ht_iot_act_is_mgnt_use_cck_6m(struct rtllib_device *ieee, |
ec0dc6be | 191 | struct rtllib_network *network) |
94a79942 LF |
192 | { |
193 | u8 retValue = 0; | |
194 | ||
345586fe | 195 | if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) |
94a79942 | 196 | retValue = 1; |
94a79942 LF |
197 | |
198 | return retValue; | |
199 | } | |
200 | ||
2d3f27b5 | 201 | static u8 ht_iot_act_is_ccd_fsync(struct rtllib_device *ieee) |
94a79942 LF |
202 | { |
203 | u8 retValue = 0; | |
831cb9db | 204 | |
345586fe | 205 | if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) |
94a79942 | 206 | retValue = 1; |
94a79942 LF |
207 | return retValue; |
208 | } | |
209 | ||
6bcb6ec3 | 210 | static void ht_iot_act_determine_ra_func(struct rtllib_device *ieee, bool bPeerRx2ss) |
94a79942 | 211 | { |
ccdbe14b | 212 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
3a6b70c3 | 213 | |
ccdbe14b | 214 | ht_info->iot_ra_func &= HT_IOT_RAFUNC_DISABLE_ALL; |
94a79942 | 215 | |
345586fe | 216 | if (ht_info->iot_peer == HT_IOT_PEER_RALINK && !bPeerRx2ss) |
ccdbe14b | 217 | ht_info->iot_ra_func |= HT_IOT_RAFUNC_PEER_1R; |
94a79942 | 218 | |
ccdbe14b PH |
219 | if (ht_info->iot_action & HT_IOT_ACT_AMSDU_ENABLE) |
220 | ht_info->iot_ra_func |= HT_IOT_RAFUNC_TX_AMSDU; | |
94a79942 LF |
221 | } |
222 | ||
9ba1a160 | 223 | void ht_reset_iot_setting(struct rt_hi_throughput *ht_info) |
94a79942 | 224 | { |
ccdbe14b | 225 | ht_info->iot_action = 0; |
345586fe | 226 | ht_info->iot_peer = HT_IOT_PEER_UNKNOWN; |
ccdbe14b | 227 | ht_info->iot_ra_func = 0; |
94a79942 LF |
228 | } |
229 | ||
078330ab | 230 | void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap, |
145524f8 | 231 | u8 *len, u8 is_encrypt, bool assoc) |
94a79942 | 232 | { |
b2264b62 | 233 | struct rt_hi_throughput *ht = ieee->ht_info; |
d08c910e | 234 | struct ht_capab_ele *cap_ele = NULL; |
94a79942 | 235 | |
b2264b62 | 236 | if (!pos_ht_cap || !ht) { |
11e672c3 | 237 | netdev_warn(ieee->dev, |
8f3d1269 | 238 | "%s(): pos_ht_cap and ht_info are null\n", __func__); |
94a79942 LF |
239 | return; |
240 | } | |
078330ab | 241 | memset(pos_ht_cap, 0, *len); |
94a79942 | 242 | |
93235f62 | 243 | if ((assoc) && (ht->peer_ht_spec_ver == HT_SPEC_VER_EWC)) { |
1d629063 | 244 | static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 }; |
3a6b70c3 | 245 | |
078330ab | 246 | memcpy(pos_ht_cap, EWC11NHTCap, sizeof(EWC11NHTCap)); |
d08c910e | 247 | cap_ele = (struct ht_capab_ele *)&pos_ht_cap[4]; |
94a79942 | 248 | *len = 30 + 2; |
831cb9db | 249 | } else { |
d08c910e | 250 | cap_ele = (struct ht_capab_ele *)pos_ht_cap; |
94a79942 LF |
251 | *len = 26 + 2; |
252 | } | |
253 | ||
d08c910e | 254 | cap_ele->AdvCoding = 0; |
b9e4dfb0 | 255 | if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) |
d08c910e | 256 | cap_ele->ChlWidth = 0; |
94a79942 | 257 | else |
d08c910e | 258 | cap_ele->ChlWidth = 1; |
94a79942 | 259 | |
d08c910e GR |
260 | cap_ele->MimoPwrSave = 3; |
261 | cap_ele->GreenField = 0; | |
262 | cap_ele->ShortGI20Mhz = 1; | |
263 | cap_ele->ShortGI40Mhz = 1; | |
94a79942 | 264 | |
d08c910e GR |
265 | cap_ele->TxSTBC = 1; |
266 | cap_ele->RxSTBC = 0; | |
267 | cap_ele->DelayBA = 0; | |
268 | cap_ele->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0; | |
269 | cap_ele->DssCCk = 1; | |
270 | cap_ele->PSMP = 0; | |
fb3ac10f | 271 | cap_ele->lsig_txop_protect = 0; |
94a79942 | 272 | |
b94436b5 MK |
273 | netdev_dbg(ieee->dev, |
274 | "TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n", | |
d08c910e | 275 | cap_ele->ChlWidth, cap_ele->MaxAMSDUSize, cap_ele->DssCCk); |
94a79942 | 276 | |
1a469abc | 277 | if (is_encrypt) { |
d08c910e GR |
278 | cap_ele->MPDUDensity = 7; |
279 | cap_ele->MaxRxAMPDUFactor = 2; | |
831cb9db | 280 | } else { |
d08c910e GR |
281 | cap_ele->MaxRxAMPDUFactor = 3; |
282 | cap_ele->MPDUDensity = 0; | |
94a79942 LF |
283 | } |
284 | ||
d08c910e GR |
285 | memcpy(cap_ele->MCS, ieee->reg_dot11ht_oper_rate_set, 16); |
286 | memset(&cap_ele->ExtHTCapInfo, 0, 2); | |
287 | memset(cap_ele->TxBFCap, 0, 4); | |
94a79942 | 288 | |
d08c910e | 289 | cap_ele->ASCap = 0; |
94a79942 | 290 | |
145524f8 | 291 | if (assoc) { |
b2264b62 | 292 | if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS15) |
d08c910e | 293 | cap_ele->MCS[1] &= 0x7f; |
94a79942 | 294 | |
b2264b62 | 295 | if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS14) |
d08c910e | 296 | cap_ele->MCS[1] &= 0xbf; |
94a79942 | 297 | |
b2264b62 | 298 | if (ht->iot_action & HT_IOT_ACT_DISABLE_ALL_2SS) |
d08c910e | 299 | cap_ele->MCS[1] &= 0x00; |
94a79942 | 300 | |
b2264b62 | 301 | if (ht->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI) |
d08c910e | 302 | cap_ele->ShortGI40Mhz = 0; |
94a79942 | 303 | |
b9e4dfb0 | 304 | if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) { |
d08c910e GR |
305 | cap_ele->ChlWidth = 0; |
306 | cap_ele->MCS[1] = 0; | |
94a79942 LF |
307 | } |
308 | } | |
94a79942 | 309 | } |
831cb9db | 310 | |
83280534 | 311 | void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg, |
831cb9db | 312 | u8 *len) |
94a79942 | 313 | { |
84b45d4f | 314 | if (!posRT2RTAgg) { |
11e672c3 | 315 | netdev_warn(ieee->dev, "%s(): posRT2RTAgg is null\n", __func__); |
94a79942 LF |
316 | return; |
317 | } | |
318 | memset(posRT2RTAgg, 0, *len); | |
319 | *posRT2RTAgg++ = 0x00; | |
320 | *posRT2RTAgg++ = 0xe0; | |
321 | *posRT2RTAgg++ = 0x4c; | |
322 | *posRT2RTAgg++ = 0x02; | |
323 | *posRT2RTAgg++ = 0x01; | |
324 | ||
94a79942 | 325 | *posRT2RTAgg = 0x30; |
94a79942 | 326 | |
831cb9db | 327 | if (ieee->bSupportRemoteWakeUp) |
94a79942 | 328 | *posRT2RTAgg |= RT_HT_CAP_USE_WOW; |
94a79942 LF |
329 | |
330 | *len = 6 + 2; | |
94a79942 LF |
331 | } |
332 | ||
07c9ef14 | 333 | static u8 ht_pick_mcs_rate(struct rtllib_device *ieee, u8 *pOperateMCS) |
94a79942 | 334 | { |
831cb9db | 335 | u8 i; |
3a6b70c3 | 336 | |
84b45d4f | 337 | if (!pOperateMCS) { |
11e672c3 | 338 | netdev_warn(ieee->dev, "%s(): pOperateMCS is null\n", __func__); |
94a79942 LF |
339 | return false; |
340 | } | |
341 | ||
342 | switch (ieee->mode) { | |
5cac011c PH |
343 | case WIRELESS_MODE_B: |
344 | case WIRELESS_MODE_G: | |
831cb9db LF |
345 | for (i = 0; i <= 15; i++) |
346 | pOperateMCS[i] = 0; | |
94a79942 | 347 | break; |
5cac011c | 348 | case WIRELESS_MODE_N_24G: |
831cb9db LF |
349 | pOperateMCS[0] &= RATE_ADPT_1SS_MASK; |
350 | pOperateMCS[1] &= RATE_ADPT_2SS_MASK; | |
351 | pOperateMCS[3] &= RATE_ADPT_MCS32_MASK; | |
94a79942 LF |
352 | break; |
353 | default: | |
354 | break; | |
94a79942 LF |
355 | } |
356 | ||
357 | return true; | |
358 | } | |
359 | ||
2e9b84b7 | 360 | u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet, |
831cb9db | 361 | u8 *pMCSFilter) |
94a79942 LF |
362 | { |
363 | u8 i, j; | |
364 | u8 bitMap; | |
365 | u8 mcsRate = 0; | |
366 | u8 availableMcsRate[16]; | |
3a6b70c3 | 367 | |
84b45d4f | 368 | if (!pMCSRateSet || !pMCSFilter) { |
11e672c3 MK |
369 | netdev_warn(ieee->dev, |
370 | "%s(): pMCSRateSet and pMCSFilter are null\n", | |
371 | __func__); | |
94a79942 LF |
372 | return false; |
373 | } | |
831cb9db | 374 | for (i = 0; i < 16; i++) |
94a79942 LF |
375 | availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i]; |
376 | ||
831cb9db | 377 | for (i = 0; i < 16; i++) { |
94a79942 LF |
378 | if (availableMcsRate[i] != 0) |
379 | break; | |
380 | } | |
381 | if (i == 16) | |
382 | return false; | |
383 | ||
831cb9db LF |
384 | for (i = 0; i < 16; i++) { |
385 | if (availableMcsRate[i] != 0) { | |
94a79942 | 386 | bitMap = availableMcsRate[i]; |
831cb9db | 387 | for (j = 0; j < 8; j++) { |
3cc112a0 | 388 | if ((bitMap % 2) != 0) { |
f0a8eb60 GR |
389 | if (ht_mcs_to_data_rate(ieee, (8 * i + j)) > |
390 | ht_mcs_to_data_rate(ieee, mcsRate)) | |
24542a00 | 391 | mcsRate = 8 * i + j; |
94a79942 | 392 | } |
be31fed4 | 393 | bitMap >>= 1; |
94a79942 LF |
394 | } |
395 | } | |
396 | } | |
831cb9db | 397 | return mcsRate | 0x80; |
94a79942 LF |
398 | } |
399 | ||
93663789 | 400 | static u8 ht_filter_mcs_rate(struct rtllib_device *ieee, u8 *pSupportMCS, |
e0c84c1c | 401 | u8 *pOperateMCS) |
94a79942 | 402 | { |
831cb9db | 403 | u8 i; |
94a79942 | 404 | |
831cb9db | 405 | for (i = 0; i <= 15; i++) |
ca25401e | 406 | pOperateMCS[i] = ieee->reg_dot11tx_ht_oper_rate_set[i] & |
831cb9db | 407 | pSupportMCS[i]; |
94a79942 | 408 | |
07c9ef14 | 409 | ht_pick_mcs_rate(ieee, pOperateMCS); |
94a79942 | 410 | |
b9e4dfb0 | 411 | if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) |
94a79942 LF |
412 | pOperateMCS[1] = 0; |
413 | ||
831cb9db | 414 | for (i = 2; i <= 15; i++) |
94a79942 LF |
415 | pOperateMCS[i] = 0; |
416 | ||
417 | return true; | |
418 | } | |
831cb9db | 419 | |
36802495 | 420 | void ht_set_connect_bw_mode(struct rtllib_device *ieee, |
4256e500 | 421 | enum ht_channel_width bandwidth, |
831cb9db LF |
422 | enum ht_extchnl_offset Offset); |
423 | ||
8caf3a8e | 424 | void ht_on_assoc_rsp(struct rtllib_device *ieee) |
94a79942 | 425 | { |
ccdbe14b | 426 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
e92b71d5 | 427 | struct ht_capab_ele *pPeerHTCap = NULL; |
407e998e | 428 | struct ht_info_ele *pPeerHTInfo = NULL; |
831cb9db | 429 | u8 *pMcsFilter = NULL; |
94a79942 | 430 | |
1d629063 CIK |
431 | static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 }; |
432 | static const u8 EWC11NHTInfo[] = { 0x00, 0x90, 0x4c, 0x34 }; | |
94a79942 | 433 | |
782bfb06 | 434 | if (!ht_info->current_ht_support) { |
11e672c3 | 435 | netdev_warn(ieee->dev, "%s(): HT_DISABLE\n", __func__); |
94a79942 LF |
436 | return; |
437 | } | |
b94436b5 | 438 | netdev_dbg(ieee->dev, "%s(): HT_ENABLE\n", __func__); |
94a79942 | 439 | |
05ee6e2f TD |
440 | if (!memcmp(ht_info->peer_ht_cap_buf, EWC11NHTCap, sizeof(EWC11NHTCap))) |
441 | pPeerHTCap = (struct ht_capab_ele *)(&ht_info->peer_ht_cap_buf[4]); | |
94a79942 | 442 | else |
05ee6e2f | 443 | pPeerHTCap = (struct ht_capab_ele *)(ht_info->peer_ht_cap_buf); |
94a79942 | 444 | |
332fe0ec | 445 | if (!memcmp(ht_info->peer_ht_info_buf, EWC11NHTInfo, sizeof(EWC11NHTInfo))) |
831cb9db | 446 | pPeerHTInfo = (struct ht_info_ele *) |
332fe0ec | 447 | (&ht_info->peer_ht_info_buf[4]); |
94a79942 | 448 | else |
332fe0ec | 449 | pPeerHTInfo = (struct ht_info_ele *)(ht_info->peer_ht_info_buf); |
94a79942 | 450 | |
72321415 | 451 | #ifdef VERBOSE_DEBUG |
b99692f4 | 452 | print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, |
72321415 MK |
453 | pPeerHTCap, sizeof(struct ht_capab_ele)); |
454 | #endif | |
36802495 | 455 | ht_set_connect_bw_mode(ieee, (enum ht_channel_width)(pPeerHTCap->ChlWidth), |
354989f7 | 456 | (enum ht_extchnl_offset)(pPeerHTInfo->ExtChlOffset)); |
ccdbe14b | 457 | ht_info->cur_tx_bw40mhz = ((pPeerHTInfo->RecommemdedTxWidth == 1) ? |
831cb9db | 458 | true : false); |
94a79942 | 459 | |
97c75386 | 460 | ht_info->cur_short_gi_20mhz = ((pPeerHTCap->ShortGI20Mhz == 1) ? true : false); |
e5d021b7 | 461 | ht_info->cur_short_gi_40mhz = ((pPeerHTCap->ShortGI40Mhz == 1) ? true : false); |
94a79942 | 462 | |
e97f14e9 | 463 | ht_info->current_ampdu_enable = ht_info->ampdu_enable; |
94a79942 | 464 | if (ieee->rtllib_ap_sec_type && |
354989f7 | 465 | (ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_WEP | SEC_ALG_TKIP))) { |
345586fe GR |
466 | if ((ht_info->iot_peer == HT_IOT_PEER_ATHEROS) || |
467 | (ht_info->iot_peer == HT_IOT_PEER_UNKNOWN)) | |
c1d2dc03 | 468 | ht_info->current_ampdu_enable = false; |
94a79942 LF |
469 | } |
470 | ||
286f01ea PH |
471 | if (ieee->current_network.bssht.bd_rt2rt_aggregation) { |
472 | if (ieee->pairwise_key_type != KEY_TYPE_NA) | |
f72a0778 | 473 | ht_info->current_ampdu_factor = |
286f01ea | 474 | pPeerHTCap->MaxRxAMPDUFactor; |
94a79942 | 475 | else |
f72a0778 | 476 | ht_info->current_ampdu_factor = HT_AGG_SIZE_64K; |
94a79942 | 477 | } else { |
f72a0778 | 478 | ht_info->current_ampdu_factor = min_t(u32, pPeerHTCap->MaxRxAMPDUFactor, |
286f01ea | 479 | HT_AGG_SIZE_32K); |
94a79942 | 480 | } |
286f01ea | 481 | |
584c18e2 | 482 | ht_info->current_mpdu_density = pPeerHTCap->MPDUDensity; |
0ef4a269 | 483 | if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K) |
c1d2dc03 | 484 | ht_info->current_ampdu_enable = false; |
0ef4a269 | 485 | |
162440f2 | 486 | ht_info->cur_rx_reorder_enable = 1; |
94a79942 LF |
487 | |
488 | if (pPeerHTCap->MCS[0] == 0) | |
489 | pPeerHTCap->MCS[0] = 0xff; | |
490 | ||
6bcb6ec3 | 491 | ht_iot_act_determine_ra_func(ieee, ((pPeerHTCap->MCS[1]) != 0)); |
94a79942 | 492 | |
93663789 | 493 | ht_filter_mcs_rate(ieee, pPeerHTCap->MCS, ieee->dot11ht_oper_rate_set); |
94a79942 | 494 | |
e7eeb02b | 495 | pMcsFilter = MCS_FILTER_ALL; |
2e9b84b7 | 496 | ieee->HTHighestOperaRate = ht_get_highest_mcs_rate(ieee, |
ca25401e | 497 | ieee->dot11ht_oper_rate_set, |
354989f7 | 498 | pMcsFilter); |
94a79942 LF |
499 | ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; |
500 | ||
b45d48dc | 501 | ht_info->current_op_mode = pPeerHTInfo->opt_mode; |
94a79942 LF |
502 | } |
503 | ||
5e8cdb6f | 504 | void ht_initialize_ht_info(struct rtllib_device *ieee) |
94a79942 | 505 | { |
ccdbe14b | 506 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
94a79942 | 507 | |
782bfb06 | 508 | ht_info->current_ht_support = false; |
94a79942 | 509 | |
213702c8 | 510 | ht_info->cur_bw_40mhz = false; |
ccdbe14b | 511 | ht_info->cur_tx_bw40mhz = false; |
94a79942 | 512 | |
5ca1e3c9 | 513 | ht_info->cur_short_gi_20mhz = false; |
da811655 | 514 | ht_info->cur_short_gi_40mhz = false; |
94a79942 | 515 | |
584c18e2 | 516 | ht_info->current_mpdu_density = 0; |
f72a0778 | 517 | ht_info->current_ampdu_factor = ht_info->ampdu_factor; |
94a79942 | 518 | |
0efe628a TD |
519 | memset((void *)(&ht_info->self_ht_cap), 0, |
520 | sizeof(ht_info->self_ht_cap)); | |
05ee6e2f TD |
521 | memset((void *)(&ht_info->peer_ht_cap_buf), 0, |
522 | sizeof(ht_info->peer_ht_cap_buf)); | |
332fe0ec TD |
523 | memset((void *)(&ht_info->peer_ht_info_buf), 0, |
524 | sizeof(ht_info->peer_ht_info_buf)); | |
94a79942 | 525 | |
ccdbe14b | 526 | ht_info->sw_bw_in_progress = false; |
94a79942 | 527 | |
93235f62 | 528 | ht_info->peer_ht_spec_ver = HT_SPEC_VER_IEEE; |
94a79942 | 529 | |
ccdbe14b PH |
530 | ht_info->current_rt2rt_aggregation = false; |
531 | ht_info->current_rt2rt_long_slot_time = false; | |
94a79942 | 532 | |
345586fe | 533 | ht_info->iot_peer = 0; |
ccdbe14b PH |
534 | ht_info->iot_action = 0; |
535 | ht_info->iot_ra_func = 0; | |
94a79942 LF |
536 | |
537 | { | |
ca25401e | 538 | u8 *RegHTSuppRateSets = &ieee->reg_ht_supp_rate_set[0]; |
3a6b70c3 | 539 | |
94a79942 LF |
540 | RegHTSuppRateSets[0] = 0xFF; |
541 | RegHTSuppRateSets[1] = 0xFF; | |
542 | RegHTSuppRateSets[4] = 0x01; | |
543 | } | |
544 | } | |
831cb9db | 545 | |
9cfe5964 | 546 | void ht_initialize_bss_desc(struct bss_ht *bss_ht) |
94a79942 | 547 | { |
9cfe5964 TD |
548 | bss_ht->bd_support_ht = false; |
549 | memset(bss_ht->bd_ht_cap_buf, 0, sizeof(bss_ht->bd_ht_cap_buf)); | |
550 | bss_ht->bd_ht_cap_len = 0; | |
551 | memset(bss_ht->bd_ht_info_buf, 0, sizeof(bss_ht->bd_ht_info_buf)); | |
552 | bss_ht->bd_ht_info_len = 0; | |
94a79942 | 553 | |
9cfe5964 | 554 | bss_ht->bd_ht_spec_ver = HT_SPEC_VER_IEEE; |
94a79942 | 555 | |
9cfe5964 TD |
556 | bss_ht->bd_rt2rt_aggregation = false; |
557 | bss_ht->bd_rt2rt_long_slot_time = false; | |
558 | bss_ht->rt2rt_ht_mode = (enum rt_ht_capability)0; | |
94a79942 LF |
559 | } |
560 | ||
0901e696 | 561 | void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee, |
831cb9db | 562 | struct rtllib_network *pNetwork) |
94a79942 | 563 | { |
ccdbe14b | 564 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
94a79942 LF |
565 | u8 bIOTAction = 0; |
566 | ||
ab4bcf79 | 567 | /* unmark enable_ht flag here is the same reason why unmarked in |
14b40d92 MK |
568 | * function rtllib_softmac_new_net. WB 2008.09.10 |
569 | */ | |
b3b55bd7 | 570 | if (pNetwork->bssht.bd_support_ht) { |
782bfb06 | 571 | ht_info->current_ht_support = true; |
93235f62 | 572 | ht_info->peer_ht_spec_ver = pNetwork->bssht.bd_ht_spec_ver; |
94a79942 | 573 | |
20e90635 | 574 | if (pNetwork->bssht.bd_ht_cap_len > 0 && |
05ee6e2f TD |
575 | pNetwork->bssht.bd_ht_cap_len <= sizeof(ht_info->peer_ht_cap_buf)) |
576 | memcpy(ht_info->peer_ht_cap_buf, | |
b87b2108 | 577 | pNetwork->bssht.bd_ht_cap_buf, |
20e90635 | 578 | pNetwork->bssht.bd_ht_cap_len); |
831cb9db | 579 | |
060d3f6c WD |
580 | if (pNetwork->bssht.bd_ht_info_len > 0 && |
581 | pNetwork->bssht.bd_ht_info_len <= | |
332fe0ec TD |
582 | sizeof(ht_info->peer_ht_info_buf)) |
583 | memcpy(ht_info->peer_ht_info_buf, | |
2408ee9e | 584 | pNetwork->bssht.bd_ht_info_buf, |
060d3f6c | 585 | pNetwork->bssht.bd_ht_info_len); |
831cb9db | 586 | |
286f01ea PH |
587 | ht_info->current_rt2rt_aggregation = |
588 | pNetwork->bssht.bd_rt2rt_aggregation; | |
589 | ht_info->current_rt2rt_long_slot_time = | |
590 | pNetwork->bssht.bd_rt2rt_long_slot_time; | |
94a79942 | 591 | |
d6171fe9 | 592 | ht_iot_peer_determine(ieee); |
94a79942 | 593 | |
ccdbe14b | 594 | ht_info->iot_action = 0; |
32992c40 | 595 | bIOTAction = ht_iot_act_is_mgnt_use_cck_6m(ieee, pNetwork); |
94a79942 | 596 | if (bIOTAction) |
ccdbe14b | 597 | ht_info->iot_action |= HT_IOT_ACT_MGNT_USE_CCK_6M; |
2d3f27b5 | 598 | bIOTAction = ht_iot_act_is_ccd_fsync(ieee); |
94a79942 | 599 | if (bIOTAction) |
ccdbe14b | 600 | ht_info->iot_action |= HT_IOT_ACT_CDD_FSYNC; |
94a79942 | 601 | } else { |
782bfb06 | 602 | ht_info->current_ht_support = false; |
ccdbe14b PH |
603 | ht_info->current_rt2rt_aggregation = false; |
604 | ht_info->current_rt2rt_long_slot_time = false; | |
94a79942 | 605 | |
ccdbe14b PH |
606 | ht_info->iot_action = 0; |
607 | ht_info->iot_ra_func = 0; | |
94a79942 | 608 | } |
94a79942 LF |
609 | } |
610 | ||
976d5341 SM |
611 | void HT_update_self_and_peer_setting(struct rtllib_device *ieee, |
612 | struct rtllib_network *pNetwork) | |
94a79942 | 613 | { |
ccdbe14b | 614 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
831cb9db | 615 | struct ht_info_ele *pPeerHTInfo = |
2408ee9e | 616 | (struct ht_info_ele *)pNetwork->bssht.bd_ht_info_buf; |
94a79942 | 617 | |
782bfb06 | 618 | if (ht_info->current_ht_support) { |
060d3f6c | 619 | if (pNetwork->bssht.bd_ht_info_len != 0) |
b45d48dc | 620 | ht_info->current_op_mode = pPeerHTInfo->opt_mode; |
94a79942 LF |
621 | } |
622 | } | |
976d5341 | 623 | EXPORT_SYMBOL(HT_update_self_and_peer_setting); |
94a79942 | 624 | |
b399e239 | 625 | u8 ht_c_check(struct rtllib_device *ieee, u8 *pFrame) |
94a79942 | 626 | { |
782bfb06 | 627 | if (ieee->ht_info->current_ht_support) { |
7ea8ae9e | 628 | if ((IsQoSDataFrame(pFrame) && frame_order(pFrame)) == 1) { |
b94436b5 | 629 | netdev_dbg(ieee->dev, "HT CONTROL FILED EXIST!!\n"); |
94a79942 LF |
630 | return true; |
631 | } | |
632 | } | |
633 | return false; | |
634 | } | |
635 | ||
35350898 | 636 | static void ht_set_connect_bw_mode_callback(struct rtllib_device *ieee) |
831cb9db | 637 | { |
ccdbe14b | 638 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
831cb9db | 639 | |
213702c8 | 640 | if (ht_info->cur_bw_40mhz) { |
01742a40 | 641 | if (ht_info->cur_sta_ext_chnl_offset == HT_EXTCHNL_OFFSET_UPPER) |
831cb9db LF |
642 | ieee->set_chan(ieee->dev, |
643 | ieee->current_network.channel + 2); | |
01742a40 | 644 | else if (ht_info->cur_sta_ext_chnl_offset == |
831cb9db LF |
645 | HT_EXTCHNL_OFFSET_LOWER) |
646 | ieee->set_chan(ieee->dev, | |
647 | ieee->current_network.channel - 2); | |
648 | else | |
649 | ieee->set_chan(ieee->dev, | |
650 | ieee->current_network.channel); | |
651 | ||
0ec908bc | 652 | ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20_40, |
01742a40 | 653 | ht_info->cur_sta_ext_chnl_offset); |
831cb9db LF |
654 | } else { |
655 | ieee->set_chan(ieee->dev, ieee->current_network.channel); | |
0ec908bc | 656 | ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20, |
831cb9db LF |
657 | HT_EXTCHNL_OFFSET_NO_EXT); |
658 | } | |
659 | ||
ccdbe14b | 660 | ht_info->sw_bw_in_progress = false; |
831cb9db LF |
661 | } |
662 | ||
36802495 | 663 | void ht_set_connect_bw_mode(struct rtllib_device *ieee, |
4256e500 | 664 | enum ht_channel_width bandwidth, |
831cb9db | 665 | enum ht_extchnl_offset Offset) |
94a79942 | 666 | { |
ccdbe14b | 667 | struct rt_hi_throughput *ht_info = ieee->ht_info; |
94a79942 | 668 | |
b9e4dfb0 | 669 | if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) |
4256e500 | 670 | bandwidth = HT_CHANNEL_WIDTH_20; |
94a79942 | 671 | |
ccdbe14b | 672 | if (ht_info->sw_bw_in_progress) { |
27dd3f00 | 673 | pr_info("%s: sw_bw_in_progress!!\n", __func__); |
94a79942 LF |
674 | return; |
675 | } | |
4256e500 | 676 | if (bandwidth == HT_CHANNEL_WIDTH_20_40) { |
831cb9db LF |
677 | if (ieee->current_network.channel < 2 && |
678 | Offset == HT_EXTCHNL_OFFSET_LOWER) | |
94a79942 | 679 | Offset = HT_EXTCHNL_OFFSET_NO_EXT; |
831cb9db LF |
680 | if (Offset == HT_EXTCHNL_OFFSET_UPPER || |
681 | Offset == HT_EXTCHNL_OFFSET_LOWER) { | |
213702c8 | 682 | ht_info->cur_bw_40mhz = true; |
01742a40 | 683 | ht_info->cur_sta_ext_chnl_offset = Offset; |
94a79942 | 684 | } else { |
213702c8 | 685 | ht_info->cur_bw_40mhz = false; |
01742a40 | 686 | ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT; |
94a79942 LF |
687 | } |
688 | } else { | |
213702c8 | 689 | ht_info->cur_bw_40mhz = false; |
01742a40 | 690 | ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT; |
94a79942 LF |
691 | } |
692 | ||
ccdbe14b | 693 | netdev_dbg(ieee->dev, "%s():ht_info->bCurBW40MHz:%x\n", __func__, |
213702c8 | 694 | ht_info->cur_bw_40mhz); |
94a79942 | 695 | |
ccdbe14b | 696 | ht_info->sw_bw_in_progress = true; |
94a79942 | 697 | |
35350898 | 698 | ht_set_connect_bw_mode_callback(ieee); |
94a79942 | 699 | } |