18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - background scan and roaming module: learn 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "list.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "drivers/driver.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config_ssid.h" 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver_i.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "scan.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "bgscan.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct bgscan_learn_bss { 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dl_list list; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 bssid[ETH_ALEN]; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int freq; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *neigh; /* num_neigh * ETH_ALEN buffer */ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_neigh; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct bgscan_learn_data { 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_supplicant *wpa_s; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpa_ssid *ssid; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int scan_interval; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int signal_threshold; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int short_interval; /* use if signal < threshold */ 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int long_interval; /* use if signal > threshold */ 37fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct os_reltime last_bgscan; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *fname; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dl_list bss; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *supp_freqs; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int probe_idx; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bss_free(struct bgscan_learn_bss *bss) 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(bss->neigh); 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(bss); 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid) 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (array == NULL || array_len == 0) 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < array_len; i++) { 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0) 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss, 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *bssid) 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *n; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bssid_in_array(bss->neigh, bss->num_neigh, bssid)) 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN); 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (n == NULL) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN); 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss->neigh = n; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss->num_neigh++; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct bgscan_learn_bss * bgscan_learn_get_bss( 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data, const u8 *bssid) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return bss; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bgscan_learn_load(struct bgscan_learn_data *data) 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt FILE *f; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[128]; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->fname == NULL) 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt f = fopen(data->fname, "r"); 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (f == NULL) 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s", 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fname); 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fgets(buf, sizeof(buf), f) == NULL || 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) { 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s", 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fname); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fclose(f); 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (fgets(buf, sizeof(buf), f)) { 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strncmp(buf, "BSS ", 4) == 0) { 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss = os_zalloc(sizeof(*bss)); 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!bss) 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hwaddr_aton(buf + 4, bss->bssid) < 0) { 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss_free(bss); 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss->freq = atoi(buf + 4 + 18); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_add(&data->bss, &bss->list); 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS " 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "entry: " MACSTR " freq=%d", 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq); 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) { 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 addr[ETH_ALEN]; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hwaddr_aton(buf + 9, addr) < 0) 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss = bgscan_learn_get_bss(data, addr); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss == NULL) 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hwaddr_aton(buf + 9 + 18, addr) < 0) 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bgscan_learn_add_neighbor(bss, addr); 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fclose(f); 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_save(struct bgscan_learn_data *data) 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt FILE *f; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->fname == NULL) 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s", 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fname); 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt f = fopen(data->fname, "w"); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (f == NULL) 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fprintf(f, "wpa_supplicant-bgscan-learn\n"); 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fprintf(f, "BSS " MACSTR " %d\n", 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq); 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < bss->num_neigh; i++) { 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n", 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->neigh + i * ETH_ALEN)); 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fclose(f); 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int in_array(int *array, int val) 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (array == NULL) 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; array[i]; i++) { 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (array[i] == val) 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int * bgscan_learn_get_freqs(struct bgscan_learn_data *data, 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *count) 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *freqs = NULL, *n; 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *count = 0; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (in_array(freqs, bss->freq)) 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 22261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt n = os_realloc_array(freqs, *count + 2, sizeof(int)); 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (n == NULL) 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs = n; 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[*count] = bss->freq; 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (*count)++; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[*count] = 0; 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *freqs, size_t count) 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int idx, *n; 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->supp_freqs == NULL) 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 243fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt idx = data->probe_idx; 244fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt do { 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!in_array(freqs, data->supp_freqs[idx])) { 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq " 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%u", data->supp_freqs[idx]); 248fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt data->probe_idx = idx + 1; 249fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (data->supp_freqs[data->probe_idx] == 0) 250fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt data->probe_idx = 0; 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt n = os_realloc_array(freqs, count + 2, sizeof(int)); 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (n == NULL) 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs = n; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[count] = data->supp_freqs[idx]; 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[count] = 0; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt idx++; 262fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (data->supp_freqs[idx] == 0) 263fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt idx = 0; 264fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } while (idx != data->probe_idx); 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx) 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data = eloop_ctx; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_supplicant *wpa_s = data->wpa_s; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *freqs = NULL; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t count, i; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char msg[100], *pos; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt params.num_ssids = 1; 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt params.ssids[0].ssid = data->ssid->ssid; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt params.ssids[0].ssid_len = data->ssid->ssid_len; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->ssid->scan_freq) 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt params.freqs = data->ssid->scan_freq; 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else { 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs = bgscan_learn_get_freqs(data, &count); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have " 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "been seen on %u channels", (unsigned int) count); 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs = bgscan_learn_get_probe_freq(data, freqs, count); 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg[0] = '\0'; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = msg; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; freqs && freqs[i]; i++) { 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d", 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[i]); 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= msg + sizeof(msg) - pos) 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos[0] = '\0'; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s", 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg); 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt params.freqs = freqs; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan"); 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan"); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(data->scan_interval, 0, 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bgscan_learn_timeout, data, NULL); 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 313fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_get_reltime(&data->last_bgscan); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(freqs); 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bgscan_learn_get_params(struct bgscan_learn_data *data, 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *params) 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *pos; 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (params == NULL) 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->short_interval = atoi(params); 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = os_strchr(params, ':'); 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->signal_threshold = atoi(pos); 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = os_strchr(pos, ':'); 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) { 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval " 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for high signal"); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->long_interval = atoi(pos); 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = os_strchr(pos, ':'); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos) { 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fname = os_strdup(pos); 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s) 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, j, *freqs = NULL, *n; 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t count = 0; 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt modes = wpa_s->hw.modes; 3581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (modes == NULL) 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < wpa_s->hw.num_modes; i++) { 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < modes[i].num_channels; j++) { 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED) 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 365fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* some hw modes (e.g. 11b & 11g) contain same freqs */ 366fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (in_array(freqs, modes[i].channels[j].freq)) 367fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt continue; 36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt n = os_realloc_array(freqs, count + 2, sizeof(int)); 3691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (n == NULL) 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs = n; 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[count] = modes[i].channels[j].freq; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt count++; 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freqs[count] = 0; 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return freqs; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * bgscan_learn_init(struct wpa_supplicant *wpa_s, 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *params, 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpa_ssid *ssid) 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_init(&data->bss); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->wpa_s = wpa_s; 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ssid = ssid; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bgscan_learn_get_params(data, params) < 0) { 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->fname); 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->short_interval <= 0) 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->short_interval = 30; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->long_interval <= 0) 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->long_interval = 30; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bgscan_learn_load(data) < 0) { 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->fname); 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d " 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Short bgscan interval %d Long bgscan interval %d", 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->signal_threshold, data->short_interval, 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->long_interval); 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->signal_threshold && 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable " 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "signal strength monitoring"); 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->scan_interval = data->short_interval; 424fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (data->signal_threshold) { 425fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* Poll for signal info to set initial scan interval */ 426fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct wpa_signal_info siginfo; 427fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && 428fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt siginfo.current_signal >= data->signal_threshold) 429fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt data->scan_interval = data->long_interval; 430fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } 431fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data, NULL); 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called immediately after an association, so it is 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * reasonable to assume that a scan was completed recently. This makes 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * us skip an immediate new scan in cases where the current signal 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * level is below the bgscan threshold. 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 441fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_get_reltime(&data->last_bgscan); 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_deinit(void *priv) 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data = priv; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss, *n; 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bgscan_learn_save(data); 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->signal_threshold) 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_drv_signal_monitor(data->wpa_s, 0, 0); 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->fname); 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_for_each_safe(bss, n, &data->bss, struct bgscan_learn_bss, 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt list) { 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_del(&bss->list); 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss_free(bss); 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->supp_freqs); 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bgscan_learn_bss_match(struct bgscan_learn_data *data, 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss) 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *ie; 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ie == NULL) 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->ssid->ssid_len != ie[1] || 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0) 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* SSID mismatch */ 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bgscan_learn_notify_scan(void *priv, 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data = priv; 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i, j; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_BSS 50 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 bssid[MAX_BSS * ETH_ALEN]; 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_bssid = 0; 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification"); 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data, NULL); 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *res = scan_res->res[i]; 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!bgscan_learn_bss_match(data, res)) 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (num_bssid < MAX_BSS) { 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(bssid + num_bssid * ETH_ALEN, res->bssid, 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ETH_ALEN); 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_bssid++; 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: %u matching BSSes in scan " 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "results", (unsigned int) num_bssid); 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *res = scan_res->res[i]; 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_bss *bss; 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!bgscan_learn_bss_match(data, res)) 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss = bgscan_learn_get_bss(data, res->bssid); 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss && bss->freq != res->freq) { 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Update BSS " 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MACSTR " freq %d -> %d", 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(res->bssid), bss->freq, res->freq); 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss->freq = res->freq; 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (!bss) { 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Add BSS " MACSTR 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d", MAC2STR(res->bssid), res->freq); 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss = os_zalloc(sizeof(*bss)); 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!bss) 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(bss->bssid, res->bssid, ETH_ALEN); 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bss->freq = res->freq; 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_add(&data->bss, &bss->list); 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < num_bssid; j++) { 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *addr = bssid + j * ETH_ALEN; 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bgscan_learn_add_neighbor(bss, addr); 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * A more advanced bgscan could process scan results internally, select 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the BSS and request roam if needed. This sample uses the existing 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * BSS/ESS selection routine. Change this to return 1 if selection is 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * done inside the bgscan module. 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_notify_beacon_loss(void *priv) 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss"); 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: speed up background scanning */ 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void bgscan_learn_notify_signal_change(void *priv, int above, 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int current_signal, 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int current_noise, 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int current_txrate) 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct bgscan_learn_data *data = priv; 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int scan = 0; 568fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt struct os_reltime now; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->short_interval == data->long_interval || 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->signal_threshold == 0) 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed " 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(above=%d current_signal=%d current_noise=%d " 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "current_txrate=%d)", above, current_signal, 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt current_noise, current_txrate); 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->scan_interval == data->long_interval && !above) { 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan " 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "interval"); 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->scan_interval = data->short_interval; 582fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_get_reltime(&now); 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (now.sec > data->last_bgscan.sec + 1) 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan = 1; 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (data->scan_interval == data->short_interval && above) { 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan " 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "interval"); 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->scan_interval = data->long_interval; 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(data->scan_interval, 0, 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bgscan_learn_timeout, data, NULL); 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (!above) { 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Signal dropped further 4 dB. Request a new scan if we have 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * not yet scanned in a while. 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 597fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_get_reltime(&now); 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (now.sec > data->last_bgscan.sec + 10) 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan = 1; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan) { 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan"); 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(0, 0, bgscan_learn_timeout, data, NULL); 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct bgscan_ops bgscan_learn_ops = { 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .name = "learn", 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .init = bgscan_learn_init, 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .deinit = bgscan_learn_deinit, 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .notify_scan = bgscan_learn_notify_scan, 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .notify_beacon_loss = bgscan_learn_notify_beacon_loss, 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt .notify_signal_change = bgscan_learn_notify_signal_change, 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 618