Patchwork [v3,01/25] Remove WPA per-VLAN groups when all stations left on rekeying

login
register
mail settings
Submitter michael-dev@fami-braun.de
Date July 27, 2013, 4:08 p.m.
Message ID <20130727160824.1152.49791.stgit@ray-controller>
Download mbox | patch
Permalink /patch/262462/
State Superseded
Headers show

Comments

michael-dev@fami-braun.de - July 27, 2013, 4:08 p.m.
This adds a references counter to struct wpa_group and frees
a group if it is unused.

This is useful when extending the number of VLANs supported.

Signed-hostap: Michael Braun <michael-dev@fami-braun.de>

V3: Freeing is not done in rekeying timer anymore.
---
 src/ap/wpa_auth.c   |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/wpa_auth_i.h |    2 +
 2 files changed, 73 insertions(+)

Patch

diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 83cc857..af7250e 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -41,6 +41,11 @@  static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
 			  struct wpa_group *group);
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 				       struct wpa_group *group);
+static void wpa_group_free(void *eloop_ctx, void *timeout_ctx);
+static void wpa_group_get(struct wpa_authenticator *wpa_auth,
+                          struct wpa_group *group);
+static void wpa_group_put(struct wpa_authenticator *wpa_auth,
+                          struct wpa_group *group);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -52,6 +57,7 @@  static const u32 eapol_key_timeout_first_group = 500; /* ms */
 static const int dot11RSNAConfigPMKLifetime = 43200;
 static const int dot11RSNAConfigPMKReauthThreshold = 70;
 static const int dot11RSNAConfigSATimeout = 60;
+static const int groupFreeTimeout = 5;
 
 
 static inline int wpa_auth_mic_failure_report(
@@ -467,6 +473,7 @@  void wpa_deinit(struct wpa_authenticator *wpa_auth)
 	while (group) {
 		prev = group;
 		group = group->next;
+		eloop_cancel_timeout(wpa_group_free, wpa_auth, group);
 		os_free(prev);
 	}
 
@@ -519,6 +526,7 @@  wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
 
 	sm->wpa_auth = wpa_auth;
 	sm->group = wpa_auth->group;
+	wpa_group_get(sm->wpa_auth, sm->group);
 
 	return sm;
 }
@@ -581,6 +589,7 @@  static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 #endif /* CONFIG_IEEE80211R */
 	os_free(sm->last_rx_eapol_key);
 	os_free(sm->wpa_ie);
+	wpa_group_put(sm->wpa_auth, sm->group);
 	os_free(sm);
 }
 
@@ -2960,6 +2969,65 @@  void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 }
 
 
+/**
+ * Remove and free the group from wpa_authenticator.
+ * This is triggered by a callback to make sure nobody
+ * is currently iterating the group list while it gets modified.
+ */
+static void wpa_group_free(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_group *group = timeout_ctx;
+	struct wpa_group *prev = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
+		   group->vlan_id);
+
+	while (prev) {
+		if (prev->next == group) {
+			/* This never frees the special first group as needed */
+			prev->next = group->next;
+			os_free(group);
+			break;
+		}
+		prev = prev->next;
+	}
+
+}
+
+
+static void
+wpa_group_get(struct wpa_authenticator *wpa_auth, struct wpa_group *group)
+{
+	// skip the special first group
+	if (wpa_auth->group == group)
+		return;
+
+	if (group->references == -1) {
+		eloop_cancel_timeout(wpa_group_free, wpa_auth, group);
+		group->references = 0;
+	}
+
+	group->references++;
+}
+
+
+static void
+wpa_group_put(struct wpa_authenticator *wpa_auth, struct wpa_group *group)
+{
+	// skip the special first group
+	if (wpa_auth->group == group)
+		return;
+
+	group->references--;
+	if (group->references != 0)
+		return;
+	eloop_register_timeout(groupFreeTimeout, 0, wpa_group_free, wpa_auth,
+	                       group);
+	group->references = -1;
+}
+
+
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
@@ -3007,7 +3075,10 @@  int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
 	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
 		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
 
+	wpa_group_put(sm->wpa_auth, sm->group);
 	sm->group = group;
+	wpa_group_get(sm->wpa_auth, sm->group);
+
 	return 0;
 }
 
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 97489d3..82e6e3a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -151,6 +151,8 @@  struct wpa_group {
 	u8 IGTK[2][WPA_IGTK_LEN];
 	int GN_igtk, GM_igtk;
 #endif /* CONFIG_IEEE80211W */
+	/* number of references except those in struct wpa_group->next */
+	int references;
 };