Fix init of group state machine for static VLANs
This ensures that group key is set as long as the interface exists. Additionally, ifconfig_up is needed as wpa_group will enter FATAL_FAILURE if the interface is still down. Also vlan_remove_dynamic() is moved after wpa_auth_sta_deinit() so vlan_remove_dynamic() can check it was the last user of the wpa_group. Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
This commit is contained in:
parent
a359c7bb23
commit
7cebc8e210
5 changed files with 184 additions and 33 deletions
|
@ -172,19 +172,6 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id_bound) {
|
||||
/*
|
||||
* Need to remove the STA entry before potentially removing the
|
||||
* VLAN.
|
||||
*/
|
||||
if (hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
ap_sta_list_del(hapd, sta);
|
||||
|
||||
|
@ -274,6 +261,24 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
/*
|
||||
* sta->wpa_sm->group needs to be released before so that
|
||||
* vlan_remove_dynamic() can check that no stations are left on the
|
||||
* AP_VLAN netdev.
|
||||
*/
|
||||
if (sta->vlan_id_bound) {
|
||||
/*
|
||||
* Need to remove the STA entry before potentially removing the
|
||||
* VLAN.
|
||||
*/
|
||||
if (hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
os_free(sta->challenge);
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
@ -21,6 +21,7 @@
|
|||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "vlan_init.h"
|
||||
#include "vlan_util.h"
|
||||
|
||||
|
@ -119,6 +120,8 @@ static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
|
|||
return clean;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
|
||||
static int ifconfig_helper(const char *if_name, int up)
|
||||
{
|
||||
|
@ -167,6 +170,58 @@ static int ifconfig_up(const char *if_name)
|
|||
}
|
||||
|
||||
|
||||
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
|
||||
int existsok)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!if_nametoindex(vlan->ifname))
|
||||
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
|
||||
else if (!existsok)
|
||||
return -1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
|
||||
|
||||
if (hapd->wpa_auth)
|
||||
ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
|
||||
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
|
||||
wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
|
||||
vlan->vlan_id, ret);
|
||||
if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
|
||||
wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
|
||||
|
||||
/* group state machine setup failed */
|
||||
if (hostapd_vlan_if_remove(hapd, vlan->ifname))
|
||||
wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
|
||||
if (ret)
|
||||
wpa_printf(MSG_ERROR,
|
||||
"WPA deinitialization for VLAN %d failed (%d)",
|
||||
vlan->vlan_id, ret);
|
||||
|
||||
return hostapd_vlan_if_remove(hapd, vlan->ifname);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
|
||||
static int ifconfig_down(const char *if_name)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
|
||||
|
@ -913,17 +968,14 @@ static int vlan_dynamic_add(struct hostapd_data *hapd,
|
|||
{
|
||||
while (vlan) {
|
||||
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
|
||||
if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
|
||||
if (errno != EEXIST) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could "
|
||||
"not add VLAN %s: %s",
|
||||
vlan->ifname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (vlan_if_add(hapd, vlan, 1)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VLAN: Could not add VLAN %s: %s",
|
||||
vlan->ifname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
ifconfig_up(vlan->ifname);
|
||||
vlan_newlink(vlan->ifname, hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
}
|
||||
|
||||
|
@ -943,7 +995,7 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
|
|||
next = vlan->next;
|
||||
|
||||
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
||||
hostapd_vlan_if_remove(hapd, vlan->ifname)) {
|
||||
vlan_if_remove(hapd, vlan)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
|
||||
"iface: %s: %s",
|
||||
vlan->ifname, strerror(errno));
|
||||
|
@ -1031,19 +1083,17 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
|||
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
|
||||
pos);
|
||||
|
||||
if (hostapd_vlan_if_add(hapd, n->ifname)) {
|
||||
n->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = n;
|
||||
|
||||
/* hapd->conf->vlan needs this new VLAN here for WPA setup */
|
||||
if (vlan_if_add(hapd, n, 0)) {
|
||||
hapd->conf->vlan = n->next;
|
||||
os_free(n);
|
||||
n = NULL;
|
||||
goto free_ifname;
|
||||
}
|
||||
|
||||
n->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = n;
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
ifconfig_up(n->ifname);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
free_ifname:
|
||||
os_free(ifname);
|
||||
return n;
|
||||
|
@ -1073,7 +1123,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
|||
return 1;
|
||||
|
||||
if (vlan->dynamic_vlan == 0) {
|
||||
hostapd_vlan_if_remove(hapd, vlan->ifname);
|
||||
vlan_if_remove(hapd, vlan);
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
vlan_dellink(vlan->ifname, hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
|
|
@ -3388,6 +3388,98 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enforce that the group state machine for the VLAN is running, increase
|
||||
* reference counter as interface is up. References might have been increased
|
||||
* even if a negative value is returned.
|
||||
* Returns: -1 on error (group missing, group already failed); otherwise, 0
|
||||
*/
|
||||
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return 0;
|
||||
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
if (group->vlan_id == vlan_id)
|
||||
break;
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
if (group == NULL) {
|
||||
group = wpa_auth_add_group(wpa_auth, vlan_id);
|
||||
if (group == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Ensure group state machine running for VLAN ID %d",
|
||||
vlan_id);
|
||||
|
||||
wpa_group_get(wpa_auth, group);
|
||||
group->num_setup_iface++;
|
||||
|
||||
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decrease reference counter, expected to be zero afterwards.
|
||||
* returns: -1 on error (group not found, group in fail state)
|
||||
* -2 if wpa_group is still referenced
|
||||
* 0 else
|
||||
*/
|
||||
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
int ret = 0;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return 0;
|
||||
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
if (group->vlan_id == vlan_id)
|
||||
break;
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
if (group == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Try stopping group state machine for VLAN ID %d",
|
||||
vlan_id);
|
||||
|
||||
if (group->num_setup_iface <= 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
|
||||
vlan_id);
|
||||
return -1;
|
||||
}
|
||||
group->num_setup_iface--;
|
||||
|
||||
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
|
||||
ret = -1;
|
||||
|
||||
if (group->references > 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
|
||||
vlan_id);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
wpa_group_put(wpa_auth, group);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
|
|
|
@ -325,4 +325,7 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
|
|||
struct radius_das_attrs *attr);
|
||||
void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
|
||||
|
||||
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
|
|
@ -171,6 +171,7 @@ struct wpa_group {
|
|||
#endif /* CONFIG_IEEE80211W */
|
||||
/* Number of references except those in struct wpa_group->next */
|
||||
unsigned int references;
|
||||
unsigned int num_setup_iface;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue