1 /* 2 * Common hostapd/wpa_supplicant HW features 3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4 * Copyright (c) 2015, Qualcomm Atheros, Inc. 5 * 6 * This software may be distributed under the terms of the BSD license. 7 * See README for more details. 8 */ 9 10 #include "includes.h" 11 12 #include "common.h" 13 #include "defs.h" 14 #include "ieee802_11_defs.h" 15 #include "ieee802_11_common.h" 16 #include "hw_features_common.h" 17 18 19 struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode, 20 int chan, int *freq) 21 { 22 int i; 23 24 if (freq) 25 *freq = 0; 26 27 if (!mode) 28 return NULL; 29 30 for (i = 0; i < mode->num_channels; i++) { 31 struct hostapd_channel_data *ch = &mode->channels[i]; 32 if (ch->chan == chan) { 33 if (freq) 34 *freq = ch->freq; 35 return ch; 36 } 37 } 38 39 return NULL; 40 } 41 42 43 struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode, 44 int freq, int *chan) 45 { 46 int i; 47 48 if (chan) 49 *chan = 0; 50 51 if (!mode) 52 return NULL; 53 54 for (i = 0; i < mode->num_channels; i++) { 55 struct hostapd_channel_data *ch = &mode->channels[i]; 56 if (ch->freq == freq) { 57 if (chan) 58 *chan = ch->chan; 59 return ch; 60 } 61 } 62 63 return NULL; 64 } 65 66 67 int hw_get_freq(struct hostapd_hw_modes *mode, int chan) 68 { 69 int freq; 70 71 hw_get_channel_chan(mode, chan, &freq); 72 73 return freq; 74 } 75 76 77 int hw_get_chan(struct hostapd_hw_modes *mode, int freq) 78 { 79 int chan; 80 81 hw_get_channel_freq(mode, freq, &chan); 82 83 return chan; 84 } 85 86 87 int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan, 88 int sec_chan) 89 { 90 int ok, j, first; 91 int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 92 184, 192 }; 93 size_t k; 94 95 if (pri_chan == sec_chan || !sec_chan) 96 return 1; /* HT40 not used */ 97 98 wpa_printf(MSG_DEBUG, 99 "HT40: control channel: %d secondary channel: %d", 100 pri_chan, sec_chan); 101 102 /* Verify that HT40 secondary channel is an allowed 20 MHz 103 * channel */ 104 ok = 0; 105 for (j = 0; j < mode->num_channels; j++) { 106 struct hostapd_channel_data *chan = &mode->channels[j]; 107 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 108 chan->chan == sec_chan) { 109 ok = 1; 110 break; 111 } 112 } 113 if (!ok) { 114 wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 115 sec_chan); 116 return 0; 117 } 118 119 /* 120 * Verify that HT40 primary,secondary channel pair is allowed per 121 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 122 * 2.4 GHz rules allow all cases where the secondary channel fits into 123 * the list of allowed channels (already checked above). 124 */ 125 if (mode->mode != HOSTAPD_MODE_IEEE80211A) 126 return 1; 127 128 first = pri_chan < sec_chan ? pri_chan : sec_chan; 129 130 ok = 0; 131 for (k = 0; k < ARRAY_SIZE(allowed); k++) { 132 if (first == allowed[k]) { 133 ok = 1; 134 break; 135 } 136 } 137 if (!ok) { 138 wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 139 pri_chan, sec_chan); 140 return 0; 141 } 142 143 return 1; 144 } 145 146 147 void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan) 148 { 149 struct ieee80211_ht_operation *oper; 150 struct ieee802_11_elems elems; 151 152 *pri_chan = *sec_chan = 0; 153 154 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 155 if (elems.ht_operation && 156 elems.ht_operation_len >= sizeof(*oper)) { 157 oper = (struct ieee80211_ht_operation *) elems.ht_operation; 158 *pri_chan = oper->primary_chan; 159 if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { 160 int sec = oper->ht_param & 161 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 162 if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 163 *sec_chan = *pri_chan + 4; 164 else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 165 *sec_chan = *pri_chan - 4; 166 } 167 } 168 } 169 170 171 int check_40mhz_5g(struct hostapd_hw_modes *mode, 172 struct wpa_scan_results *scan_res, int pri_chan, 173 int sec_chan) 174 { 175 int pri_freq, sec_freq, pri_bss, sec_bss; 176 int bss_pri_chan, bss_sec_chan; 177 size_t i; 178 int match; 179 180 if (!mode || !scan_res || !pri_chan || !sec_chan) 181 return 0; 182 183 if (pri_chan == sec_chan) 184 return 0; 185 186 pri_freq = hw_get_freq(mode, pri_chan); 187 sec_freq = hw_get_freq(mode, sec_chan); 188 189 /* 190 * Switch PRI/SEC channels if Beacons were detected on selected SEC 191 * channel, but not on selected PRI channel. 192 */ 193 pri_bss = sec_bss = 0; 194 for (i = 0; i < scan_res->num; i++) { 195 struct wpa_scan_res *bss = scan_res->res[i]; 196 if (bss->freq == pri_freq) 197 pri_bss++; 198 else if (bss->freq == sec_freq) 199 sec_bss++; 200 } 201 if (sec_bss && !pri_bss) { 202 wpa_printf(MSG_INFO, 203 "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes"); 204 return 2; 205 } 206 207 /* 208 * Match PRI/SEC channel with any existing HT40 BSS on the same 209 * channels that we are about to use (if already mixed order in 210 * existing BSSes, use own preference). 211 */ 212 match = 0; 213 for (i = 0; i < scan_res->num; i++) { 214 struct wpa_scan_res *bss = scan_res->res[i]; 215 get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 216 if (pri_chan == bss_pri_chan && 217 sec_chan == bss_sec_chan) { 218 match = 1; 219 break; 220 } 221 } 222 if (!match) { 223 for (i = 0; i < scan_res->num; i++) { 224 struct wpa_scan_res *bss = scan_res->res[i]; 225 get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 226 if (pri_chan == bss_sec_chan && 227 sec_chan == bss_pri_chan) { 228 wpa_printf(MSG_INFO, "Switch own primary and " 229 "secondary channel due to BSS " 230 "overlap with " MACSTR, 231 MAC2STR(bss->bssid)); 232 return 2; 233 } 234 } 235 } 236 237 return 1; 238 } 239 240 241 int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end) 242 { 243 struct ieee802_11_elems elems; 244 struct ieee80211_ht_operation *oper; 245 246 if (bss->freq < start || bss->freq > end || bss->freq == pri_freq) 247 return 0; 248 249 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 250 if (!elems.ht_capabilities) { 251 wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: " 252 MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 253 return 1; 254 } 255 256 if (elems.ht_operation && 257 elems.ht_operation_len >= sizeof(*oper)) { 258 oper = (struct ieee80211_ht_operation *) elems.ht_operation; 259 if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK) 260 return 0; 261 262 wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: " 263 MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 264 return 1; 265 } 266 return 0; 267 } 268 269 270 int check_40mhz_2g4(struct hostapd_hw_modes *mode, 271 struct wpa_scan_results *scan_res, int pri_chan, 272 int sec_chan) 273 { 274 int pri_freq, sec_freq; 275 int affected_start, affected_end; 276 size_t i; 277 278 if (!mode || !scan_res || !pri_chan || !sec_chan) 279 return 0; 280 281 if (pri_chan == sec_chan) 282 return 0; 283 284 pri_freq = hw_get_freq(mode, pri_chan); 285 sec_freq = hw_get_freq(mode, sec_chan); 286 287 affected_start = (pri_freq + sec_freq) / 2 - 25; 288 affected_end = (pri_freq + sec_freq) / 2 + 25; 289 wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 290 affected_start, affected_end); 291 for (i = 0; i < scan_res->num; i++) { 292 struct wpa_scan_res *bss = scan_res->res[i]; 293 int pri = bss->freq; 294 int sec = pri; 295 struct ieee802_11_elems elems; 296 297 /* Check for overlapping 20 MHz BSS */ 298 if (check_20mhz_bss(bss, pri_freq, affected_start, 299 affected_end)) { 300 wpa_printf(MSG_DEBUG, 301 "Overlapping 20 MHz BSS is found"); 302 return 0; 303 } 304 305 get_pri_sec_chan(bss, &pri_chan, &sec_chan); 306 307 if (sec_chan) { 308 if (sec_chan < pri_chan) 309 sec = pri - 20; 310 else 311 sec = pri + 20; 312 } 313 314 if ((pri < affected_start || pri > affected_end) && 315 (sec < affected_start || sec > affected_end)) 316 continue; /* not within affected channel range */ 317 318 wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 319 " freq=%d pri=%d sec=%d", 320 MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 321 322 if (sec_chan) { 323 if (pri_freq != pri || sec_freq != sec) { 324 wpa_printf(MSG_DEBUG, 325 "40 MHz pri/sec mismatch with BSS " 326 MACSTR 327 " <%d,%d> (chan=%d%c) vs. <%d,%d>", 328 MAC2STR(bss->bssid), 329 pri, sec, pri_chan, 330 sec > pri ? '+' : '-', 331 pri_freq, sec_freq); 332 return 0; 333 } 334 } 335 336 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 337 0); 338 if (elems.ht_capabilities && 339 elems.ht_capabilities_len >= 340 sizeof(struct ieee80211_ht_capabilities)) { 341 struct ieee80211_ht_capabilities *ht_cap = 342 (struct ieee80211_ht_capabilities *) 343 elems.ht_capabilities; 344 345 if (le_to_host16(ht_cap->ht_capabilities_info) & 346 HT_CAP_INFO_40MHZ_INTOLERANT) { 347 wpa_printf(MSG_DEBUG, 348 "40 MHz Intolerant is set on channel %d in BSS " 349 MACSTR, pri, MAC2STR(bss->bssid)); 350 return 0; 351 } 352 } 353 } 354 355 return 1; 356 } 357 358 359 int hostapd_set_freq_params(struct hostapd_freq_params *data, 360 enum hostapd_hw_mode mode, 361 int freq, int channel, int ht_enabled, 362 int vht_enabled, int sec_channel_offset, 363 int vht_oper_chwidth, int center_segment0, 364 int center_segment1, u32 vht_caps) 365 { 366 int tmp; 367 368 os_memset(data, 0, sizeof(*data)); 369 data->mode = mode; 370 data->freq = freq; 371 data->channel = channel; 372 data->ht_enabled = ht_enabled; 373 data->vht_enabled = vht_enabled; 374 data->sec_channel_offset = sec_channel_offset; 375 data->center_freq1 = freq + sec_channel_offset * 10; 376 data->center_freq2 = 0; 377 data->bandwidth = sec_channel_offset ? 40 : 20; 378 379 if (data->vht_enabled) switch (vht_oper_chwidth) { 380 case VHT_CHANWIDTH_USE_HT: 381 if (center_segment1) 382 return -1; 383 if (center_segment0 != 0 && 384 5000 + center_segment0 * 5 != data->center_freq1 && 385 2407 + center_segment0 * 5 != data->center_freq1) 386 return -1; 387 break; 388 case VHT_CHANWIDTH_80P80MHZ: 389 if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { 390 wpa_printf(MSG_ERROR, 391 "80+80 channel width is not supported!"); 392 return -1; 393 } 394 if (center_segment1 == center_segment0 + 4 || 395 center_segment1 == center_segment0 - 4) 396 return -1; 397 data->center_freq2 = 5000 + center_segment1 * 5; 398 /* fall through */ 399 case VHT_CHANWIDTH_80MHZ: 400 data->bandwidth = 80; 401 if (vht_oper_chwidth == 1 && center_segment1) 402 return -1; 403 if (vht_oper_chwidth == 3 && !center_segment1) 404 return -1; 405 if (!sec_channel_offset) 406 return -1; 407 /* primary 40 part must match the HT configuration */ 408 tmp = (30 + freq - 5000 - center_segment0 * 5) / 20; 409 tmp /= 2; 410 if (data->center_freq1 != 5000 + 411 center_segment0 * 5 - 20 + 40 * tmp) 412 return -1; 413 data->center_freq1 = 5000 + center_segment0 * 5; 414 break; 415 case VHT_CHANWIDTH_160MHZ: 416 data->bandwidth = 160; 417 if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | 418 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { 419 wpa_printf(MSG_ERROR, 420 "160MHZ channel width is not supported!"); 421 return -1; 422 } 423 if (center_segment1) 424 return -1; 425 if (!sec_channel_offset) 426 return -1; 427 /* primary 40 part must match the HT configuration */ 428 tmp = (70 + freq - 5000 - center_segment0 * 5) / 20; 429 tmp /= 2; 430 if (data->center_freq1 != 5000 + 431 center_segment0 * 5 - 60 + 40 * tmp) 432 return -1; 433 data->center_freq1 = 5000 + center_segment0 * 5; 434 break; 435 } 436 437 return 0; 438 } 439