diff mbox

[v2,4/4] implement secondary SSID capability

Message ID 20150426134336.GK26331@zirkel.wertarbyte.de
State Deferred
Headers show

Commit Message

Stefan Tomanek April 26, 2015, 1:43 p.m. UTC
This change enables the definition of secondary SSID strings attached to the
same BSS; clients actively requesting those will be able to associate with the
BSS using the alternative names.

Config example:

interface=wlan1
ssid=Path-e-tec
secondary_ssid=Path-Way
secondary_ssid=E-Tec
hw_mode=g
channel=1

So even after the (fictional) companies Path-Way and E-Tec completed their
merger and renamed their networks, legacy devices can still connect to the old
network names (as long as they employ active scanning, since currently no
beacons are generated for the secondary SSIDs).

Signed-off-by: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
---
 hostapd/config_file.c | 18 ++++++++++++++++++
 hostapd/hostapd.conf  |  8 ++++++++
 src/ap/ap_config.h    | 14 ++++++++++++++
 src/ap/beacon.c       | 46 ++++++++++++++++++++++++++++++++++++++++++----
 src/ap/ieee802_11.c   | 22 +++++++++++++++++++---
 5 files changed, 101 insertions(+), 7 deletions(-)
diff mbox

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 09f51c1..0927b4b 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1994,6 +1994,24 @@  static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "utf8_ssid") == 0) {
 		bss->ssid.utf8_ssid = atoi(pos) > 0;
 #ifdef CONFIG_MULTI_SSID
+	} else if (os_strcmp(buf, "secondary_ssid") == 0) {
+		struct hostapd_ssid_str *sec;
+		if (bss->secondary_ssid_count >= MAX_BSS_SECONDARY_SSID_COUNT) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: count of secondary ssids exceeded",
+				   line);
+			return 1;
+		}
+		sec = &bss->secondary_ssid[bss->secondary_ssid_count];
+		sec->ssid_len = os_strlen(pos);
+		if (sec->ssid_len > SSID_MAX_LEN ||
+		    sec->ssid_len < 1) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+				   line, pos);
+			return 1;
+		}
+		os_memcpy(sec->ssid, pos, sec->ssid_len);
+		bss->secondary_ssid_count++;
 	} else if (os_strcmp(buf, "catchall") == 0) {
 		bss->ssid.catchall = atoi(pos) > 0;
 #endif /* CONFIG_MULTI_SSID */
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 10542e2..9fee5c1 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -93,6 +93,14 @@  ssid=test
 # UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
 #utf8_ssid=1
 
+# Secondary SSID strings that are acceptable as well. No beacons will be
+# transmitted using these names; clients actively requesting them will be
+# associated and subjected to the same configuration as the ones using the
+# primary SSID. Up to 8 secondary SSIDs might be defined for each BSS.
+#secondary_ssid=foo
+#secondary_ssid=bar
+#secondary_ssid=baz
+
 # Accept any requested SSID for association with this BSS
 #catchall=1
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index dd99a85..0e9e895 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -77,6 +77,11 @@  typedef enum hostap_security_policy {
 	SECURITY_OSEN = 5
 } secpolicy;
 
+struct hostapd_ssid_str {
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+};
+
 struct hostapd_ssid {
 	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
@@ -216,6 +221,10 @@  struct hostapd_nai_realm_data {
 	} eap_method[MAX_NAI_EAP_METHODS];
 };
 
+#ifdef CONFIG_MULTI_SSID
+#define MAX_BSS_SECONDARY_SSID_COUNT 8
+#endif /* CONFIG_MULTI_SSID */
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
@@ -259,6 +268,11 @@  struct hostapd_bss_config {
 
 	struct hostapd_ssid ssid;
 
+#ifdef CONFIG_MULTI_SSID
+	int secondary_ssid_count;
+	struct hostapd_ssid_str secondary_ssid[MAX_BSS_SECONDARY_SSID_COUNT];
+#endif /* CONFIG_MULTI_SSID */
+
 	char *eap_req_id_text; /* optional displayable message sent with
 				* EAP Request-Identity */
 	size_t eap_req_id_text_len;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 24af671..399a111 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -505,6 +505,7 @@  enum ssid_match_result {
 	NO_SSID_MATCH,
 	EXACT_SSID_MATCH,
 #ifdef CONFIG_MULTI_SSID
+	SECONDARY_SSID_MATCH,
 	CATCHALL_SSID_MATCH,
 #endif /* CONFIG_MULTI_SSID */
 	WILDCARD_SSID_MATCH
@@ -515,6 +516,9 @@  static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 					 const u8 *ssid_list,
 					 size_t ssid_list_len)
 {
+#ifdef CONFIG_MULTI_SSID
+	size_t i;
+#endif /* CONFIG_MULTI_SSID */
 	const u8 *pos, *end;
 	int wildcard = 0;
 
@@ -524,6 +528,15 @@  static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 	    os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
 		return EXACT_SSID_MATCH;
 
+#ifdef CONFIG_MULTI_SSID
+	for (i = 0; i < hapd->conf->secondary_ssid_count; i++) {
+		struct hostapd_ssid_str *s = &hapd->conf->secondary_ssid[i];
+		if (ssid_len == s->ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			return SECONDARY_SSID_MATCH;
+	}
+#endif /* CONFIG_MULTI_SSID */
+
 	if (ssid_list == NULL)
 		return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
 
@@ -537,6 +550,15 @@  static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 		if (pos[1] == hapd->conf->ssid.ssid_len &&
 		    os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
 			return EXACT_SSID_MATCH;
+#ifdef CONFIG_MULTI_SSID
+		for (i = 0; i < hapd->conf->secondary_ssid_count; i++) {
+			struct hostapd_ssid_str *s = &hapd->conf->secondary_ssid[i];
+			if (pos[1] == s->ssid_len &&
+			    os_memcmp(pos + 2, s->ssid, pos[1]) == 0)
+				return SECONDARY_SSID_MATCH;
+		}
+#endif /* CONFIG_MULTI_SSID */
+
 		pos += 2 + pos[1];
 	}
 
@@ -547,10 +569,11 @@  static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 static u8 ssid_is_handled(struct hostapd_iface *iface, const u8 *ssid, size_t ssid_len) {
 	size_t i;
 	struct hostapd_data *bss;
+	enum ssid_match_result res;
 	for (i = 0; i < iface->num_bss; i++) {
 		bss = iface->bss[i];
-		if (bss->conf->ssid.ssid_len == ssid_len &&
-		    os_memcmp(bss->conf->ssid.ssid, ssid, ssid_len) == 0)
+		res = ssid_match(bss, ssid, ssid_len, NULL, 0);
+		if (res == EXACT_SSID_MATCH || res == SECONDARY_SSID_MATCH)
 			return 1;
 	}
 	return 0;
@@ -671,6 +694,16 @@  void handle_probe_req(struct hostapd_data *hapd,
 
 #ifdef CONFIG_MULTI_SSID
 	/*
+	 * The client is requesting one of our secondary
+	 * SSID strings, so we just play along and use the
+	 * supplied values.
+	 */
+	if (res == SECONDARY_SSID_MATCH) {
+		ssid = elems.ssid;
+		ssid_len = elems.ssid_len;
+	}
+
+	/*
 	 * Process the probe request if "catchall" is set and no other match
 	 * is found in this or any other BSS.
 	 */
@@ -694,9 +727,14 @@  void handle_probe_req(struct hostapd_data *hapd,
 			#ifdef CONFIG_MULTI_SSID
 			hostapd_free_cloned_ssid(sta->ssid_probe);
 			sta->ssid_probe = NULL;
-			if (res == CATCHALL_SSID_MATCH)
+			if (res == CATCHALL_SSID_MATCH || res == SECONDARY_SSID_MATCH) {
+				/*
+				 * if the client isn't using the default SSID, we
+				 * create a temporary (and client specific) configuration
+				 * using the default settings as a template
+				 */
 				sta->ssid_probe = hostapd_clone_twin_ssid(hapd->conf, ssid, ssid_len);
-			else
+			} else
 			#endif /* CONFIG_MULTI_SSID */
 				sta->ssid_probe = &hapd->conf->ssid;
 		}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 42ab25f..6840c0f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1179,6 +1179,20 @@  static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
 	return 0;
 }
 
+#ifdef CONFIG_MULTI_SSID
+static u8 check_secondary_ssid(struct hostapd_data *hapd,
+		      const u8 *ssid_ie, size_t ssid_ie_len)
+{
+	size_t i;
+	for (i = 0; i < hapd->conf->secondary_ssid_count; i++) {
+		struct hostapd_ssid_str *s = &hapd->conf->secondary_ssid[i];
+		if (ssid_ie_len == s->ssid_len &&
+		    os_memcmp(ssid_ie, s->ssid, ssid_ie_len) == 0)
+			return 1;
+	}
+	return 0;
+}
+#endif /* CONFIG_MULTI_SSID */
 
 static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
 		      const u8 *ssid_ie, size_t ssid_ie_len)
@@ -1192,11 +1206,13 @@  static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
 	}
 
 #ifdef CONFIG_MULTI_SSID
-	if (hapd->conf->ssid.catchall) {
+	if (hapd->conf->ssid.catchall ||
+	    check_secondary_ssid(hapd, ssid_ie, ssid_ie_len)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO,
-			       "Station associating with catchall network, requested SSID "
-			       "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
+			       "Station associating with catchall/secondary network,"
+			       "requested SSID '%s'",
+			       wpa_ssid_txt(ssid_ie, ssid_ie_len));
 		sta->ssid = hostapd_clone_twin_ssid(hapd->conf, ssid_ie, ssid_ie_len);
 		if (sta->ssid == NULL)
 			return WLAN_STATUS_UNSPECIFIED_FAILURE;