[PATCH v4 21/25] Fix STA dynamic vlan tracking
Michael Braun
michael-dev
Sat Jul 27 12:56:12 PDT 2013
When an STA is authenticated, it gets moved to appropiate (dynamic)
vlan using ap_sta_bind_vlan. Though, it is not removed when the
station disconnects - even if the struct sta_info is freed.
This results in dynamic interfaces not being removed.
Solution: The struct sta_info tracks the dynamic vlans the station
has been assigned. This information can be used to release
the VLAN the STA has been added to it before.
Signed-hostap: Michael Braun <michael-dev at fami-braun.de>
---
src/ap/ieee802_1x.c | 2 +-
src/ap/sta_info.c | 33 ++++++++++++++++++++++++++++++---
src/ap/sta_info.h | 4 ++++
3 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 604b115..e5bf003 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1360,7 +1360,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
break;
- vlan_free(&old_vlanid);
/* RFC 3580, Ch. 3.17 */
if (session_timeout_set && termination_action ==
@@ -1415,6 +1414,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
sm->eap_if->aaaEapReq = FALSE;
eapol_auth_step(sm);
+ vlan_free(&old_vlanid);
return RADIUS_RX_QUEUED;
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d3d9349..5fe1321 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -119,6 +119,22 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
}
+/**
+ * This method marks the STA as not being assigned to any VLAN currently.
+ * It may only be called if the STA is not assigned to its VLAN interface
+ * in kernel!
+ * It is used before freeing the sta data structure to release
+ * tehe vlan_id_bound VLAN pointer.
+ */
+void ap_unbind_sta_vlan(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (vlan_notempty(&sta->vlan_id_bound) &&
+ vlan_untagged(&sta->vlan_id_bound) >= 0)
+ vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ vlan_free(&sta->vlan_id_bound);
+}
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -247,6 +263,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_SAE */
vlan_free(&sta->vlan_id);
+ ap_unbind_sta_vlan(hapd, sta);
os_free(sta);
}
@@ -662,12 +679,18 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
+/**
+ * Moves the STA to its VLAN.
+ * @param old_vlanid Used to check if anything has changed. Might differ from
+ * sta->bound_vlanid as tracking in hostapd is not exact.
+ */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
vlan_t old_vlanid)
{
#ifndef CONFIG_NO_VLAN
const char *iface;
struct hostapd_vlan *vlan = NULL;
+ int boundVLANchanged;
int ret;
/*
@@ -681,8 +704,9 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
* During 1x reauth, if the vlan id changes, then remove the old id and
* proceed furthur to add the new one.
*/
- if (vlan_notempty(&old_vlanid) && vlan_untagged(&old_vlanid) >= 0)
- vlan_remove_dynamic(hapd, old_vlanid);
+ boundVLANchanged = !vlan_cmp(&sta->vlan_id, &sta->vlan_id_bound);
+ if (boundVLANchanged)
+ ap_unbind_sta_vlan(hapd, sta);
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
@@ -742,7 +766,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
"interface '%s'", iface);
} else if (vlan && vlan_cmp(&vlan->vlan_id, &sta->vlan_id)) {
if (vlan_notempty(&sta->vlan_id) &&
- vlan_untagged(&sta->vlan_id) >= 0) {
+ vlan_untagged(&sta->vlan_id) >= 0 &&
+ boundVLANchanged) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -770,6 +795,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
+ if (boundVLANchanged)
+ vlan_alloc_copy(&sta->vlan_id_bound, &sta->vlan_id);
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index c2d1525..ac25d9b 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -97,7 +97,10 @@ struct sta_info {
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+ /* VLAN-ID given by auth or acl */
vlan_t vlan_id;
+ /* VLAN ID currently in use (as counted with vlan->dynamic_vlan) */
+ vlan_t vlan_id_bound;
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -177,6 +180,7 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
vlan_t old_vlanid);
+void ap_unbind_sta_vlan(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
More information about the Hostap
mailing list