1 /* 2 * Common hostapd/wpa_supplicant HW features 3 * Copyright (c) 2002-2013, Jouni Malinen <j (at) 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, 140, 92 149, 157, 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 oper = (struct ieee80211_ht_operation *) elems.ht_operation; 157 *pri_chan = oper->primary_chan; 158 if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { 159 int sec = oper->ht_param & 160 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 161 if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 162 *sec_chan = *pri_chan + 4; 163 else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 164 *sec_chan = *pri_chan - 4; 165 } 166 } 167 } 168 169 170 int check_40mhz_5g(struct hostapd_hw_modes *mode, 171 struct wpa_scan_results *scan_res, int pri_chan, 172 int sec_chan) 173 { 174 int pri_freq, sec_freq, pri_bss, sec_bss; 175 int bss_pri_chan, bss_sec_chan; 176 size_t i; 177 int match; 178 179 if (!mode || !scan_res || !pri_chan || !sec_chan || 180 pri_chan == sec_chan) 181 return 0; 182 183 pri_freq = hw_get_freq(mode, pri_chan); 184 sec_freq = hw_get_freq(mode, sec_chan); 185 186 /* 187 * Switch PRI/SEC channels if Beacons were detected on selected SEC 188 * channel, but not on selected PRI channel. 189 */ 190 pri_bss = sec_bss = 0; 191 for (i = 0; i < scan_res->num; i++) { 192 struct wpa_scan_res *bss = scan_res->res[i]; 193 if (bss->freq == pri_freq) 194 pri_bss++; 195 else if (bss->freq == sec_freq) 196 sec_bss++; 197 } 198 if (sec_bss && !pri_bss) { 199 wpa_printf(MSG_INFO, 200 "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes"); 201 return 2; 202 } 203 204 /* 205 * Match PRI/SEC channel with any existing HT40 BSS on the same 206 * channels that we are about to use (if already mixed order in 207 * existing BSSes, use own preference). 208 */ 209 match = 0; 210 for (i = 0; i < scan_res->num; i++) { 211 struct wpa_scan_res *bss = scan_res->res[i]; 212 get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 213 if (pri_chan == bss_pri_chan && 214 sec_chan == bss_sec_chan) { 215 match = 1; 216 break; 217 } 218 } 219 if (!match) { 220 for (i = 0; i < scan_res->num; i++) { 221 struct wpa_scan_res *bss = scan_res->res[i]; 222 get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 223 if (pri_chan == bss_sec_chan && 224 sec_chan == bss_pri_chan) { 225 wpa_printf(MSG_INFO, "Switch own primary and " 226 "secondary channel due to BSS " 227 "overlap with " MACSTR, 228 MAC2STR(bss->bssid)); 229 return 2; 230 } 231 } 232 } 233 234 return 1; 235 } 236 237 238 static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, 239 int end) 240 { 241 struct ieee802_11_elems elems; 242 struct ieee80211_ht_operation *oper; 243 244 if (bss->freq < start || bss->freq > end || bss->freq == pri_freq) 245 return 0; 246 247 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 248 if (!elems.ht_capabilities) { 249 wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: " 250 MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 251 return 1; 252 } 253 254 if (elems.ht_operation) { 255 oper = (struct ieee80211_ht_operation *) elems.ht_operation; 256 if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK) 257 return 0; 258 259 wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: " 260 MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 261 return 1; 262 } 263 return 0; 264 } 265 266 267 int check_40mhz_2g4(struct hostapd_hw_modes *mode, 268 struct wpa_scan_results *scan_res, int pri_chan, 269 int sec_chan) 270 { 271 int pri_freq, sec_freq; 272 int affected_start, affected_end; 273 size_t i; 274 275 if (!mode || !scan_res || !pri_chan || !sec_chan) 276 return 0; 277 278 if (pri_chan == sec_chan) 279 return 0; 280 281 pri_freq = hw_get_freq(mode, pri_chan); 282 sec_freq = hw_get_freq(mode, sec_chan); 283 284 affected_start = (pri_freq + sec_freq) / 2 - 25; 285 affected_end = (pri_freq + sec_freq) / 2 + 25; 286 wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 287 affected_start, affected_end); 288 for (i = 0; i < scan_res->num; i++) { 289 struct wpa_scan_res *bss = scan_res->res[i]; 290 int pri = bss->freq; 291 int sec = pri; 292 struct ieee802_11_elems elems; 293 294 /* Check for overlapping 20 MHz BSS */ 295 if (check_20mhz_bss(bss, pri_freq, affected_start, 296 affected_end)) { 297 wpa_printf(MSG_DEBUG, 298 "Overlapping 20 MHz BSS is found"); 299 return 0; 300 } 301 302 get_pri_sec_chan(bss, &pri_chan, &sec_chan); 303 304 if (sec_chan) { 305 if (sec_chan < pri_chan) 306 sec = pri - 20; 307 else 308 sec = pri + 20; 309 } 310 311 if ((pri < affected_start || pri > affected_end) && 312 (sec < affected_start || sec > affected_end)) 313 continue; /* not within affected channel range */ 314 315 wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 316 " freq=%d pri=%d sec=%d", 317 MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 318 319 if (sec_chan) { 320 if (pri_freq != pri || sec_freq != sec) { 321 wpa_printf(MSG_DEBUG, 322 "40 MHz pri/sec mismatch with BSS " 323 MACSTR 324 " <%d,%d> (chan=%d%c) vs. <%d,%d>", 325 MAC2STR(bss->bssid), 326 pri, sec, pri_chan, 327 sec > pri ? '+' : '-', 328 pri_freq, sec_freq); 329 return 0; 330 } 331 } 332 333 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 334 0); 335 if (elems.ht_capabilities) { 336 struct ieee80211_ht_capabilities *ht_cap = 337 (struct ieee80211_ht_capabilities *) 338 elems.ht_capabilities; 339 340 if (le_to_host16(ht_cap->ht_capabilities_info) & 341 HT_CAP_INFO_40MHZ_INTOLERANT) { 342 wpa_printf(MSG_DEBUG, 343 "40 MHz Intolerant is set on channel %d in BSS " 344 MACSTR, pri, MAC2STR(bss->bssid)); 345 return 0; 346 } 347 } 348 } 349 350 return 1; 351 } 352 353 354 int hostapd_set_freq_params(struct hostapd_freq_params *data, 355 enum hostapd_hw_mode mode, 356 int freq, int channel, int ht_enabled, 357 int vht_enabled, int sec_channel_offset, 358 int vht_oper_chwidth, int center_segment0, 359 int center_segment1, u32 vht_caps) 360 { 361 os_memset(data, 0, sizeof(*data)); 362 data->mode = mode; 363 data->freq = freq; 364 data->channel = channel; 365 data->ht_enabled = ht_enabled; 366 data->vht_enabled = vht_enabled; 367 data->sec_channel_offset = sec_channel_offset; 368 data->center_freq1 = freq + sec_channel_offset * 10; 369 data->center_freq2 = 0; 370 data->bandwidth = sec_channel_offset ? 40 : 20; 371 372 if (data->vht_enabled) switch (vht_oper_chwidth) { 373 case VHT_CHANWIDTH_USE_HT: 374 if (center_segment1 || 375 (center_segment0 != 0 && 376 5000 + center_segment0 * 5 != data->center_freq1 && 377 2407 + center_segment0 * 5 != data->center_freq1)) 378 return -1; 379 break; 380 case VHT_CHANWIDTH_80P80MHZ: 381 if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { 382 wpa_printf(MSG_ERROR, 383 "80+80 channel width is not supported!"); 384 return -1; 385 } 386 if (center_segment1 == center_segment0 + 4 || 387 center_segment1 == center_segment0 - 4) 388 return -1; 389 data->center_freq2 = 5000 + center_segment1 * 5; 390 /* fall through */ 391 case VHT_CHANWIDTH_80MHZ: 392 data->bandwidth = 80; 393 if ((vht_oper_chwidth == 1 && center_segment1) || 394 (vht_oper_chwidth == 3 && !center_segment1) || 395 !sec_channel_offset) 396 return -1; 397 if (!center_segment0) { 398 if (channel <= 48) 399 center_segment0 = 42; 400 else if (channel <= 64) 401 center_segment0 = 58; 402 else if (channel <= 112) 403 center_segment0 = 106; 404 else if (channel <= 128) 405 center_segment0 = 122; 406 else if (channel <= 144) 407 center_segment0 = 138; 408 else if (channel <= 161) 409 center_segment0 = 155; 410 data->center_freq1 = 5000 + center_segment0 * 5; 411 } else { 412 /* 413 * Note: HT/VHT config and params are coupled. Check if 414 * HT40 channel band is in VHT80 Pri channel band 415 * configuration. 416 */ 417 if (center_segment0 == channel + 6 || 418 center_segment0 == channel + 2 || 419 center_segment0 == channel - 2 || 420 center_segment0 == channel - 6) 421 data->center_freq1 = 5000 + center_segment0 * 5; 422 else 423 return -1; 424 } 425 break; 426 case VHT_CHANWIDTH_160MHZ: 427 data->bandwidth = 160; 428 if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | 429 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { 430 wpa_printf(MSG_ERROR, 431 "160MHZ channel width is not supported!"); 432 return -1; 433 } 434 if (center_segment1) 435 return -1; 436 if (!sec_channel_offset) 437 return -1; 438 /* 439 * Note: HT/VHT config and params are coupled. Check if 440 * HT40 channel band is in VHT160 channel band configuration. 441 */ 442 if (center_segment0 == channel + 14 || 443 center_segment0 == channel + 10 || 444 center_segment0 == channel + 6 || 445 center_segment0 == channel + 2 || 446 center_segment0 == channel - 2 || 447 center_segment0 == channel - 6 || 448 center_segment0 == channel - 10 || 449 center_segment0 == channel - 14) 450 data->center_freq1 = 5000 + center_segment0 * 5; 451 else 452 return -1; 453 break; 454 } 455 456 return 0; 457 } 458