| Dmitry Shmidt | 391c59f | 2013-09-03 12:16:28 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * ACS - Automatic Channel Selection module | 
|  | 3 | * Copyright (c) 2011, Atheros Communications | 
|  | 4 | * Copyright (c) 2013, 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 "utils/includes.h" | 
|  | 11 | #include <math.h> | 
|  | 12 |  | 
|  | 13 | #include "utils/common.h" | 
|  | 14 | #include "utils/list.h" | 
|  | 15 | #include "common/ieee802_11_defs.h" | 
|  | 16 | #include "drivers/driver.h" | 
|  | 17 | #include "hostapd.h" | 
|  | 18 | #include "ap_drv_ops.h" | 
|  | 19 | #include "ap_config.h" | 
|  | 20 | #include "hw_features.h" | 
|  | 21 | #include "acs.h" | 
|  | 22 |  | 
|  | 23 | /* | 
|  | 24 | * Automatic Channel Selection | 
|  | 25 | * =========================== | 
|  | 26 | * | 
|  | 27 | * More info at | 
|  | 28 | * ------------ | 
|  | 29 | * http://wireless.kernel.org/en/users/Documentation/acs | 
|  | 30 | * | 
|  | 31 | * How to use | 
|  | 32 | * ---------- | 
|  | 33 | * - make sure you have CONFIG_ACS=y in hostapd's .config | 
|  | 34 | * - use channel=0 or channel=acs to enable ACS | 
|  | 35 | * | 
|  | 36 | * How does it work | 
|  | 37 | * ---------------- | 
|  | 38 | * 1. passive scans are used to collect survey data | 
|  | 39 | *    (it is assumed that scan trigger collection of survey data in driver) | 
|  | 40 | * 2. interference factor is calculated for each channel | 
|  | 41 | * 3. ideal channel is picked depending on channel width by using adjacent | 
|  | 42 | *    channel interference factors | 
|  | 43 | * | 
|  | 44 | * Known limitations | 
|  | 45 | * ----------------- | 
|  | 46 | * - Current implementation depends heavily on the amount of time willing to | 
|  | 47 | *   spend gathering survey data during hostapd startup. Short traffic bursts | 
|  | 48 | *   may be missed and a suboptimal channel may be picked. | 
|  | 49 | * - Ideal channel may end up overlapping a channel with 40 MHz intolerant BSS | 
|  | 50 | * | 
|  | 51 | * Todo / Ideas | 
|  | 52 | * ------------ | 
|  | 53 | * - implement other interference computation methods | 
|  | 54 | *   - BSS/RSSI based | 
|  | 55 | *   - spectral scan based | 
|  | 56 | *   (should be possibly to hook this up with current ACS scans) | 
|  | 57 | * - add wpa_supplicant support (for P2P) | 
|  | 58 | * - collect a histogram of interference over time allowing more educated | 
|  | 59 | *   guess about an ideal channel (perhaps CSA could be used to migrate AP to a | 
|  | 60 | *   new "better" channel while running) | 
|  | 61 | * - include neighboring BSS scan to avoid conflicts with 40 MHz intolerant BSSs | 
|  | 62 | *   when choosing the ideal channel | 
|  | 63 | * | 
|  | 64 | * Survey interference factor implementation details | 
|  | 65 | * ------------------------------------------------- | 
|  | 66 | * Generic interference_factor in struct hostapd_channel_data is used. | 
|  | 67 | * | 
|  | 68 | * The survey interference factor is defined as the ratio of the | 
|  | 69 | * observed busy time over the time we spent on the channel, | 
|  | 70 | * this value is then amplified by the observed noise floor on | 
|  | 71 | * the channel in comparison to the lowest noise floor observed | 
|  | 72 | * on the entire band. | 
|  | 73 | * | 
|  | 74 | * This corresponds to: | 
|  | 75 | * --- | 
|  | 76 | * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf) | 
|  | 77 | * --- | 
|  | 78 | * | 
|  | 79 | * The coefficient of 2 reflects the way power in "far-field" | 
|  | 80 | * radiation decreases as the square of distance from the antenna [1]. | 
|  | 81 | * What this does is it decreases the observed busy time ratio if the | 
|  | 82 | * noise observed was low but increases it if the noise was high, | 
|  | 83 | * proportionally to the way "far field" radiation changes over | 
|  | 84 | * distance. | 
|  | 85 | * | 
|  | 86 | * If channel busy time is not available the fallback is to use channel RX time. | 
|  | 87 | * | 
|  | 88 | * Since noise floor is in dBm it is necessary to convert it into Watts so that | 
|  | 89 | * combined channel interference (e.g., HT40, which uses two channels) can be | 
|  | 90 | * calculated easily. | 
|  | 91 | * --- | 
|  | 92 | * (busy time - tx time) / (active time - tx time) * | 
|  | 93 | *    2^(10^(chan_nf/10) + 10^(band_min_nf/10)) | 
|  | 94 | * --- | 
|  | 95 | * | 
|  | 96 | * However to account for cases where busy/rx time is 0 (channel load is then | 
|  | 97 | * 0%) channel noise floor signal power is combined into the equation so a | 
|  | 98 | * channel with lower noise floor is preferred. The equation becomes: | 
|  | 99 | * --- | 
|  | 100 | * 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) * | 
|  | 101 | *    2^(10^(chan_nf/10) + 10^(band_min_nf/10)) | 
|  | 102 | * --- | 
|  | 103 | * | 
|  | 104 | * All this "interference factor" is purely subjective and only time | 
|  | 105 | * will tell how usable this is. By using the minimum noise floor we | 
|  | 106 | * remove any possible issues due to card calibration. The computation | 
|  | 107 | * of the interference factor then is dependent on what the card itself | 
|  | 108 | * picks up as the minimum noise, not an actual real possible card | 
|  | 109 | * noise value. | 
|  | 110 | * | 
|  | 111 | * Total interference computation details | 
|  | 112 | * -------------------------------------- | 
|  | 113 | * The above channel interference factor is calculated with no respect to | 
|  | 114 | * target operational bandwidth. | 
|  | 115 | * | 
|  | 116 | * To find an ideal channel the above data is combined by taking into account | 
|  | 117 | * the target operational bandwidth and selected band. E.g., on 2.4 GHz channels | 
|  | 118 | * overlap with 20 MHz bandwidth, but there is no overlap for 20 MHz bandwidth | 
|  | 119 | * on 5 GHz. | 
|  | 120 | * | 
|  | 121 | * Each valid and possible channel spec (i.e., channel + width) is taken and its | 
|  | 122 | * interference factor is computed by summing up interferences of each channel | 
|  | 123 | * it overlaps. The one with least total interference is picked up. | 
|  | 124 | * | 
|  | 125 | * Note: This implies base channel interference factor must be non-negative | 
|  | 126 | * allowing easy summing up. | 
|  | 127 | * | 
|  | 128 | * Example ACS analysis printout | 
|  | 129 | * ----------------------------- | 
|  | 130 | * | 
|  | 131 | * ACS: Trying survey-based ACS | 
|  | 132 | * ACS: Survey analysis for channel 1 (2412 MHz) | 
|  | 133 | * ACS:  1: min_nf=-113 interference_factor=0.0802469 nf=-113 time=162 busy=0 rx=13 | 
|  | 134 | * ACS:  2: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12 | 
|  | 135 | * ACS:  3: min_nf=-113 interference_factor=0.0679012 nf=-113 time=162 busy=0 rx=11 | 
|  | 136 | * ACS:  4: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5 | 
|  | 137 | * ACS:  5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4 | 
|  | 138 | * ACS:  * interference factor average: 0.0557166 | 
|  | 139 | * ACS: Survey analysis for channel 2 (2417 MHz) | 
|  | 140 | * ACS:  1: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3 | 
|  | 141 | * ACS:  2: min_nf=-113 interference_factor=0.0246914 nf=-113 time=162 busy=0 rx=4 | 
|  | 142 | * ACS:  3: min_nf=-113 interference_factor=0.037037 nf=-113 time=162 busy=0 rx=6 | 
|  | 143 | * ACS:  4: min_nf=-113 interference_factor=0.149068 nf=-113 time=161 busy=0 rx=24 | 
|  | 144 | * ACS:  5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4 | 
|  | 145 | * ACS:  * interference factor average: 0.050832 | 
|  | 146 | * ACS: Survey analysis for channel 3 (2422 MHz) | 
|  | 147 | * ACS:  1: min_nf=-113 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 | 
|  | 148 | * ACS:  2: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3 | 
|  | 149 | * ACS:  3: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 | 
|  | 150 | * ACS:  4: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 | 
|  | 151 | * ACS:  5: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3 | 
|  | 152 | * ACS:  * interference factor average: 0.0148838 | 
|  | 153 | * ACS: Survey analysis for channel 4 (2427 MHz) | 
|  | 154 | * ACS:  1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 155 | * ACS:  2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9 | 
|  | 156 | * ACS:  3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 | 
|  | 157 | * ACS:  4: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3 | 
|  | 158 | * ACS:  5: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 | 
|  | 159 | * ACS:  * interference factor average: 0.0160801 | 
|  | 160 | * ACS: Survey analysis for channel 5 (2432 MHz) | 
|  | 161 | * ACS:  1: min_nf=-114 interference_factor=0.409938 nf=-113 time=161 busy=0 rx=66 | 
|  | 162 | * ACS:  2: min_nf=-114 interference_factor=0.0432099 nf=-113 time=162 busy=0 rx=7 | 
|  | 163 | * ACS:  3: min_nf=-114 interference_factor=0.0124224 nf=-113 time=161 busy=0 rx=2 | 
|  | 164 | * ACS:  4: min_nf=-114 interference_factor=0.677019 nf=-113 time=161 busy=0 rx=109 | 
|  | 165 | * ACS:  5: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3 | 
|  | 166 | * ACS:  * interference factor average: 0.232244 | 
|  | 167 | * ACS: Survey analysis for channel 6 (2437 MHz) | 
|  | 168 | * ACS:  1: min_nf=-113 interference_factor=0.552795 nf=-113 time=161 busy=0 rx=89 | 
|  | 169 | * ACS:  2: min_nf=-113 interference_factor=0.0807453 nf=-112 time=161 busy=0 rx=13 | 
|  | 170 | * ACS:  3: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5 | 
|  | 171 | * ACS:  4: min_nf=-113 interference_factor=0.434783 nf=-112 time=161 busy=0 rx=70 | 
|  | 172 | * ACS:  5: min_nf=-113 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10 | 
|  | 173 | * ACS:  * interference factor average: 0.232298 | 
|  | 174 | * ACS: Survey analysis for channel 7 (2442 MHz) | 
|  | 175 | * ACS:  1: min_nf=-113 interference_factor=0.440994 nf=-112 time=161 busy=0 rx=71 | 
|  | 176 | * ACS:  2: min_nf=-113 interference_factor=0.385093 nf=-113 time=161 busy=0 rx=62 | 
|  | 177 | * ACS:  3: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 | 
|  | 178 | * ACS:  4: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 | 
|  | 179 | * ACS:  5: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12 | 
|  | 180 | * ACS:  * interference factor average: 0.195031 | 
|  | 181 | * ACS: Survey analysis for channel 8 (2447 MHz) | 
|  | 182 | * ACS:  1: min_nf=-114 interference_factor=0.0496894 nf=-112 time=161 busy=0 rx=8 | 
|  | 183 | * ACS:  2: min_nf=-114 interference_factor=0.0496894 nf=-114 time=161 busy=0 rx=8 | 
|  | 184 | * ACS:  3: min_nf=-114 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6 | 
|  | 185 | * ACS:  4: min_nf=-114 interference_factor=0.12963 nf=-113 time=162 busy=0 rx=21 | 
|  | 186 | * ACS:  5: min_nf=-114 interference_factor=0.166667 nf=-114 time=162 busy=0 rx=27 | 
|  | 187 | * ACS:  * interference factor average: 0.0865885 | 
|  | 188 | * ACS: Survey analysis for channel 9 (2452 MHz) | 
|  | 189 | * ACS:  1: min_nf=-114 interference_factor=0.0124224 nf=-114 time=161 busy=0 rx=2 | 
|  | 190 | * ACS:  2: min_nf=-114 interference_factor=0.0310559 nf=-114 time=161 busy=0 rx=5 | 
|  | 191 | * ACS:  3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 | 
|  | 192 | * ACS:  4: min_nf=-114 interference_factor=0.00617284 nf=-114 time=162 busy=0 rx=1 | 
|  | 193 | * ACS:  5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 194 | * ACS:  * interference factor average: 0.00993022 | 
|  | 195 | * ACS: Survey analysis for channel 10 (2457 MHz) | 
|  | 196 | * ACS:  1: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 | 
|  | 197 | * ACS:  2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 | 
|  | 198 | * ACS:  3: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 | 
|  | 199 | * ACS:  4: min_nf=-114 interference_factor=0.0493827 nf=-114 time=162 busy=0 rx=8 | 
|  | 200 | * ACS:  5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 201 | * ACS:  * interference factor average: 0.0136033 | 
|  | 202 | * ACS: Survey analysis for channel 11 (2462 MHz) | 
|  | 203 | * ACS:  1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0 | 
|  | 204 | * ACS:  2: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0 | 
|  | 205 | * ACS:  3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0 | 
|  | 206 | * ACS:  4: min_nf=-114 interference_factor=0.0432099 nf=-114 time=162 busy=0 rx=7 | 
|  | 207 | * ACS:  5: min_nf=-114 interference_factor=0.0925926 nf=-114 time=162 busy=0 rx=15 | 
|  | 208 | * ACS:  * interference factor average: 0.0271605 | 
|  | 209 | * ACS: Survey analysis for channel 12 (2467 MHz) | 
|  | 210 | * ACS:  1: min_nf=-114 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10 | 
|  | 211 | * ACS:  2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1 | 
|  | 212 | * ACS:  3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 | 
|  | 213 | * ACS:  4: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0 | 
|  | 214 | * ACS:  5: min_nf=-114 interference_factor=0.00617284 nf=-113 time=162 busy=0 rx=1 | 
|  | 215 | * ACS:  * interference factor average: 0.0148992 | 
|  | 216 | * ACS: Survey analysis for channel 13 (2472 MHz) | 
|  | 217 | * ACS:  1: min_nf=-114 interference_factor=0.0745342 nf=-114 time=161 busy=0 rx=12 | 
|  | 218 | * ACS:  2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9 | 
|  | 219 | * ACS:  3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 220 | * ACS:  4: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 221 | * ACS:  5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0 | 
|  | 222 | * ACS:  * interference factor average: 0.0260179 | 
|  | 223 | * ACS: Survey analysis for selected bandwidth 20MHz | 
|  | 224 | * ACS:  * channel 1: total interference = 0.121432 | 
|  | 225 | * ACS:  * channel 2: total interference = 0.137512 | 
|  | 226 | * ACS:  * channel 3: total interference = 0.369757 | 
|  | 227 | * ACS:  * channel 4: total interference = 0.546338 | 
|  | 228 | * ACS:  * channel 5: total interference = 0.690538 | 
|  | 229 | * ACS:  * channel 6: total interference = 0.762242 | 
|  | 230 | * ACS:  * channel 7: total interference = 0.756092 | 
|  | 231 | * ACS:  * channel 8: total interference = 0.537451 | 
|  | 232 | * ACS:  * channel 9: total interference = 0.332313 | 
|  | 233 | * ACS:  * channel 10: total interference = 0.152182 | 
|  | 234 | * ACS:  * channel 11: total interference = 0.0916111 | 
|  | 235 | * ACS:  * channel 12: total interference = 0.0816809 | 
|  | 236 | * ACS:  * channel 13: total interference = 0.0680776 | 
|  | 237 | * ACS: Ideal channel is 13 (2472 MHz) with total interference factor of 0.0680776 | 
|  | 238 | * | 
|  | 239 | * [1] http://en.wikipedia.org/wiki/Near_and_far_field | 
|  | 240 | */ | 
|  | 241 |  | 
|  | 242 |  | 
|  | 243 | static int acs_request_scan(struct hostapd_iface *iface); | 
|  | 244 |  | 
|  | 245 |  | 
|  | 246 | static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) | 
|  | 247 | { | 
|  | 248 | struct freq_survey *survey, *tmp; | 
|  | 249 |  | 
|  | 250 | if (dl_list_empty(&chan->survey_list)) | 
|  | 251 | return; | 
|  | 252 |  | 
|  | 253 | dl_list_for_each_safe(survey, tmp, &chan->survey_list, | 
|  | 254 | struct freq_survey, list) { | 
|  | 255 | dl_list_del(&survey->list); | 
|  | 256 | os_free(survey); | 
|  | 257 | } | 
|  | 258 | } | 
|  | 259 |  | 
|  | 260 |  | 
|  | 261 | static void acs_cleanup(struct hostapd_iface *iface) | 
|  | 262 | { | 
|  | 263 | int i; | 
|  | 264 | struct hostapd_channel_data *chan; | 
|  | 265 |  | 
|  | 266 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 267 | chan = &iface->current_mode->channels[i]; | 
|  | 268 |  | 
|  | 269 | if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) | 
|  | 270 | acs_clean_chan_surveys(chan); | 
|  | 271 |  | 
|  | 272 | dl_list_init(&chan->survey_list); | 
|  | 273 | chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; | 
|  | 274 | chan->min_nf = 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | iface->chans_surveyed = 0; | 
|  | 278 | iface->acs_num_completed_scans = 0; | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 |  | 
|  | 282 | void acs_fail(struct hostapd_iface *iface) | 
|  | 283 | { | 
|  | 284 | wpa_printf(MSG_ERROR, "ACS: Failed to start"); | 
|  | 285 | acs_cleanup(iface); | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 |  | 
|  | 289 | static long double | 
|  | 290 | acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf) | 
|  | 291 | { | 
|  | 292 | long double factor, busy, total; | 
|  | 293 |  | 
|  | 294 | if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) | 
|  | 295 | busy = survey->channel_time_busy; | 
|  | 296 | else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX) | 
|  | 297 | busy = survey->channel_time_rx; | 
|  | 298 | else { | 
|  | 299 | /* This shouldn't really happen as survey data is checked in | 
|  | 300 | * acs_sanity_check() */ | 
|  | 301 | wpa_printf(MSG_ERROR, "ACS: Survey data missing"); | 
|  | 302 | return 0; | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | total = survey->channel_time; | 
|  | 306 |  | 
|  | 307 | if (survey->filled & SURVEY_HAS_CHAN_TIME_TX) { | 
|  | 308 | busy -= survey->channel_time_tx; | 
|  | 309 | total -= survey->channel_time_tx; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | /* TODO: figure out the best multiplier for noise floor base */ | 
|  | 313 | factor = pow(10, survey->nf / 5.0L) + | 
|  | 314 | (busy / total) * | 
|  | 315 | pow(2, pow(10, (long double) survey->nf / 10.0L) - | 
|  | 316 | pow(10, (long double) min_nf / 10.0L)); | 
|  | 317 |  | 
|  | 318 | return factor; | 
|  | 319 | } | 
|  | 320 |  | 
|  | 321 |  | 
|  | 322 | static void | 
|  | 323 | acs_survey_chan_interference_factor(struct hostapd_iface *iface, | 
|  | 324 | struct hostapd_channel_data *chan) | 
|  | 325 | { | 
|  | 326 | struct freq_survey *survey; | 
|  | 327 | unsigned int i = 0; | 
|  | 328 | long double int_factor = 0; | 
|  | 329 |  | 
|  | 330 | if (dl_list_empty(&chan->survey_list)) | 
|  | 331 | return; | 
|  | 332 |  | 
|  | 333 | if (chan->flag & HOSTAPD_CHAN_DISABLED) | 
|  | 334 | return; | 
|  | 335 |  | 
|  | 336 | chan->interference_factor = 0; | 
|  | 337 |  | 
|  | 338 | dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list) | 
|  | 339 | { | 
|  | 340 | int_factor = acs_survey_interference_factor(survey, | 
|  | 341 | iface->lowest_nf); | 
|  | 342 | chan->interference_factor += int_factor; | 
|  | 343 | wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu", | 
|  | 344 | ++i, chan->min_nf, int_factor, | 
|  | 345 | survey->nf, (unsigned long) survey->channel_time, | 
|  | 346 | (unsigned long) survey->channel_time_busy, | 
|  | 347 | (unsigned long) survey->channel_time_rx); | 
|  | 348 | } | 
|  | 349 |  | 
|  | 350 | chan->interference_factor = chan->interference_factor / | 
|  | 351 | dl_list_len(&chan->survey_list); | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 |  | 
|  | 355 | static int acs_usable_chan(struct hostapd_channel_data *chan) | 
|  | 356 | { | 
|  | 357 | if (dl_list_empty(&chan->survey_list)) | 
|  | 358 | return 0; | 
|  | 359 | if (chan->flag & HOSTAPD_CHAN_DISABLED) | 
|  | 360 | return 0; | 
|  | 361 | return 1; | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 |  | 
|  | 365 | static int acs_usable_ht40_chan(struct hostapd_channel_data *chan) | 
|  | 366 | { | 
|  | 367 | const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, | 
|  | 368 | 157, 184, 192 }; | 
|  | 369 | unsigned int i; | 
|  | 370 |  | 
|  | 371 | for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++) | 
|  | 372 | if (chan->chan == allowed[i]) | 
|  | 373 | return 1; | 
|  | 374 |  | 
|  | 375 | return 0; | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 |  | 
|  | 379 | static int acs_survey_is_sufficient(struct freq_survey *survey) | 
|  | 380 | { | 
|  | 381 | if (!(survey->filled & SURVEY_HAS_NF)) { | 
|  | 382 | wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor"); | 
|  | 383 | return 0; | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) { | 
|  | 387 | wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time"); | 
|  | 388 | return 0; | 
|  | 389 | } | 
|  | 390 |  | 
|  | 391 | if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) && | 
|  | 392 | !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) { | 
|  | 393 | wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)"); | 
|  | 394 | return 0; | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | return 1; | 
|  | 398 | } | 
|  | 399 |  | 
|  | 400 |  | 
|  | 401 | static int acs_surveys_are_sufficient(struct hostapd_iface *iface) | 
|  | 402 | { | 
|  | 403 | int i; | 
|  | 404 | struct hostapd_channel_data *chan; | 
|  | 405 | struct freq_survey *survey; | 
|  | 406 |  | 
|  | 407 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 408 | chan = &iface->current_mode->channels[i]; | 
|  | 409 | if (chan->flag & HOSTAPD_CHAN_DISABLED) | 
|  | 410 | continue; | 
|  | 411 |  | 
|  | 412 | dl_list_for_each(survey, &chan->survey_list, | 
|  | 413 | struct freq_survey, list) | 
|  | 414 | { | 
|  | 415 | if (!acs_survey_is_sufficient(survey)) { | 
|  | 416 | wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data", | 
|  | 417 | chan->chan); | 
|  | 418 | return 0; | 
|  | 419 | } | 
|  | 420 | } | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | return 1; | 
|  | 424 | } | 
|  | 425 |  | 
|  | 426 |  | 
|  | 427 | static void acs_survey_all_chans_intereference_factor( | 
|  | 428 | struct hostapd_iface *iface) | 
|  | 429 | { | 
|  | 430 | int i; | 
|  | 431 | struct hostapd_channel_data *chan; | 
|  | 432 |  | 
|  | 433 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 434 | chan = &iface->current_mode->channels[i]; | 
|  | 435 |  | 
|  | 436 | if (!acs_usable_chan(chan)) | 
|  | 437 | continue; | 
|  | 438 |  | 
|  | 439 | wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", | 
|  | 440 | chan->chan, chan->freq); | 
|  | 441 |  | 
|  | 442 | acs_survey_chan_interference_factor(iface, chan); | 
|  | 443 |  | 
|  | 444 | wpa_printf(MSG_DEBUG, "ACS:  * interference factor average: %Lg", | 
|  | 445 | chan->interference_factor); | 
|  | 446 | } | 
|  | 447 | } | 
|  | 448 |  | 
|  | 449 |  | 
|  | 450 | static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, | 
|  | 451 | int freq) | 
|  | 452 | { | 
|  | 453 | struct hostapd_channel_data *chan; | 
|  | 454 | int i; | 
|  | 455 |  | 
|  | 456 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 457 | chan = &iface->current_mode->channels[i]; | 
|  | 458 |  | 
|  | 459 | if (!acs_usable_chan(chan)) | 
|  | 460 | continue; | 
|  | 461 |  | 
|  | 462 | if (chan->freq == freq) | 
|  | 463 | return chan; | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | return NULL; | 
|  | 467 | } | 
|  | 468 |  | 
|  | 469 |  | 
|  | 470 | /* | 
|  | 471 | * At this point it's assumed chan->interface_factor has been computed. | 
|  | 472 | * This function should be reusable regardless of interference computation | 
|  | 473 | * option (survey, BSS, spectral, ...). chan->interference factor must be | 
|  | 474 | * summable (i.e., must be always greater than zero). | 
|  | 475 | */ | 
|  | 476 | static struct hostapd_channel_data * | 
|  | 477 | acs_find_ideal_chan(struct hostapd_iface *iface) | 
|  | 478 | { | 
|  | 479 | struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL; | 
|  | 480 | long double factor, ideal_factor = 0; | 
|  | 481 | int i, j; | 
|  | 482 | int n_chans = 1; | 
|  | 483 |  | 
|  | 484 | /* TODO: HT40- support */ | 
|  | 485 |  | 
|  | 486 | if (iface->conf->ieee80211n && | 
|  | 487 | iface->conf->secondary_channel == -1) { | 
|  | 488 | wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); | 
|  | 489 | return NULL; | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | if (iface->conf->ieee80211n && | 
|  | 493 | iface->conf->secondary_channel) | 
|  | 494 | n_chans = 2; | 
|  | 495 |  | 
|  | 496 | if (iface->conf->ieee80211ac && | 
|  | 497 | iface->conf->vht_oper_chwidth == 1) | 
|  | 498 | n_chans = 4; | 
|  | 499 |  | 
|  | 500 | /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */ | 
|  | 501 |  | 
|  | 502 | wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz", | 
|  | 503 | n_chans == 1 ? 20 : | 
|  | 504 | n_chans == 2 ? 40 : | 
|  | 505 | n_chans == 4 ? 80 : | 
|  | 506 | -1); | 
|  | 507 |  | 
|  | 508 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 509 | chan = &iface->current_mode->channels[i]; | 
|  | 510 |  | 
|  | 511 | if (!acs_usable_chan(chan)) | 
|  | 512 | continue; | 
|  | 513 |  | 
|  | 514 | /* HT40 on 5 GHz has a limited set of primary channels as per | 
|  | 515 | * 11n Annex J */ | 
|  | 516 | if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && | 
|  | 517 | iface->conf->ieee80211n && | 
|  | 518 | iface->conf->secondary_channel && | 
|  | 519 | !acs_usable_ht40_chan(chan)) { | 
|  | 520 | wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40", | 
|  | 521 | chan->chan); | 
|  | 522 | continue; | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | factor = chan->interference_factor; | 
|  | 526 |  | 
|  | 527 | for (j = 1; j < n_chans; j++) { | 
|  | 528 | adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); | 
|  | 529 | if (!adj_chan) | 
|  | 530 | break; | 
|  | 531 |  | 
|  | 532 | factor += adj_chan->interference_factor; | 
|  | 533 | } | 
|  | 534 |  | 
|  | 535 | if (j != n_chans) { | 
|  | 536 | wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", | 
|  | 537 | chan->chan); | 
|  | 538 | continue; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent | 
|  | 542 | * channel interference factor. */ | 
|  | 543 | if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || | 
|  | 544 | iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) { | 
|  | 545 | for (j = 0; j < n_chans; j++) { | 
|  | 546 | /* TODO: perhaps a multiplier should be used | 
|  | 547 | * here? */ | 
|  | 548 |  | 
|  | 549 | adj_chan = acs_find_chan(iface, chan->freq + | 
|  | 550 | (j * 20) - 5); | 
|  | 551 | if (adj_chan) | 
|  | 552 | factor += adj_chan->interference_factor; | 
|  | 553 |  | 
|  | 554 | adj_chan = acs_find_chan(iface, chan->freq + | 
|  | 555 | (j * 20) - 10); | 
|  | 556 | if (adj_chan) | 
|  | 557 | factor += adj_chan->interference_factor; | 
|  | 558 |  | 
|  | 559 | adj_chan = acs_find_chan(iface, chan->freq + | 
|  | 560 | (j * 20) + 5); | 
|  | 561 | if (adj_chan) | 
|  | 562 | factor += adj_chan->interference_factor; | 
|  | 563 |  | 
|  | 564 | adj_chan = acs_find_chan(iface, chan->freq + | 
|  | 565 | (j * 20) + 10); | 
|  | 566 | if (adj_chan) | 
|  | 567 | factor += adj_chan->interference_factor; | 
|  | 568 | } | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg", | 
|  | 572 | chan->chan, factor); | 
|  | 573 |  | 
|  | 574 | if (!ideal_chan || factor < ideal_factor) { | 
|  | 575 | ideal_factor = factor; | 
|  | 576 | ideal_chan = chan; | 
|  | 577 | } | 
|  | 578 | } | 
|  | 579 |  | 
|  | 580 | if (ideal_chan) | 
|  | 581 | wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", | 
|  | 582 | ideal_chan->chan, ideal_chan->freq, ideal_factor); | 
|  | 583 |  | 
|  | 584 | return ideal_chan; | 
|  | 585 | } | 
|  | 586 |  | 
|  | 587 |  | 
|  | 588 | static void acs_adjust_vht_center_freq(struct hostapd_iface *iface) | 
|  | 589 | { | 
|  | 590 | wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency"); | 
|  | 591 |  | 
|  | 592 | switch (iface->conf->vht_oper_chwidth) { | 
|  | 593 | case VHT_CHANWIDTH_USE_HT: | 
|  | 594 | iface->conf->vht_oper_centr_freq_seg0_idx = | 
|  | 595 | iface->conf->channel + 2; | 
|  | 596 | break; | 
|  | 597 | case VHT_CHANWIDTH_80MHZ: | 
|  | 598 | iface->conf->vht_oper_centr_freq_seg0_idx = | 
|  | 599 | iface->conf->channel + 6; | 
|  | 600 | break; | 
|  | 601 | default: | 
|  | 602 | /* TODO: How can this be calculated? Adjust | 
|  | 603 | * acs_find_ideal_chan() */ | 
|  | 604 | wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now"); | 
|  | 605 | break; | 
|  | 606 | } | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 |  | 
|  | 610 | static int acs_study_survey_based(struct hostapd_iface *iface) | 
|  | 611 | { | 
|  | 612 | wpa_printf(MSG_DEBUG, "ACS: Trying survey-based ACS"); | 
|  | 613 |  | 
|  | 614 | if (!iface->chans_surveyed) { | 
|  | 615 | wpa_printf(MSG_ERROR, "ACS: Unable to collect survey data"); | 
|  | 616 | return -1; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | if (!acs_surveys_are_sufficient(iface)) { | 
|  | 620 | wpa_printf(MSG_ERROR, "ACS: Surveys have insufficient data"); | 
|  | 621 | return -1; | 
|  | 622 | } | 
|  | 623 |  | 
|  | 624 | acs_survey_all_chans_intereference_factor(iface); | 
|  | 625 | return 0; | 
|  | 626 | } | 
|  | 627 |  | 
|  | 628 |  | 
|  | 629 | static int acs_study_options(struct hostapd_iface *iface) | 
|  | 630 | { | 
|  | 631 | int err; | 
|  | 632 |  | 
|  | 633 | err = acs_study_survey_based(iface); | 
|  | 634 | if (err == 0) | 
|  | 635 | return 0; | 
|  | 636 |  | 
|  | 637 | /* TODO: If no surveys are available/sufficient this is a good | 
|  | 638 | * place to fallback to BSS-based ACS */ | 
|  | 639 |  | 
|  | 640 | return -1; | 
|  | 641 | } | 
|  | 642 |  | 
|  | 643 |  | 
|  | 644 | static void acs_study(struct hostapd_iface *iface) | 
|  | 645 | { | 
|  | 646 | struct hostapd_channel_data *ideal_chan; | 
|  | 647 | int err; | 
|  | 648 |  | 
|  | 649 | err = acs_study_options(iface); | 
|  | 650 | if (err < 0) { | 
|  | 651 | wpa_printf(MSG_ERROR, "ACS: All study options have failed"); | 
|  | 652 | goto fail; | 
|  | 653 | } | 
|  | 654 |  | 
|  | 655 | ideal_chan = acs_find_ideal_chan(iface); | 
|  | 656 | if (!ideal_chan) { | 
|  | 657 | wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel"); | 
|  | 658 | goto fail; | 
|  | 659 | } | 
|  | 660 |  | 
|  | 661 | iface->conf->channel = ideal_chan->chan; | 
|  | 662 |  | 
|  | 663 | if (iface->conf->ieee80211ac) | 
|  | 664 | acs_adjust_vht_center_freq(iface); | 
|  | 665 |  | 
|  | 666 | /* | 
|  | 667 | * hostapd_setup_interface_complete() will return -1 on failure, | 
|  | 668 | * 0 on success and 0 is HOSTAPD_CHAN_VALID :) | 
|  | 669 | */ | 
|  | 670 | switch (hostapd_acs_completed(iface)) { | 
|  | 671 | case HOSTAPD_CHAN_VALID: | 
|  | 672 | acs_cleanup(iface); | 
|  | 673 | return; | 
|  | 674 | case HOSTAPD_CHAN_INVALID: | 
|  | 675 | case HOSTAPD_CHAN_ACS: | 
|  | 676 | default: | 
|  | 677 | /* This can possibly happen if channel parameters (secondary | 
|  | 678 | * channel, center frequencies) are misconfigured */ | 
|  | 679 | wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file."); | 
|  | 680 | goto fail; | 
|  | 681 | } | 
|  | 682 |  | 
|  | 683 | fail: | 
|  | 684 | acs_fail(iface); | 
|  | 685 | } | 
|  | 686 |  | 
|  | 687 |  | 
|  | 688 | static void acs_scan_complete(struct hostapd_iface *iface) | 
|  | 689 | { | 
|  | 690 | int err; | 
|  | 691 |  | 
|  | 692 | iface->scan_cb = NULL; | 
|  | 693 |  | 
|  | 694 | wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)", | 
|  | 695 | iface->conf->acs_num_scans); | 
|  | 696 |  | 
|  | 697 | err = hostapd_drv_get_survey(iface->bss[0], 0); | 
|  | 698 | if (err) { | 
|  | 699 | wpa_printf(MSG_ERROR, "ACS: Failed to get survey data"); | 
|  | 700 | acs_fail(iface); | 
|  | 701 | } | 
|  | 702 |  | 
|  | 703 | if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) { | 
|  | 704 | err = acs_request_scan(iface); | 
|  | 705 | if (err) { | 
|  | 706 | wpa_printf(MSG_ERROR, "ACS: Failed to request scan"); | 
|  | 707 | acs_fail(iface); | 
|  | 708 | return; | 
|  | 709 | } | 
|  | 710 |  | 
|  | 711 | return; | 
|  | 712 | } | 
|  | 713 |  | 
|  | 714 | acs_study(iface); | 
|  | 715 | } | 
|  | 716 |  | 
|  | 717 |  | 
|  | 718 | static int acs_request_scan(struct hostapd_iface *iface) | 
|  | 719 | { | 
|  | 720 | struct wpa_driver_scan_params params; | 
|  | 721 | struct hostapd_channel_data *chan; | 
|  | 722 | int i, *freq; | 
|  | 723 |  | 
|  | 724 | os_memset(¶ms, 0, sizeof(params)); | 
|  | 725 | params.freqs = os_calloc(iface->current_mode->num_channels + 1, | 
|  | 726 | sizeof(params.freqs[0])); | 
|  | 727 | if (params.freqs == NULL) | 
|  | 728 | return -1; | 
|  | 729 |  | 
|  | 730 | freq = params.freqs; | 
|  | 731 | for (i = 0; i < iface->current_mode->num_channels; i++) { | 
|  | 732 | chan = &iface->current_mode->channels[i]; | 
|  | 733 | if (chan->flag & HOSTAPD_CHAN_DISABLED) | 
|  | 734 | continue; | 
|  | 735 |  | 
|  | 736 | *freq++ = chan->freq; | 
|  | 737 | } | 
|  | 738 | *freq = 0; | 
|  | 739 |  | 
|  | 740 | iface->scan_cb = acs_scan_complete; | 
|  | 741 |  | 
|  | 742 | wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", | 
|  | 743 | iface->acs_num_completed_scans + 1, | 
|  | 744 | iface->conf->acs_num_scans); | 
|  | 745 |  | 
|  | 746 | if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { | 
|  | 747 | wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan"); | 
|  | 748 | acs_cleanup(iface); | 
|  | 749 | return -1; | 
|  | 750 | } | 
|  | 751 |  | 
|  | 752 | os_free(params.freqs); | 
|  | 753 | return 0; | 
|  | 754 | } | 
|  | 755 |  | 
|  | 756 |  | 
|  | 757 | enum hostapd_chan_status acs_init(struct hostapd_iface *iface) | 
|  | 758 | { | 
|  | 759 | int err; | 
|  | 760 |  | 
|  | 761 | wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit"); | 
|  | 762 |  | 
|  | 763 | acs_cleanup(iface); | 
|  | 764 |  | 
|  | 765 | err = acs_request_scan(iface); | 
|  | 766 | if (err < 0) | 
|  | 767 | return HOSTAPD_CHAN_INVALID; | 
|  | 768 |  | 
|  | 769 | return HOSTAPD_CHAN_ACS; | 
|  | 770 | } |