Parcourir la source

bgscan learn: Probe one new channel at a time to find APs

This allows APs to be found from channels that have not previously
been observed to contain APs for this ESS.
Jouni Malinen il y a 14 ans
Parent
commit
2e2a8d073d
1 fichiers modifiés avec 87 ajouts et 5 suppressions
  1. 87 5
      wpa_supplicant/bgscan_learn.c

+ 87 - 5
wpa_supplicant/bgscan_learn.c

@@ -41,6 +41,8 @@ struct bgscan_learn_data {
 	struct os_time last_bgscan;
 	char *fname;
 	struct dl_list bss;
+	int *supp_freqs;
+	int probe_idx;
 };
 
 
@@ -168,13 +170,47 @@ static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
 }
 
 
+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 + 1;
+	while (idx != data->probe_idx) {
+		if (data->supp_freqs[idx] == 0)
+			idx = 0;
+		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;
+			n = os_realloc(freqs, (count + 2) * sizeof(int));
+			if (n == NULL)
+				return freqs;
+			freqs = n;
+			freqs[count] = data->supp_freqs[idx];
+			count++;
+			freqs[count] = 0;
+			break;
+		}
+
+		idx++;
+	}
+
+	return freqs;
+}
+
+
 static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct bgscan_learn_data *data = eloop_ctx;
 	struct wpa_supplicant *wpa_s = data->wpa_s;
 	struct wpa_driver_scan_params params;
 	int *freqs = NULL;
-	size_t count;
+	size_t count, i;
+	char msg[100], *pos;
 
 	os_memset(&params, 0, sizeof(params));
 	params.num_ssids = 1;
@@ -186,10 +222,21 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
 		freqs = bgscan_learn_get_freqs(data, &count);
 		wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have "
 			   "been seen on %u channels", (unsigned int) count);
-		/*
-		 * TODO: add other frequencies (rotate through one or couple at
-		 * a time, etc., to find APs from new channels)
-		 */
+		freqs = bgscan_learn_get_probe_freq(data, freqs, count);
+
+		msg[0] = '\0';
+		pos = msg;
+		for (i = 0; freqs && freqs[i]; i++) {
+			int ret;
+			ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
+					  freqs[i]);
+			if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+				break;
+			pos += ret;
+		}
+		pos[0] = '\0';
+		wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s",
+			   msg);
 		params.freqs = freqs;
 	}
 
@@ -237,6 +284,39 @@ static int bgscan_learn_get_params(struct bgscan_learn_data *data,
 }
 
 
+static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_hw_modes *modes;
+	u16 num_modes, flags;
+	int i, j, *freqs = NULL, *n;
+	size_t count = 0;
+
+	modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
+	if (!modes)
+		return NULL;
+
+	for (i = 0; i < num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			n = os_realloc(freqs, (count + 2) * sizeof(int));
+			if (!n)
+				continue;
+
+			freqs = n;
+			freqs[count] = modes[i].channels[j].freq;
+			count++;
+			freqs[count] = 0;
+		}
+		os_free(modes[i].channels);
+		os_free(modes[i].rates);
+	}
+	os_free(modes);
+
+	return freqs;
+}
+
+
 static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
 				const char *params,
 				const struct wpa_ssid *ssid)
@@ -276,6 +356,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
 			   "signal strength monitoring");
 	}
 
+	data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
 	data->scan_interval = data->short_interval;
 	eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
 			       data, NULL);
@@ -298,6 +379,7 @@ static void bgscan_learn_deinit(void *priv)
 		dl_list_del(&bss->list);
 		os_free(bss);
 	}
+	os_free(data->supp_freqs);
 	os_free(data);
 }