[PATCH v5 01/22] Remove WPA per-VLAN groups when all stations left on rekeying
Michael Braun
michael-dev
Tue Nov 19 11:46:44 PST 2013
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 at fami-braun.de>
V3: Freeing is not done in rekeying timer anymore.
V4: Avoid eloop timeout.
---
src/ap/wpa_auth.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++--
src/ap/wpa_auth_i.h | 2 +
2 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 03b15c2..7c508f8 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -41,6 +41,12 @@ 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(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
+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;
@@ -237,15 +243,22 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
- struct wpa_group *group;
+ struct wpa_group *group, *lastgroup;
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
- for (group = wpa_auth->group; group; group = group->next) {
+ group = wpa_auth->group;
+ while (group) {
+ wpa_group_get(wpa_auth, group);
+
group->GTKReKey = TRUE;
do {
group->changed = FALSE;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
+
+ lastgroup = group;
+ group = group->next;
+ wpa_group_put(wpa_auth, lastgroup);
}
if (wpa_auth->conf.wpa_group_rekey) {
@@ -525,6 +538,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;
}
@@ -587,6 +601,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);
}
@@ -2971,6 +2986,64 @@ 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(struct wpa_authenticator *wpa_auth, struct wpa_group *group)
+{
+ 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;
+
+ group->references++;
+}
+
+
+/**
+ * This decreases the reference counter and maybe frees the group.
+ */
+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;
+ wpa_group_free(wpa_auth, group);
+}
+
+
+/**
+ * This adds a group that has its references counter set to zero.
+ * Call wpa_group_get on the return value!
+ */
static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
@@ -2994,7 +3067,7 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
{
- struct wpa_group *group;
+ struct wpa_group *group, *oldgroup;
if (sm == NULL || sm->wpa_auth == NULL)
return 0;
@@ -3018,7 +3091,11 @@ 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_get(sm->wpa_auth, group);
+ oldgroup = sm->group;
sm->group = group;
+ wpa_group_put(sm->wpa_auth, oldgroup);
+
return 0;
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 12e59bc..4fd06c8 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -152,6 +152,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 */
+ unsigned int references;
};
More information about the Hostap
mailing list