|
@@ -45,6 +45,12 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
|
|
|
struct wpa_group *group);
|
|
|
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
|
|
const u8 *pmk, struct wpa_ptk *ptk);
|
|
|
+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;
|
|
@@ -262,15 +268,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, *next;
|
|
|
|
|
|
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);
|
|
|
+
|
|
|
+ next = group->next;
|
|
|
+ wpa_group_put(wpa_auth, group);
|
|
|
+ group = next;
|
|
|
}
|
|
|
|
|
|
if (wpa_auth->conf.wpa_group_rekey) {
|
|
@@ -573,6 +586,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;
|
|
|
}
|
|
@@ -651,6 +665,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);
|
|
|
}
|
|
|
|
|
@@ -3281,6 +3296,63 @@ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Increase the reference counter for group */
|
|
|
+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++;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Decrease the reference counter and maybe free 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)
|
|
|
+ return;
|
|
|
+ wpa_group_free(wpa_auth, group);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Add a group that has its references counter set to zero. Caller needs to
|
|
|
+ * call wpa_group_get() on the return value to mark the entry in use.
|
|
|
+ */
|
|
|
static struct wpa_group *
|
|
|
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
|
|
{
|
|
@@ -3331,7 +3403,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_get(sm->wpa_auth, group);
|
|
|
+ wpa_group_put(sm->wpa_auth, sm->group);
|
|
|
sm->group = group;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|