Add option to ignore Probe Request frames on 2.4 GHz from dualband STA

The new no_probe_resp_if_seen_on=<ifname> parameter can now be used to
configure hostapd to not reply to group-addressed Probe Request from a
station that was seen on another radio.

This can be used with enabled track_sta_max_num configuration on another
interface controlled by the same hostapd process to restrict Probe
Request frame handling from replying to group-addressed Probe Request
frames from a station that has been detected to be capable of operating
on another band, e.g., to try to reduce likelihood of the station
selecting a 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz
BSS concurrently.

Note: Enabling this can cause connectivity issues and increase latency
for discovering the AP.

Signed-off-by: Jouni Malinen <j@w1.fi>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 336eba9..57ccbc6 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3403,6 +3403,9 @@
 		conf->track_sta_max_num = atoi(pos);
 	} else if (os_strcmp(buf, "track_sta_max_age") == 0) {
 		conf->track_sta_max_age = atoi(pos);
+	} else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
+		os_free(bss->no_probe_resp_if_seen_on);
+		bss->no_probe_resp_if_seen_on = os_strdup(pos);
 	} else {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index d912197..43e81ca 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1289,6 +1289,21 @@
 # Default: 180
 #track_sta_max_age=180
 
+# Do not reply to group-addressed Probe Request from a station that was seen on
+# another radio.
+# Default: Disabled
+#
+# This can be used with enabled track_sta_max_num configuration on another
+# interface controlled by the same hostapd process to restrict Probe Request
+# frame handling from replying to group-addressed Probe Request frames from a
+# station that has been detected to be capable of operating on another band,
+# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when
+# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
+#
+# Note: Enabling this can cause connectivity issues and increase latency for
+# discovering the AP.
+#no_probe_resp_if_seen_on=wlan1
+
 ##### Wi-Fi Protected Setup (WPS) #############################################
 
 # WPS state
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index be2fa8b..96f8651 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -566,6 +566,8 @@
 	wpabuf_free(conf->own_ie_override);
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	os_free(conf->no_probe_resp_if_seen_on);
+
 	os_free(conf);
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 3434214..d821f27 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -554,6 +554,8 @@
 	int radio_measurements;
 
 	int vendor_vht;
+
+	char *no_probe_resp_if_seen_on;
 };
 
 
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 46fff82..651ee74 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -622,6 +622,29 @@
 }
 
 
+static int sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
+			     const char *ifname)
+{
+	struct hapd_interfaces *interfaces = iface->interfaces;
+	size_t i, j;
+
+	for (i = 0; i < interfaces->count; i++) {
+		iface = interfaces->iface[i];
+		for (j = 0; j < iface->num_bss; j++) {
+			struct hostapd_data *hapd = iface->bss[j];
+
+			if (os_strcmp(ifname, hapd->conf->iface) == 0)
+				break;
+		}
+
+		if (j < iface->num_bss && sta_track_get(iface, addr))
+			return 1;
+	}
+
+	return 0;
+}
+
+
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len,
 		      int ssi_signal)
@@ -787,6 +810,18 @@
 	/* TODO: verify that supp_rates contains at least one matching rate
 	 * with AP configuration */
 
+	if (hapd->conf->no_probe_resp_if_seen_on &&
+	    is_multicast_ether_addr(mgmt->da) &&
+	    is_multicast_ether_addr(mgmt->bssid) &&
+	    sta_track_seen_on(hapd->iface, mgmt->sa,
+			      hapd->conf->no_probe_resp_if_seen_on)) {
+		wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+			   " since STA has been seen on %s",
+			   hapd->conf->iface, MAC2STR(mgmt->sa),
+			   hapd->conf->no_probe_resp_if_seen_on);
+		return;
+	}
+
 #ifdef CONFIG_TESTING_OPTIONS
 	if (hapd->iconf->ignore_probe_probability > 0.0 &&
 	    drand48() < hapd->iconf->ignore_probe_probability) {