[PATCH v2 3/4] Clone SSID twins to enable encrypted catchall APs

Stefan Tomanek stefan.tomanek
Sun Apr 26 06:43:29 PDT 2015


This change makes it possible to use encryption with catchall networks.
Upon associating a new client with a custom SSID, a new "twin" of the existing
ssid structure is created and keys are regenerated using the new SSID and the
existing origin configuration as a template. So multiple clones of the same
network can coexist using different SSID names - hence the term "twin".

Signed-off-by: Stefan Tomanek <stefan.tomanek at wertarbyte.de>
---
 src/ap/ap_config.c     | 67 ++++++++++++++++++++++++++++++++++++++++++++++----
 src/ap/ap_config.h     | 12 ++++++++-
 src/ap/beacon.c        | 12 +++++++--
 src/ap/ieee802_11.c    |  7 ++++--
 src/ap/sta_info.c      |  6 +++++
 src/ap/wpa_auth_glue.c |  2 +-
 6 files changed, 95 insertions(+), 11 deletions(-)

diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cccbfab..553397b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -18,6 +18,7 @@
 #include "wpa_auth.h"
 #include "sta_info.h"
 #include "ap_config.h"
+#include "hostapd.h"
 
 
 static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
@@ -314,10 +315,8 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
 }
 
 
-int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+static int hostapd_setup_wpa_ssid_psk(struct hostapd_ssid *ssid, struct hostapd_bss_config *conf)
 {
-	struct hostapd_ssid *ssid = &conf->ssid;
-
 	if (ssid->wpa_passphrase != NULL) {
 		if (ssid->wpa_psk != NULL) {
 			wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@@ -340,6 +339,11 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
 	return 0;
 }
 
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+{
+	return hostapd_setup_wpa_ssid_psk(&conf->ssid, conf);
+}
+
 
 static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
 				       int num_servers)
@@ -666,12 +670,17 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
 }
 
 
-const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+const u8 * hostapd_get_psk(struct hostapd_data *hapd,
 			   const u8 *addr, const u8 *p2p_dev_addr,
 			   const u8 *prev_psk)
 {
 	struct hostapd_wpa_psk *psk;
 	int next_ok = prev_psk == NULL;
+	struct hostapd_bss_config *conf = hapd->conf;
+	struct hostapd_ssid *ssid = &conf->ssid;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta && sta->ssid)
+		ssid = sta->ssid;
 
 	if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
@@ -684,7 +693,7 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   MAC2STR(addr), prev_psk);
 	}
 
-	for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
+	for (psk = ssid->wpa_psk; psk != NULL; psk = psk->next) {
 		if (next_ok &&
 		    (psk->group ||
 		     (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
@@ -946,3 +955,51 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
 			bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
 	}
 }
+
+#ifdef CONFIG_MULTI_SSID
+/**
+ * hostapd_clone_twin_ssid - Create a copy of an SSID struct
+ * @bss: The BSS to use as template for the cloning
+ * @ssid: The SSID identifier to use for the twin network
+ * @ssid_len: The length of the SSID identifier to be used
+ * Returns: The cloned hostapd_ssid struct.
+ *
+ * Create an independent copy of the hostapd_ssid struct used
+ * by the BSS instance and substitute the identifier; if a WPA
+ * passphrase is used, the new keys are derived using the new
+ * network identifier.
+ */
+struct hostapd_ssid * hostapd_clone_twin_ssid(struct hostapd_bss_config *bss,
+                                             const u8 *ssid, size_t ssid_len) {
+	/* clone ssid struct */
+	struct hostapd_ssid *orig = &bss->ssid;
+	struct hostapd_ssid *clone = os_zalloc(sizeof(*orig));
+	if (clone == NULL)
+		return NULL;
+	os_memcpy(clone, orig, sizeof(*orig));
+	clone->origin = orig;
+	/* insert new SSID */
+	os_memcpy(&clone->ssid, ssid, ssid_len);
+	clone->ssid_len = ssid_len;
+	/* clear and reinitialize WPA keys */
+	clone->wpa_psk = NULL;
+	hostapd_setup_wpa_ssid_psk(clone, bss);
+	return clone;
+}
+
+/**
+ * hostapd_free_cloned_ssid - Destroy a cloned SSID structure
+ * @ssid: The SSID structure to free
+ *
+ * Free the memory allocated for the hostapd_ssid structure
+ * and its contained WPA keys if the instance has been cloned
+ * instead of originating from the BSS config.
+ */
+void hostapd_free_cloned_ssid(struct hostapd_ssid *ssid) {
+	/* is this ssid a clone? */
+	if (!ssid || !ssid->origin)
+		return;
+	hostapd_config_clear_wpa_psk(&ssid->wpa_psk);
+	os_free(ssid);
+}
+#endif /* CONFIG_MULTI_SSID */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 52359d5..dd99a85 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "wps/wps.h"
+#include "sta_info.h"
 
 /**
  * mesh_conf - local MBSS state and settings
@@ -108,6 +109,10 @@ struct hostapd_ssid {
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	char *vlan_tagged_interface;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+#ifdef CONFIG_MULTI_SSID
+	struct hostapd_ssid *origin;
+#endif /* CONFIG_MULTI_SSID */
 };
 
 
@@ -668,7 +673,7 @@ void hostapd_config_free(struct hostapd_config *conf);
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
 			  const u8 *addr, int *vlan_id);
 int hostapd_rate_found(int *list, int rate);
-const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+const u8 * hostapd_get_psk(struct hostapd_data *hapd,
 			   const u8 *addr, const u8 *p2p_dev_addr,
 			   const u8 *prev_psk);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
@@ -681,4 +686,9 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
 void hostapd_set_security_params(struct hostapd_bss_config *bss,
 				 int full_config);
 
+#ifdef CONFIG_MULTI_SSID
+struct hostapd_ssid *hostapd_clone_twin_ssid(struct hostapd_bss_config *bss,
+                                             const u8 *ssid, size_t ssid_len);
+void hostapd_free_cloned_ssid(struct hostapd_ssid *ssid);
+#endif /* CONFIG_MULTI_SSID */
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 53c1a61..24af671 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -690,8 +690,16 @@ void handle_probe_req(struct hostapd_data *hapd,
 #endif /* CONFIG_MULTI_SSID */
 
 	if (res != NO_SSID_MATCH) {
-		if (sta)
-			sta->ssid_probe = &hapd->conf->ssid;
+		if (sta) {
+			#ifdef CONFIG_MULTI_SSID
+			hostapd_free_cloned_ssid(sta->ssid_probe);
+			sta->ssid_probe = NULL;
+			if (res == CATCHALL_SSID_MATCH)
+				sta->ssid_probe = hostapd_clone_twin_ssid(hapd->conf, ssid, ssid_len);
+			else
+			#endif /* CONFIG_MULTI_SSID */
+				sta->ssid_probe = &hapd->conf->ssid;
+		}
 	} else {
 		if (!(mgmt->da[0] & 0x01)) {
 			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a4884cc..42ab25f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1197,6 +1197,9 @@ static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
 			       HOSTAPD_LEVEL_INFO,
 			       "Station associating with catchall 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;
 		return WLAN_STATUS_SUCCESS;
 	}
 #endif /* CONFIG_MULTI_SSID */
@@ -2409,8 +2412,8 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO,
-		       "associated (aid %d)",
-		       sta->aid);
+		       "associated (aid %d) [%s]",
+		       sta->aid, wpa_ssid_txt(sta->ssid->ssid, sta->ssid->ssid_len));
 
 	if (sta->flags & WLAN_STA_ASSOC)
 		new_assoc = 0;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 1576db9..5c31009 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -311,6 +311,12 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 	os_free(sta->sae);
 #endif /* CONFIG_SAE */
 
+#ifdef CONFIG_MULTI_SSID
+	/* free cloned SSIDs */
+	hostapd_free_cloned_ssid(sta->ssid);
+	hostapd_free_cloned_ssid(sta->ssid_probe);
+#endif /* CONFIG_MULTI_SSID */
+
 	os_free(sta);
 }
 
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 7cd0b6c..2f8246c 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -229,7 +229,7 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
 	}
 #endif /* CONFIG_SAE */
 
-	psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
+	psk = hostapd_get_psk(hapd, addr, p2p_dev_addr, prev_psk);
 	/*
 	 * This is about to iterate over all psks, prev_psk gives the last
 	 * returned psk which should not be returned again.
-- 
2.1.4



More information about the Hostap mailing list