+static void bss_free(struct bgscan_learn_bss *bss)
+{
+ os_free(bss->neigh);
+ os_free(bss);
+}
+
+
+static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid)
+{
+ size_t i;
+
+ if (array == NULL || array_len == 0)
+ return 0;
+
+ for (i = 0; i < array_len; i++) {
+ if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
+ const u8 *bssid)
+{
+ u8 *n;
+
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+ return;
+ if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
+ return;
+
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
+ if (n == NULL)
+ return;
+
+ os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN);
+ bss->neigh = n;
+ bss->num_neigh++;
+}
+
+
+static struct bgscan_learn_bss * bgscan_learn_get_bss(
+ struct bgscan_learn_data *data, const u8 *bssid)
+{
+ struct bgscan_learn_bss *bss;
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+ return bss;
+ }
+ return NULL;
+}
+
+
+static int bgscan_learn_load(struct bgscan_learn_data *data)
+{
+ FILE *f;
+ char buf[128];
+ struct bgscan_learn_bss *bss;
+
+ if (data->fname == NULL)
+ return 0;
+
+ f = fopen(data->fname, "r");
+ if (f == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s",
+ data->fname);
+
+ if (fgets(buf, sizeof(buf), f) == NULL ||
+ os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) {
+ wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s",
+ data->fname);
+ fclose(f);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ if (os_strncmp(buf, "BSS ", 4) == 0) {
+ bss = os_zalloc(sizeof(*bss));
+ if (!bss)
+ continue;
+ if (hwaddr_aton(buf + 4, bss->bssid) < 0) {
+ bss_free(bss);
+ continue;
+ }
+ bss->freq = atoi(buf + 4 + 18);
+ dl_list_add(&data->bss, &bss->list);
+ wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS "
+ "entry: " MACSTR " freq=%d",
+ MAC2STR(bss->bssid), bss->freq);
+ }
+
+ if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) {
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(buf + 9, addr) < 0)
+ continue;
+ bss = bgscan_learn_get_bss(data, addr);
+ if (bss == NULL)
+ continue;
+ if (hwaddr_aton(buf + 9 + 18, addr) < 0)
+ continue;
+
+ bgscan_learn_add_neighbor(bss, addr);
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
+
+
+static void bgscan_learn_save(struct bgscan_learn_data *data)
+{
+ FILE *f;
+ struct bgscan_learn_bss *bss;
+
+ if (data->fname == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s",
+ data->fname);
+
+ f = fopen(data->fname, "w");
+ if (f == NULL)
+ return;
+ fprintf(f, "wpa_supplicant-bgscan-learn\n");
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ fprintf(f, "BSS " MACSTR " %d\n",
+ MAC2STR(bss->bssid), bss->freq);
+ }
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ size_t i;
+ for (i = 0; i < bss->num_neigh; i++) {
+ fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n",
+ MAC2STR(bss->bssid),
+ MAC2STR(bss->neigh + i * ETH_ALEN));
+ }
+ }
+
+ fclose(f);
+}
+
+
+static int in_array(int *array, int val)
+{
+ int i;
+
+ if (array == NULL)
+ return 0;
+
+ for (i = 0; array[i]; i++) {
+ if (array[i] == val)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
+ size_t *count)
+{
+ struct bgscan_learn_bss *bss;
+ int *freqs = NULL, *n;
+
+ *count = 0;
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ if (in_array(freqs, bss->freq))
+ continue;
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
+ if (n == NULL)
+ return freqs;
+ freqs = n;
+ freqs[*count] = bss->freq;
+ (*count)++;
+ freqs[*count] = 0;
+ }
+
+ return freqs;
+}
+
+
+static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
+ int *freqs, size_t count)
+{
+ int idx, *n;
+
+ if (data->supp_freqs == NULL)
+ return freqs;
+
+ idx = data->probe_idx;
+ do {
+ if (!in_array(freqs, data->supp_freqs[idx])) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
+ "%u", data->supp_freqs[idx]);
+ data->probe_idx = idx + 1;
+ if (data->supp_freqs[data->probe_idx] == 0)
+ data->probe_idx = 0;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
+ if (n == NULL)
+ return freqs;
+ freqs = n;
+ freqs[count] = data->supp_freqs[idx];
+ count++;
+ freqs[count] = 0;
+ break;
+ }
+
+ idx++;
+ if (data->supp_freqs[idx] == 0)
+ idx = 0;
+ } while (idx != data->probe_idx);
+
+ return freqs;
+}
+
+