mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-29 02:38:22 -05:00
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
@ -172,19 +172,6 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||||||
!(sta->flags & WLAN_STA_PREAUTH))
|
!(sta->flags & WLAN_STA_PREAUTH))
|
||||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
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_hash_del(hapd, sta);
|
||||||
ap_sta_list_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);
|
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||||
#endif /* CONFIG_NO_RADIUS */
|
#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);
|
os_free(sta->challenge);
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
#include <linux/sockios.h>
|
#include <linux/sockios.h>
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/if_bridge.h>
|
#include <linux/if_bridge.h>
|
||||||
@ -21,6 +21,7 @@
|
|||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
|
#include "wpa_auth.h"
|
||||||
#include "vlan_init.h"
|
#include "vlan_init.h"
|
||||||
#include "vlan_util.h"
|
#include "vlan_util.h"
|
||||||
|
|
||||||
@ -119,6 +120,8 @@ static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
|
|||||||
return clean;
|
return clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
|
||||||
static int ifconfig_helper(const char *if_name, int up)
|
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)
|
static int ifconfig_down(const char *if_name)
|
||||||
{
|
{
|
||||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", 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) {
|
while (vlan) {
|
||||||
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
|
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
|
||||||
if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
|
if (vlan_if_add(hapd, vlan, 1)) {
|
||||||
if (errno != EEXIST) {
|
wpa_printf(MSG_ERROR,
|
||||||
wpa_printf(MSG_ERROR, "VLAN: Could "
|
"VLAN: Could not add VLAN %s: %s",
|
||||||
"not add VLAN %s: %s",
|
vlan->ifname, strerror(errno));
|
||||||
vlan->ifname,
|
return -1;
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
ifconfig_up(vlan->ifname);
|
vlan_newlink(vlan->ifname, hapd);
|
||||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,7 +995,7 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
|
|||||||
next = vlan->next;
|
next = vlan->next;
|
||||||
|
|
||||||
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
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 "
|
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
|
||||||
"iface: %s: %s",
|
"iface: %s: %s",
|
||||||
vlan->ifname, strerror(errno));
|
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,
|
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
|
||||||
pos);
|
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);
|
os_free(n);
|
||||||
n = NULL;
|
n = NULL;
|
||||||
goto free_ifname;
|
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:
|
free_ifname:
|
||||||
os_free(ifname);
|
os_free(ifname);
|
||||||
return n;
|
return n;
|
||||||
@ -1073,7 +1123,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (vlan->dynamic_vlan == 0) {
|
if (vlan->dynamic_vlan == 0) {
|
||||||
hostapd_vlan_if_remove(hapd, vlan->ifname);
|
vlan_if_remove(hapd, vlan);
|
||||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
vlan_dellink(vlan->ifname, hapd);
|
vlan_dellink(vlan->ifname, hapd);
|
||||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
#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)
|
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
|
||||||
{
|
{
|
||||||
struct wpa_group *group;
|
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);
|
struct radius_das_attrs *attr);
|
||||||
void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
|
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 */
|
#endif /* WPA_AUTH_H */
|
||||||
|
@ -171,6 +171,7 @@ struct wpa_group {
|
|||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
/* Number of references except those in struct wpa_group->next */
|
/* Number of references except those in struct wpa_group->next */
|
||||||
unsigned int references;
|
unsigned int references;
|
||||||
|
unsigned int num_setup_iface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user