2008-02-28 02:34:43 +01:00
|
|
|
/*
|
|
|
|
* hostapd / Station table
|
2017-03-12 00:26:43 +01:00
|
|
|
* Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
|
2008-02-28 02:34:43 +01:00
|
|
|
*
|
2012-02-11 15:46:35 +01:00
|
|
|
* This software may be distributed under the terms of the BSD license.
|
|
|
|
* See README for more details.
|
2008-02-28 02:34:43 +01:00
|
|
|
*/
|
|
|
|
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "utils/includes.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "utils/common.h"
|
|
|
|
#include "utils/eloop.h"
|
2009-12-25 23:31:51 +01:00
|
|
|
#include "common/ieee802_11_defs.h"
|
2011-11-03 20:58:22 +01:00
|
|
|
#include "common/wpa_ctrl.h"
|
2013-01-01 10:29:53 +01:00
|
|
|
#include "common/sae.h"
|
2009-12-24 23:30:16 +01:00
|
|
|
#include "radius/radius.h"
|
|
|
|
#include "radius/radius_client.h"
|
2010-07-18 23:30:25 +02:00
|
|
|
#include "p2p/p2p.h"
|
2015-01-21 14:30:48 +01:00
|
|
|
#include "fst/fst.h"
|
2017-03-12 00:26:43 +01:00
|
|
|
#include "crypto/crypto.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "hostapd.h"
|
|
|
|
#include "accounting.h"
|
|
|
|
#include "ieee802_1x.h"
|
|
|
|
#include "ieee802_11.h"
|
2012-11-25 17:01:55 +01:00
|
|
|
#include "ieee802_11_auth.h"
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "wpa_auth.h"
|
|
|
|
#include "preauth_auth.h"
|
|
|
|
#include "ap_config.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "beacon.h"
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "ap_mlme.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "vlan_init.h"
|
2010-07-09 02:14:24 +02:00
|
|
|
#include "p2p_hostapd.h"
|
2010-11-24 14:19:50 +01:00
|
|
|
#include "ap_drv_ops.h"
|
2012-02-26 21:34:19 +01:00
|
|
|
#include "gas_serv.h"
|
2013-08-01 23:39:30 +02:00
|
|
|
#include "wnm_ap.h"
|
2016-02-22 19:37:21 +01:00
|
|
|
#include "mbo_ap.h"
|
2014-11-01 07:33:41 +01:00
|
|
|
#include "ndisc_snoop.h"
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "sta_info.h"
|
2016-01-21 14:51:56 +01:00
|
|
|
#include "vlan.h"
|
2016-12-06 17:12:11 +01:00
|
|
|
#include "wps_hostapd.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-03-06 21:30:25 +01:00
|
|
|
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
2013-08-01 23:39:30 +02:00
|
|
|
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
|
2011-08-28 22:07:02 +02:00
|
|
|
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
|
|
|
|
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
|
2008-08-31 10:04:47 +02:00
|
|
|
#ifdef CONFIG_IEEE80211W
|
2008-12-26 10:46:21 +01:00
|
|
|
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
|
2008-08-31 10:04:47 +02:00
|
|
|
#endif /* CONFIG_IEEE80211W */
|
2011-08-28 22:07:02 +02:00
|
|
|
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
|
2016-12-06 17:12:11 +01:00
|
|
|
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
int ap_for_each_sta(struct hostapd_data *hapd,
|
|
|
|
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
void *ctx),
|
|
|
|
void *ctx)
|
|
|
|
{
|
|
|
|
struct sta_info *sta;
|
|
|
|
|
|
|
|
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
|
|
|
if (cb(hapd, sta, ctx))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
|
|
|
{
|
|
|
|
struct sta_info *s;
|
|
|
|
|
|
|
|
s = hapd->sta_hash[STA_HASH(sta)];
|
|
|
|
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
|
|
|
|
s = s->hnext;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-01 16:37:22 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
|
|
|
|
{
|
|
|
|
struct sta_info *sta;
|
|
|
|
|
|
|
|
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
|
|
|
const u8 *p2p_dev_addr;
|
|
|
|
|
|
|
|
if (sta->p2p_ie == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
|
|
|
|
if (p2p_dev_addr == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
|
|
|
|
return sta;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
struct sta_info *tmp;
|
|
|
|
|
|
|
|
if (hapd->sta_list == sta) {
|
|
|
|
hapd->sta_list = sta->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = hapd->sta_list;
|
|
|
|
while (tmp != NULL && tmp->next != sta)
|
|
|
|
tmp = tmp->next;
|
|
|
|
if (tmp == NULL) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
|
|
|
|
"list.", MAC2STR(sta->addr));
|
|
|
|
} else
|
|
|
|
tmp->next = sta->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
|
|
|
|
hapd->sta_hash[STA_HASH(sta->addr)] = sta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
struct sta_info *s;
|
|
|
|
|
|
|
|
s = hapd->sta_hash[STA_HASH(sta->addr)];
|
|
|
|
if (s == NULL) return;
|
|
|
|
if (os_memcmp(s->addr, sta->addr, 6) == 0) {
|
|
|
|
hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (s->hnext != NULL &&
|
|
|
|
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
|
|
|
|
s = s->hnext;
|
|
|
|
if (s->hnext != NULL)
|
|
|
|
s->hnext = s->hnext->hnext;
|
|
|
|
else
|
|
|
|
wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
|
|
|
|
" from hash table", MAC2STR(sta->addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-01 07:33:41 +01:00
|
|
|
void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
sta_ip6addr_del(hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
int set_beacon = 0;
|
|
|
|
|
|
|
|
accounting_sta_stop(hapd, sta);
|
|
|
|
|
2011-02-02 15:52:32 +01:00
|
|
|
/* just in case */
|
|
|
|
ap_sta_set_authorized(hapd, sta, 0);
|
|
|
|
|
2010-03-06 19:52:22 +01:00
|
|
|
if (sta->flags & WLAN_STA_WDS)
|
2013-07-20 16:41:22 +02:00
|
|
|
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
|
2010-03-06 21:30:25 +01:00
|
|
|
|
AP: Add support for Proxy ARP, DHCP snooping mechanism
Proxy ARP allows the AP devices to keep track of the hardware address to
IP address mapping of the STA devices within the BSS. When a request for
such information is made (i.e., ARP request, Neighbor Solicitation), the
AP will respond on behalf of the STA device within the BSS. Such
requests could originate from a device within the BSS or also from the
bridge. In the process of the AP replying to the request (i.e., ARP
reply, Neighbor Advertisement), the AP will drop the original request
frame. The relevant STA will not even know that such information was
ever requested.
This feature is a requirement for Hotspot 2.0, and is defined in IEEE
Std 802.11-2012, 10.23.13. While the Proxy ARP support code mainly
resides in the kernel bridge code, in order to optimize the performance
and simplify kernel implementation, the DHCP snooping code was added to
the hostapd.
Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
2014-09-26 07:32:55 +02:00
|
|
|
if (sta->ipaddr)
|
2014-11-06 01:15:46 +01:00
|
|
|
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
2014-11-01 07:33:41 +01:00
|
|
|
ap_sta_ip6addr_del(hapd, sta);
|
AP: Add support for Proxy ARP, DHCP snooping mechanism
Proxy ARP allows the AP devices to keep track of the hardware address to
IP address mapping of the STA devices within the BSS. When a request for
such information is made (i.e., ARP request, Neighbor Solicitation), the
AP will respond on behalf of the STA device within the BSS. Such
requests could originate from a device within the BSS or also from the
bridge. In the process of the AP replying to the request (i.e., ARP
reply, Neighbor Advertisement), the AP will drop the original request
frame. The relevant STA will not even know that such information was
ever requested.
This feature is a requirement for Hotspot 2.0, and is defined in IEEE
Std 802.11-2012, 10.23.13. While the Proxy ARP support code mainly
resides in the kernel bridge code, in order to optimize the performance
and simplify kernel implementation, the DHCP snooping code was added to
the hostapd.
Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
2014-09-26 07:32:55 +02:00
|
|
|
|
2014-03-05 13:55:29 +01:00
|
|
|
if (!hapd->iface->driver_ap_teardown &&
|
2016-02-16 10:54:32 +01:00
|
|
|
!(sta->flags & WLAN_STA_PREAUTH)) {
|
2010-11-24 14:36:02 +01:00
|
|
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
2016-02-16 10:54:32 +01:00
|
|
|
sta->added_unassoc = 0;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
ap_sta_hash_del(hapd, sta);
|
|
|
|
ap_sta_list_del(hapd, sta);
|
|
|
|
|
|
|
|
if (sta->aid > 0)
|
2009-03-25 14:54:25 +01:00
|
|
|
hapd->sta_aid[(sta->aid - 1) / 32] &=
|
|
|
|
~BIT((sta->aid - 1) % 32);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
hapd->num_sta--;
|
|
|
|
if (sta->nonerp_set) {
|
|
|
|
sta->nonerp_set = 0;
|
|
|
|
hapd->iface->num_sta_non_erp--;
|
|
|
|
if (hapd->iface->num_sta_non_erp == 0)
|
|
|
|
set_beacon++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sta->no_short_slot_time_set) {
|
|
|
|
sta->no_short_slot_time_set = 0;
|
|
|
|
hapd->iface->num_sta_no_short_slot_time--;
|
|
|
|
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
|
|
|
&& hapd->iface->num_sta_no_short_slot_time == 0)
|
|
|
|
set_beacon++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sta->no_short_preamble_set) {
|
|
|
|
sta->no_short_preamble_set = 0;
|
|
|
|
hapd->iface->num_sta_no_short_preamble--;
|
|
|
|
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
|
|
|
&& hapd->iface->num_sta_no_short_preamble == 0)
|
|
|
|
set_beacon++;
|
|
|
|
}
|
|
|
|
|
2008-12-02 13:32:05 +01:00
|
|
|
if (sta->no_ht_gf_set) {
|
|
|
|
sta->no_ht_gf_set = 0;
|
|
|
|
hapd->iface->num_sta_ht_no_gf--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sta->no_ht_set) {
|
|
|
|
sta->no_ht_set = 0;
|
2008-08-21 17:18:38 +02:00
|
|
|
hapd->iface->num_sta_no_ht--;
|
2008-12-02 13:32:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sta->ht_20mhz_set) {
|
|
|
|
sta->ht_20mhz_set = 0;
|
|
|
|
hapd->iface->num_sta_ht_20mhz--;
|
|
|
|
}
|
2008-08-21 17:18:38 +02:00
|
|
|
|
Passive Client Taxonomy
Implement the signature mechanism described in the paper
"Passive Taxonomy of Wifi Clients using MLME Frame Contents"
published by Denton Gentry and Avery Pennarun.
http://research.google.com/pubs/pub45429.html
https://arxiv.org/abs/1608.01725
This involves:
1. Add a CONFIG_TAXONOMY compile option. Enabling taxonomy incurs
a memory overhead of up to several kilobytes per associated
station.
2. If enabled, store the Probe Request and (Re)Associate Request frame in
struct sta_info.
3. Implement code to extract the ID of each Information Element,
plus selected fields and bitmasks from certain IEs, into a
descriptive text string. This is done in a new source file,
src/ap/taxonomy.c.
4. Implement a "signature qq:rr:ss:tt:uu:vv" command
in hostapd_cli to retrieve the signature.
Signatures take the form of a text string. For example, a signature
for the Nexus 5X is:
wifi4|probe:0,1,127,45,191,htcap:01ef,htagg:03,htmcs:0000ffff,vhtcap:338061b2,
vhtrxmcs:030cfffa,vhttxmcs:030cfffa,extcap:00000a0201000040|assoc:0,1,48,45,
221(0050f2,2),191,127,htcap:01ef,htagg:03,htmcs:0000ffff,vhtcap:339071b2,
vhtrxmcs:030cfffa,vhttxmcs:030cfffa,extcap:0000000000000040
Signed-off-by: dgentry@google.com (Denton Gentry)
Signed-off-by: denny@geekhold.com (Denton Gentry)
Signed-off-by: rofrankel@google.com (Richard Frankel)
Signed-off-by: richard@frankel.tv (Richard Frankel)
2016-08-15 06:42:48 +02:00
|
|
|
#ifdef CONFIG_TAXONOMY
|
|
|
|
wpabuf_free(sta->probe_ie_taxonomy);
|
|
|
|
sta->probe_ie_taxonomy = NULL;
|
|
|
|
wpabuf_free(sta->assoc_ie_taxonomy);
|
|
|
|
sta->assoc_ie_taxonomy = NULL;
|
|
|
|
#endif /* CONFIG_TAXONOMY */
|
|
|
|
|
2014-04-14 19:40:56 +02:00
|
|
|
#ifdef CONFIG_IEEE80211N
|
|
|
|
ht40_intolerant_remove(hapd->iface, sta);
|
|
|
|
#endif /* CONFIG_IEEE80211N */
|
|
|
|
|
2010-07-09 02:14:24 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
if (sta->no_p2p_set) {
|
|
|
|
sta->no_p2p_set = 0;
|
|
|
|
hapd->num_sta_no_p2p--;
|
|
|
|
if (hapd->num_sta_no_p2p == 0)
|
|
|
|
hostapd_p2p_non_p2p_sta_disconnected(hapd);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
2009-12-06 18:41:47 +01:00
|
|
|
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
|
2008-08-21 17:18:38 +02:00
|
|
|
if (hostapd_ht_operation_update(hapd->iface) > 0)
|
|
|
|
set_beacon++;
|
2009-12-06 18:41:47 +01:00
|
|
|
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
|
2008-08-21 17:18:38 +02:00
|
|
|
|
2014-09-01 06:23:31 +02:00
|
|
|
#ifdef CONFIG_MESH
|
|
|
|
if (hapd->mesh_sta_free_cb)
|
2016-01-31 03:45:30 +01:00
|
|
|
hapd->mesh_sta_free_cb(hapd, sta);
|
2014-09-01 06:23:31 +02:00
|
|
|
#endif /* CONFIG_MESH */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (set_beacon)
|
|
|
|
ieee802_11_set_beacons(hapd->iface);
|
|
|
|
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
|
|
|
|
__func__, MAC2STR(sta->addr));
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
|
|
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
2013-08-01 23:39:30 +02:00
|
|
|
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
|
2016-01-15 18:28:58 +01:00
|
|
|
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
2015-01-07 07:10:57 +01:00
|
|
|
sae_clear_retransmit_timer(hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2015-12-31 20:46:08 +01:00
|
|
|
ieee802_1x_free_station(hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_auth_sta_deinit(sta->wpa_sm);
|
|
|
|
rsn_preauth_free_station(hapd, sta);
|
2009-12-06 16:53:59 +01:00
|
|
|
#ifndef CONFIG_NO_RADIUS
|
2013-10-14 19:44:31 +02:00
|
|
|
if (hapd->radius)
|
|
|
|
radius_client_flush_auth(hapd->radius, sta->addr);
|
2009-12-06 16:53:59 +01:00
|
|
|
#endif /* CONFIG_NO_RADIUS */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2015-10-05 16:14:26 +02:00
|
|
|
#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.
|
|
|
|
*/
|
2016-01-21 14:51:56 +01:00
|
|
|
if (sta->vlan_id)
|
|
|
|
vlan_remove_dynamic(hapd, sta->vlan_id);
|
2015-10-05 16:14:26 +02:00
|
|
|
if (sta->vlan_id_bound) {
|
|
|
|
/*
|
|
|
|
* Need to remove the STA entry before potentially removing the
|
|
|
|
* VLAN.
|
|
|
|
*/
|
|
|
|
if (hapd->iface->driver_ap_teardown &&
|
2016-02-16 10:54:32 +01:00
|
|
|
!(sta->flags & WLAN_STA_PREAUTH)) {
|
2015-10-05 16:14:26 +02:00
|
|
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
2016-02-16 10:54:32 +01:00
|
|
|
sta->added_unassoc = 0;
|
|
|
|
}
|
2015-10-05 16:14:26 +02:00
|
|
|
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NO_VLAN */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
os_free(sta->challenge);
|
2008-08-31 10:04:47 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
2008-12-26 10:46:21 +01:00
|
|
|
os_free(sta->sa_query_trans_id);
|
|
|
|
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
|
2008-08-31 10:04:47 +02:00
|
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
|
2010-07-18 23:30:25 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
2012-02-26 21:34:19 +01:00
|
|
|
#ifdef CONFIG_INTERWORKING
|
|
|
|
if (sta->gas_dialog) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < GAS_DIALOG_MAX; i++)
|
|
|
|
gas_serv_dialog_clear(&sta->gas_dialog[i]);
|
|
|
|
os_free(sta->gas_dialog);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_INTERWORKING */
|
|
|
|
|
2008-11-29 11:11:56 +01:00
|
|
|
wpabuf_free(sta->wps_ie);
|
2010-07-18 23:30:25 +02:00
|
|
|
wpabuf_free(sta->p2p_ie);
|
2012-11-21 23:19:17 +01:00
|
|
|
wpabuf_free(sta->hs20_ie);
|
2015-01-21 14:30:48 +01:00
|
|
|
#ifdef CONFIG_FST
|
|
|
|
wpabuf_free(sta->mb_ies);
|
|
|
|
#endif /* CONFIG_FST */
|
2008-11-29 11:11:56 +01:00
|
|
|
|
2009-11-29 20:07:52 +01:00
|
|
|
os_free(sta->ht_capabilities);
|
2013-11-22 12:48:02 +01:00
|
|
|
os_free(sta->vht_capabilities);
|
2012-11-25 17:01:55 +01:00
|
|
|
hostapd_free_psk_list(sta->psk);
|
2012-08-19 13:20:10 +02:00
|
|
|
os_free(sta->identity);
|
|
|
|
os_free(sta->radius_cui);
|
2012-11-21 23:48:48 +01:00
|
|
|
os_free(sta->remediation_url);
|
2013-07-26 21:13:58 +02:00
|
|
|
wpabuf_free(sta->hs20_deauth_req);
|
2013-08-01 23:39:30 +02:00
|
|
|
os_free(sta->hs20_session_info_url);
|
2009-11-29 20:07:52 +01:00
|
|
|
|
2012-12-30 20:48:19 +01:00
|
|
|
#ifdef CONFIG_SAE
|
2013-01-01 10:29:53 +01:00
|
|
|
sae_clear_data(sta->sae);
|
2012-12-30 20:48:19 +01:00
|
|
|
os_free(sta->sae);
|
|
|
|
#endif /* CONFIG_SAE */
|
|
|
|
|
2016-02-22 19:37:21 +01:00
|
|
|
mbo_ap_sta_free(sta);
|
2016-02-24 11:20:31 +01:00
|
|
|
os_free(sta->supp_op_classes);
|
2016-02-22 19:37:21 +01:00
|
|
|
|
2017-01-31 13:38:44 +01:00
|
|
|
#ifdef CONFIG_FILS
|
|
|
|
os_free(sta->fils_pending_assoc_req);
|
|
|
|
wpabuf_free(sta->fils_hlp_resp);
|
|
|
|
wpabuf_free(sta->hlp_dhcp_discover);
|
|
|
|
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
2017-03-12 21:40:56 +01:00
|
|
|
#ifdef CONFIG_FILS_SK_PFS
|
|
|
|
crypto_ecdh_deinit(sta->fils_ecdh);
|
|
|
|
wpabuf_clear_free(sta->fils_dh_ss);
|
2017-05-07 16:04:08 +02:00
|
|
|
wpabuf_free(sta->fils_g_sta);
|
2017-03-12 21:40:56 +01:00
|
|
|
#endif /* CONFIG_FILS_SK_PFS */
|
2017-01-31 13:38:44 +01:00
|
|
|
#endif /* CONFIG_FILS */
|
|
|
|
|
2017-03-12 00:26:43 +01:00
|
|
|
#ifdef CONFIG_OWE
|
|
|
|
bin_clear_free(sta->owe_pmk, PMK_LEN);
|
|
|
|
crypto_ecdh_deinit(sta->owe_ecdh);
|
|
|
|
#endif /* CONFIG_OWE */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
os_free(sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void hostapd_free_stas(struct hostapd_data *hapd)
|
|
|
|
{
|
|
|
|
struct sta_info *sta, *prev;
|
|
|
|
|
|
|
|
sta = hapd->sta_list;
|
|
|
|
|
|
|
|
while (sta) {
|
|
|
|
prev = sta;
|
|
|
|
if (sta->flags & WLAN_STA_AUTH) {
|
|
|
|
mlme_deauthenticate_indication(
|
|
|
|
hapd, sta, WLAN_REASON_UNSPECIFIED);
|
|
|
|
}
|
|
|
|
sta = sta->next;
|
|
|
|
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
|
|
|
|
MAC2STR(prev->addr));
|
|
|
|
ap_free_sta(hapd, prev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 15:33:00 +01:00
|
|
|
/**
|
|
|
|
* ap_handle_timer - Per STA timer handler
|
|
|
|
* @eloop_ctx: struct hostapd_data *
|
|
|
|
* @timeout_ctx: struct sta_info *
|
|
|
|
*
|
|
|
|
* This function is called to check station activity and to remove inactive
|
|
|
|
* stations.
|
|
|
|
*/
|
2008-02-28 02:34:43 +01:00
|
|
|
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
unsigned long next_time = 0;
|
2013-04-05 17:41:26 +02:00
|
|
|
int reason;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
|
|
|
|
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
|
2012-04-11 13:09:40 +02:00
|
|
|
sta->timeout_next);
|
2008-02-28 02:34:43 +01:00
|
|
|
if (sta->timeout_next == STA_REMOVE) {
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
|
|
|
"local deauth request");
|
|
|
|
ap_free_sta(hapd, sta);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sta->flags & WLAN_STA_ASSOC) &&
|
|
|
|
(sta->timeout_next == STA_NULLFUNC ||
|
|
|
|
sta->timeout_next == STA_DISASSOC)) {
|
|
|
|
int inactive_sec;
|
2012-04-06 10:47:29 +02:00
|
|
|
/*
|
|
|
|
* Add random value to timeout so that we don't end up bouncing
|
|
|
|
* all stations at the same time if we have lots of associated
|
|
|
|
* stations that are idle (but keep re-associating).
|
|
|
|
*/
|
|
|
|
int fuzz = os_random() % 20;
|
2010-11-24 14:36:02 +01:00
|
|
|
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
|
2008-02-28 02:34:43 +01:00
|
|
|
if (inactive_sec == -1) {
|
2011-11-03 21:04:17 +01:00
|
|
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"Check inactivity: Could not "
|
2012-01-02 20:27:06 +01:00
|
|
|
"get station info from kernel driver for "
|
2011-02-24 16:44:45 +01:00
|
|
|
MACSTR, MAC2STR(sta->addr));
|
2012-01-02 20:27:06 +01:00
|
|
|
/*
|
|
|
|
* The driver may not support this functionality.
|
|
|
|
* Anyway, try again after the next inactivity timeout,
|
|
|
|
* but do not disconnect the station now.
|
|
|
|
*/
|
2012-04-06 10:47:29 +02:00
|
|
|
next_time = hapd->conf->ap_max_inactivity + fuzz;
|
2015-01-16 12:19:23 +01:00
|
|
|
} else if (inactive_sec == -ENOENT) {
|
|
|
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"Station " MACSTR " has lost its driver entry",
|
|
|
|
MAC2STR(sta->addr));
|
|
|
|
|
2015-02-09 22:23:53 +01:00
|
|
|
/* Avoid sending client probe on removed client */
|
|
|
|
sta->timeout_next = STA_DISASSOC;
|
|
|
|
goto skip_poll;
|
2015-01-16 12:00:57 +01:00
|
|
|
} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
|
2008-02-28 02:34:43 +01:00
|
|
|
/* station activity detected; reset timeout state */
|
2011-11-03 21:04:17 +01:00
|
|
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"Station " MACSTR " has been active %is ago",
|
2011-02-24 16:44:45 +01:00
|
|
|
MAC2STR(sta->addr), inactive_sec);
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->timeout_next = STA_NULLFUNC;
|
2012-04-06 10:47:29 +02:00
|
|
|
next_time = hapd->conf->ap_max_inactivity + fuzz -
|
2008-02-28 02:34:43 +01:00
|
|
|
inactive_sec;
|
2011-02-24 16:44:45 +01:00
|
|
|
} else {
|
2011-11-03 21:04:17 +01:00
|
|
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"Station " MACSTR " has been "
|
2011-02-24 16:44:45 +01:00
|
|
|
"inactive too long: %d sec, max allowed: %d",
|
|
|
|
MAC2STR(sta->addr), inactive_sec,
|
|
|
|
hapd->conf->ap_max_inactivity);
|
2011-12-25 19:57:01 +01:00
|
|
|
|
|
|
|
if (hapd->conf->skip_inactivity_poll)
|
|
|
|
sta->timeout_next = STA_DISASSOC;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sta->flags & WLAN_STA_ASSOC) &&
|
|
|
|
sta->timeout_next == STA_DISASSOC &&
|
2011-12-25 19:57:01 +01:00
|
|
|
!(sta->flags & WLAN_STA_PENDING_POLL) &&
|
|
|
|
!hapd->conf->skip_inactivity_poll) {
|
2011-11-03 21:04:17 +01:00
|
|
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
|
|
|
|
" has ACKed data poll", MAC2STR(sta->addr));
|
2008-02-28 02:34:43 +01:00
|
|
|
/* data nullfunc frame poll did not produce TX errors; assume
|
|
|
|
* station ACKed it */
|
|
|
|
sta->timeout_next = STA_NULLFUNC;
|
|
|
|
next_time = hapd->conf->ap_max_inactivity;
|
|
|
|
}
|
|
|
|
|
2015-02-09 22:23:53 +01:00
|
|
|
skip_poll:
|
2008-02-28 02:34:43 +01:00
|
|
|
if (next_time) {
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%lu seconds)",
|
|
|
|
__func__, MAC2STR(sta->addr), next_time);
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
|
|
|
|
sta);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sta->timeout_next == STA_NULLFUNC &&
|
|
|
|
(sta->flags & WLAN_STA_ASSOC)) {
|
2011-10-20 20:03:08 +02:00
|
|
|
wpa_printf(MSG_DEBUG, " Polling STA");
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->flags |= WLAN_STA_PENDING_POLL;
|
2011-10-20 20:03:08 +02:00
|
|
|
hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
|
|
|
|
sta->flags & WLAN_STA_WMM);
|
2008-02-28 02:34:43 +01:00
|
|
|
} else if (sta->timeout_next != STA_REMOVE) {
|
|
|
|
int deauth = sta->timeout_next == STA_DEAUTH;
|
|
|
|
|
2011-12-10 15:34:52 +01:00
|
|
|
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"Timeout, sending %s info to STA " MACSTR,
|
|
|
|
deauth ? "deauthentication" : "disassociation",
|
|
|
|
MAC2STR(sta->addr));
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
if (deauth) {
|
2010-11-24 14:36:02 +01:00
|
|
|
hostapd_drv_sta_deauth(
|
|
|
|
hapd, sta->addr,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
2008-02-28 02:34:43 +01:00
|
|
|
} else {
|
2013-04-05 17:41:26 +02:00
|
|
|
reason = (sta->timeout_next == STA_DISASSOC) ?
|
|
|
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID;
|
|
|
|
|
|
|
|
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (sta->timeout_next) {
|
|
|
|
case STA_NULLFUNC:
|
|
|
|
sta->timeout_next = STA_DISASSOC;
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
|
|
|
|
__func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
|
|
|
|
hapd, sta);
|
|
|
|
break;
|
|
|
|
case STA_DISASSOC:
|
2013-04-05 17:41:26 +02:00
|
|
|
case STA_DISASSOC_FROM_CLI:
|
2011-11-03 21:17:41 +01:00
|
|
|
ap_sta_set_authorized(hapd, sta, 0);
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->flags &= ~WLAN_STA_ASSOC;
|
|
|
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
|
|
|
if (!sta->acct_terminate_cause)
|
|
|
|
sta->acct_terminate_cause =
|
|
|
|
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
|
|
|
accounting_sta_stop(hapd, sta);
|
2015-12-31 20:46:08 +01:00
|
|
|
ieee802_1x_free_station(hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_INFO, "disassociated due to "
|
|
|
|
"inactivity");
|
2013-04-05 17:41:26 +02:00
|
|
|
reason = (sta->timeout_next == STA_DISASSOC) ?
|
|
|
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID;
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->timeout_next = STA_DEAUTH;
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
|
|
|
|
__func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
|
|
|
|
hapd, sta);
|
2013-04-05 17:41:26 +02:00
|
|
|
mlme_disassociate_indication(hapd, sta, reason);
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
case STA_DEAUTH:
|
|
|
|
case STA_REMOVE:
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
2011-12-10 15:34:52 +01:00
|
|
|
"inactivity (timer DEAUTH/REMOVE)");
|
2008-02-28 02:34:43 +01:00
|
|
|
if (!sta->acct_terminate_cause)
|
|
|
|
sta->acct_terminate_cause =
|
|
|
|
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
|
|
|
mlme_deauthenticate_indication(
|
|
|
|
hapd, sta,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
|
|
|
ap_free_sta(hapd, sta);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2012-02-26 21:34:19 +01:00
|
|
|
if (!(sta->flags & WLAN_STA_AUTH)) {
|
|
|
|
if (sta->flags & WLAN_STA_GAS) {
|
|
|
|
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
|
|
|
|
"entry " MACSTR, MAC2STR(sta->addr));
|
|
|
|
ap_free_sta(hapd, sta);
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
return;
|
2012-02-26 21:34:19 +01:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2014-03-07 22:23:41 +01:00
|
|
|
hostapd_drv_sta_deauth(hapd, sta->addr,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
2008-02-28 02:34:43 +01:00
|
|
|
mlme_deauthenticate_indication(hapd, sta,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
|
|
|
"session timeout");
|
|
|
|
sta->acct_terminate_cause =
|
|
|
|
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
|
|
|
|
ap_free_sta(hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-06 22:20:28 +01:00
|
|
|
void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
u32 session_timeout)
|
|
|
|
{
|
|
|
|
if (eloop_replenish_timeout(session_timeout, 0,
|
2014-01-05 08:59:38 +01:00
|
|
|
ap_handle_session_timer, hapd, sta) == 1) {
|
2013-11-06 22:20:28 +01:00
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "setting session timeout "
|
|
|
|
"to %d seconds", session_timeout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
u32 session_timeout)
|
|
|
|
{
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
|
|
|
|
"seconds", session_timeout);
|
|
|
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
|
|
|
eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
|
|
|
|
hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-01 23:39:30 +02:00
|
|
|
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
2017-06-12 08:29:27 +02:00
|
|
|
#ifdef CONFIG_WNM_AP
|
2013-08-01 23:39:30 +02:00
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
|
|
|
|
MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
|
2013-08-01 23:39:30 +02:00
|
|
|
if (sta->hs20_session_info_url == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
|
|
|
|
sta->hs20_disassoc_timer);
|
2017-06-12 08:29:27 +02:00
|
|
|
#endif /* CONFIG_WNM_AP */
|
2013-08-01 23:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta, int warning_time)
|
|
|
|
{
|
|
|
|
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
|
|
|
|
eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
|
|
|
|
hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
|
|
|
{
|
|
|
|
struct sta_info *sta;
|
|
|
|
|
|
|
|
sta = ap_get_sta(hapd, addr);
|
|
|
|
if (sta)
|
|
|
|
return sta;
|
|
|
|
|
|
|
|
wpa_printf(MSG_DEBUG, " New STA");
|
|
|
|
if (hapd->num_sta >= hapd->conf->max_num_sta) {
|
|
|
|
/* FIX: might try to remove some old STAs first? */
|
|
|
|
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
|
|
|
|
hapd->num_sta, hapd->conf->max_num_sta);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sta = os_zalloc(sizeof(struct sta_info));
|
|
|
|
if (sta == NULL) {
|
|
|
|
wpa_printf(MSG_ERROR, "malloc failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-11-28 22:03:20 +01:00
|
|
|
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
|
2016-01-24 12:37:46 +01:00
|
|
|
if (accounting_sta_get_id(hapd, sta) < 0) {
|
|
|
|
os_free(sta);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2013-05-16 16:44:31 +02:00
|
|
|
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
|
|
|
__func__, MAC2STR(addr),
|
|
|
|
hapd->conf->ap_max_inactivity);
|
|
|
|
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
|
|
|
ap_handle_timer, hapd, sta);
|
|
|
|
}
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
/* initialize STA info data */
|
|
|
|
os_memcpy(sta->addr, addr, ETH_ALEN);
|
|
|
|
sta->next = hapd->sta_list;
|
|
|
|
hapd->sta_list = sta;
|
|
|
|
hapd->num_sta++;
|
|
|
|
ap_sta_hash_add(hapd, sta);
|
2010-03-06 21:30:25 +01:00
|
|
|
ap_sta_remove_in_other_bss(hapd, sta);
|
2014-11-05 09:50:34 +01:00
|
|
|
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
2014-11-01 07:33:41 +01:00
|
|
|
dl_list_init(&sta->ip6addr);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2016-08-15 06:42:49 +02:00
|
|
|
#ifdef CONFIG_TAXONOMY
|
|
|
|
sta_track_claim_taxonomy_info(hapd->iface, addr,
|
|
|
|
&sta->probe_ie_taxonomy);
|
|
|
|
#endif /* CONFIG_TAXONOMY */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
return sta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
|
|
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
|
|
|
|
AP: Add support for Proxy ARP, DHCP snooping mechanism
Proxy ARP allows the AP devices to keep track of the hardware address to
IP address mapping of the STA devices within the BSS. When a request for
such information is made (i.e., ARP request, Neighbor Solicitation), the
AP will respond on behalf of the STA device within the BSS. Such
requests could originate from a device within the BSS or also from the
bridge. In the process of the AP replying to the request (i.e., ARP
reply, Neighbor Advertisement), the AP will drop the original request
frame. The relevant STA will not even know that such information was
ever requested.
This feature is a requirement for Hotspot 2.0, and is defined in IEEE
Std 802.11-2012, 10.23.13. While the Proxy ARP support code mainly
resides in the kernel bridge code, in order to optimize the performance
and simplify kernel implementation, the DHCP snooping code was added to
the hostapd.
Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
2014-09-26 07:32:55 +02:00
|
|
|
if (sta->ipaddr)
|
2014-11-06 01:15:46 +01:00
|
|
|
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
2014-11-01 07:33:41 +01:00
|
|
|
ap_sta_ip6addr_del(hapd, sta);
|
AP: Add support for Proxy ARP, DHCP snooping mechanism
Proxy ARP allows the AP devices to keep track of the hardware address to
IP address mapping of the STA devices within the BSS. When a request for
such information is made (i.e., ARP request, Neighbor Solicitation), the
AP will respond on behalf of the STA device within the BSS. Such
requests could originate from a device within the BSS or also from the
bridge. In the process of the AP replying to the request (i.e., ARP
reply, Neighbor Advertisement), the AP will drop the original request
frame. The relevant STA will not even know that such information was
ever requested.
This feature is a requirement for Hotspot 2.0, and is defined in IEEE
Std 802.11-2012, 10.23.13. While the Proxy ARP support code mainly
resides in the kernel bridge code, in order to optimize the performance
and simplify kernel implementation, the DHCP snooping code was added to
the hostapd.
Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
2014-09-26 07:32:55 +02:00
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2010-11-24 14:36:02 +01:00
|
|
|
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->flags & WLAN_STA_ASSOC) {
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
|
|
|
|
" from kernel driver",
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2008-02-28 02:34:43 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2016-02-16 10:54:32 +01:00
|
|
|
sta->added_unassoc = 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-06 21:30:25 +01:00
|
|
|
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
struct hostapd_iface *iface = hapd->iface;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < iface->num_bss; i++) {
|
|
|
|
struct hostapd_data *bss = iface->bss[i];
|
|
|
|
struct sta_info *sta2;
|
|
|
|
/* bss should always be set during operation, but it may be
|
|
|
|
* NULL during reconfiguration. Assume the STA is not
|
|
|
|
* associated to another BSS in that case to avoid NULL pointer
|
|
|
|
* dereferences. */
|
|
|
|
if (bss == hapd || bss == NULL)
|
|
|
|
continue;
|
|
|
|
sta2 = ap_get_sta(bss, sta->addr);
|
2010-03-06 21:30:25 +01:00
|
|
|
if (!sta2)
|
|
|
|
continue;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
|
|
|
|
" association from another BSS %s",
|
|
|
|
hapd->conf->iface, MAC2STR(sta2->addr),
|
|
|
|
bss->conf->iface);
|
2010-03-06 21:30:25 +01:00
|
|
|
ap_sta_disconnect(bss, sta2, sta2->addr,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-28 22:07:02 +02:00
|
|
|
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2011-08-28 22:07:02 +02:00
|
|
|
ap_sta_remove(hapd, sta);
|
|
|
|
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
u16 reason)
|
|
|
|
{
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2014-11-05 09:50:34 +01:00
|
|
|
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
2016-12-26 20:00:51 +01:00
|
|
|
if (hapd->iface->current_mode &&
|
|
|
|
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
|
|
|
/* Skip deauthentication in DMG/IEEE 802.11ad */
|
|
|
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
|
|
|
WLAN_STA_ASSOC_REQ_OK);
|
|
|
|
sta->timeout_next = STA_REMOVE;
|
|
|
|
} else {
|
|
|
|
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
|
|
|
sta->timeout_next = STA_DEAUTH;
|
|
|
|
}
|
2011-08-28 22:07:02 +02:00
|
|
|
ap_sta_set_authorized(hapd, sta, 0);
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%d seconds - "
|
|
|
|
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
|
|
|
|
__func__, MAC2STR(sta->addr),
|
|
|
|
AP_MAX_INACTIVITY_AFTER_DISASSOC);
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
|
|
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
|
|
|
ap_handle_timer, hapd, sta);
|
|
|
|
accounting_sta_stop(hapd, sta);
|
2015-12-31 20:46:08 +01:00
|
|
|
ieee802_1x_free_station(hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2011-08-28 22:07:02 +02:00
|
|
|
sta->disassoc_reason = reason;
|
2011-09-06 20:03:02 +02:00
|
|
|
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
2011-08-28 22:07:02 +02:00
|
|
|
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
|
|
|
eloop_register_timeout(hapd->iface->drv_flags &
|
|
|
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
|
|
|
ap_sta_disassoc_cb_timeout, hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2011-08-28 22:07:02 +02:00
|
|
|
ap_sta_remove(hapd, sta);
|
|
|
|
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
u16 reason)
|
|
|
|
{
|
2016-12-26 20:00:51 +01:00
|
|
|
if (hapd->iface->current_mode &&
|
|
|
|
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
|
|
|
/* Deauthentication is not used in DMG/IEEE 802.11ad;
|
|
|
|
* disassociate the STA instead. */
|
|
|
|
ap_sta_disassociate(hapd, sta, reason);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2014-11-05 09:50:34 +01:00
|
|
|
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
2014-11-29 12:31:54 +01:00
|
|
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
2011-08-28 22:07:02 +02:00
|
|
|
ap_sta_set_authorized(hapd, sta, 0);
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->timeout_next = STA_REMOVE;
|
2012-04-11 13:09:40 +02:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
|
|
|
"for " MACSTR " (%d seconds - "
|
|
|
|
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
|
|
|
|
__func__, MAC2STR(sta->addr),
|
|
|
|
AP_MAX_INACTIVITY_AFTER_DEAUTH);
|
2008-02-28 02:34:43 +01:00
|
|
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
|
|
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
|
|
|
ap_handle_timer, hapd, sta);
|
|
|
|
accounting_sta_stop(hapd, sta);
|
2015-12-31 20:46:08 +01:00
|
|
|
ieee802_1x_free_station(hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2011-08-28 22:07:02 +02:00
|
|
|
sta->deauth_reason = reason;
|
2011-09-06 20:03:02 +02:00
|
|
|
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
|
2011-08-28 22:07:02 +02:00
|
|
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
|
|
|
eloop_register_timeout(hapd->iface->drv_flags &
|
|
|
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
|
|
|
ap_sta_deauth_cb_timeout, hapd, sta);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-19 07:23:31 +01:00
|
|
|
#ifdef CONFIG_WPS
|
|
|
|
int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta, void *ctx)
|
|
|
|
{
|
|
|
|
if (sta && (sta->flags & WLAN_STA_WPS)) {
|
|
|
|
ap_sta_deauthenticate(hapd, sta,
|
|
|
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
|
|
|
wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
|
|
|
|
__func__, MAC2STR(sta->addr));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_WPS */
|
|
|
|
|
|
|
|
|
2016-01-21 14:51:57 +01:00
|
|
|
static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
|
|
|
|
{
|
|
|
|
struct hostapd_vlan *vlan;
|
|
|
|
int vlan_id = MAX_VLAN_ID + 2;
|
|
|
|
|
|
|
|
retry:
|
|
|
|
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
|
|
|
if (vlan->vlan_id == vlan_id) {
|
|
|
|
vlan_id++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return vlan_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-21 14:51:56 +01:00
|
|
|
int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
struct vlan_description *vlan_desc)
|
|
|
|
{
|
|
|
|
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
|
|
|
|
int old_vlan_id, vlan_id = 0, ret = 0;
|
|
|
|
|
2016-01-21 14:51:57 +01:00
|
|
|
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
2016-01-21 14:51:56 +01:00
|
|
|
vlan_desc = NULL;
|
|
|
|
|
2016-01-21 14:51:57 +01:00
|
|
|
/* Check if there is something to do */
|
2016-01-21 14:52:00 +01:00
|
|
|
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
|
|
|
|
/* This sta is lacking its own vif */
|
|
|
|
} else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
|
|
|
|
!hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
|
|
|
|
/* sta->vlan_id needs to be reset */
|
|
|
|
} else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
|
2016-01-21 14:51:57 +01:00
|
|
|
return 0; /* nothing to change */
|
2016-01-21 14:52:00 +01:00
|
|
|
}
|
2016-01-21 14:51:57 +01:00
|
|
|
|
|
|
|
/* Now the real VLAN changed or the STA just needs its own vif */
|
2016-01-21 14:52:00 +01:00
|
|
|
if (hapd->conf->ssid.per_sta_vif) {
|
|
|
|
/* Assign a new vif, always */
|
|
|
|
/* find a free vlan_id sufficiently big */
|
|
|
|
vlan_id = ap_sta_get_free_vlan_id(hapd);
|
|
|
|
/* Get wildcard VLAN */
|
|
|
|
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
|
|
|
if (vlan->vlan_id == VLAN_ID_WILDCARD)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!vlan) {
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
|
|
|
"per_sta_vif missing wildcard");
|
|
|
|
vlan_id = 0;
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else if (vlan_desc && vlan_desc->notempty) {
|
2016-01-21 14:51:56 +01:00
|
|
|
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
|
|
|
if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
|
|
|
|
break;
|
|
|
|
if (vlan->vlan_id == VLAN_ID_WILDCARD)
|
|
|
|
wildcard_vlan = vlan;
|
|
|
|
}
|
|
|
|
if (vlan) {
|
|
|
|
vlan_id = vlan->vlan_id;
|
|
|
|
} else if (wildcard_vlan) {
|
|
|
|
vlan = wildcard_vlan;
|
|
|
|
vlan_id = vlan_desc->untagged;
|
2016-01-21 14:51:57 +01:00
|
|
|
if (vlan_desc->tagged[0]) {
|
|
|
|
/* Tagged VLAN configuration */
|
|
|
|
vlan_id = ap_sta_get_free_vlan_id(hapd);
|
|
|
|
}
|
2016-01-21 14:51:56 +01:00
|
|
|
} else {
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
2016-01-21 14:51:57 +01:00
|
|
|
"missing vlan and wildcard for vlan=%d%s",
|
|
|
|
vlan_desc->untagged,
|
|
|
|
vlan_desc->tagged[0] ? "+" : "");
|
2016-01-21 14:51:56 +01:00
|
|
|
vlan_id = 0;
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
|
|
|
vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
|
|
|
|
if (vlan == NULL) {
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
2016-01-21 14:51:57 +01:00
|
|
|
"could not add dynamic VLAN interface for vlan=%d%s",
|
2016-02-20 18:22:43 +01:00
|
|
|
vlan_desc ? vlan_desc->untagged : -1,
|
|
|
|
(vlan_desc && vlan_desc->tagged[0]) ?
|
|
|
|
"+" : "");
|
2016-01-21 14:51:56 +01:00
|
|
|
vlan_id = 0;
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
|
|
|
"added new dynamic VLAN interface '%s'",
|
|
|
|
vlan->ifname);
|
|
|
|
} else if (vlan && vlan->dynamic_vlan > 0) {
|
|
|
|
vlan->dynamic_vlan++;
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
|
|
|
"updated existing dynamic VLAN interface '%s'",
|
|
|
|
vlan->ifname);
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
old_vlan_id = sta->vlan_id;
|
|
|
|
sta->vlan_id = vlan_id;
|
|
|
|
sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
|
|
|
|
|
|
|
|
if (vlan_id != old_vlan_id && old_vlan_id)
|
|
|
|
vlan_remove_dynamic(hapd, old_vlan_id);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
2009-01-12 20:39:19 +01:00
|
|
|
#ifndef CONFIG_NO_VLAN
|
2008-02-28 02:34:43 +01:00
|
|
|
const char *iface;
|
|
|
|
struct hostapd_vlan *vlan = NULL;
|
2010-04-15 22:44:10 +02:00
|
|
|
int ret;
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
int old_vlanid = sta->vlan_id_bound;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
iface = hapd->conf->iface;
|
2015-04-20 23:33:25 +02:00
|
|
|
if (hapd->conf->ssid.vlan[0])
|
|
|
|
iface = hapd->conf->ssid.vlan;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2016-01-21 14:51:56 +01:00
|
|
|
if (sta->vlan_id > 0) {
|
|
|
|
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
2013-08-04 20:45:50 +02:00
|
|
|
if (vlan->vlan_id == sta->vlan_id)
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-04 20:45:50 +02:00
|
|
|
if (vlan)
|
|
|
|
iface = vlan->ifname;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
/*
|
|
|
|
* Do not increment ref counters if the VLAN ID remains same, but do
|
|
|
|
* not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
|
|
|
|
* have been called before.
|
|
|
|
*/
|
|
|
|
if (sta->vlan_id == old_vlanid)
|
|
|
|
goto skip_counting;
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (sta->vlan_id > 0 && vlan == NULL) {
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
|
|
|
|
"binding station to (vlan_id=%d)",
|
|
|
|
sta->vlan_id);
|
2015-01-30 00:09:51 +01:00
|
|
|
ret = -1;
|
|
|
|
goto done;
|
2016-01-21 14:51:56 +01:00
|
|
|
} else if (vlan && vlan->dynamic_vlan > 0) {
|
2015-10-05 16:14:27 +02:00
|
|
|
vlan->dynamic_vlan++;
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
|
|
|
"updated existing dynamic VLAN interface '%s'",
|
|
|
|
iface);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
/* ref counters have been increased, so mark the station */
|
|
|
|
sta->vlan_id_bound = sta->vlan_id;
|
|
|
|
|
|
|
|
skip_counting:
|
2008-02-28 02:34:43 +01:00
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
|
|
|
|
"'%s'", iface);
|
|
|
|
|
|
|
|
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
|
|
|
|
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
|
|
|
|
|
2010-11-24 14:36:02 +01:00
|
|
|
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
|
2010-04-15 22:44:10 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
|
|
|
|
"entry to vlan_id=%d", sta->vlan_id);
|
|
|
|
}
|
2015-01-30 00:09:51 +01:00
|
|
|
|
|
|
|
/* During 1x reauth, if the vlan id changes, then remove the old id. */
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
|
2015-01-30 00:09:51 +01:00
|
|
|
vlan_remove_dynamic(hapd, old_vlanid);
|
Remove VLAN interface on STA free
Currently, vlan_remove_dynamic() is only called when the station VLAN ID
is changed (ap_sta_bind_vlan), but not when the station is freed. So
dynamic VLAN interfaces are not removed actually except within 1x
reauthentification VLAN ID change, although most of the code is already
there.
This patch fixes this by calling vlan_remove_dynamic() in ap_free_sta().
It cannot just use sta->vlan_id for this, as this might have been
changed without calling ap_sta_bind_vlan() (ap/ieee802_11.c:handle_auth
fetches from RADIUS cache for WPA-PSK), thus reference counting might
not have been updated. Additionally, reference counting might get wrong
due to old_vlanid = 0 being passed unconditionally, thus increasing the
reference counter multiple times.
So tracking the currently assigned (i.e., dynamic_vlan counter
increased) VLAN is done in a new variable sta->vlan_id_bound. Therefore,
the old_vlan_id argument of ap_sta_bind_vlan() is no longer needed and
setting the VLAN for the sta in driver happens unconditionally.
Additionally, vlan->dynamic_vlan is only incremented when it actually
is a dynamic VLAN.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
2015-04-10 14:49:50 +02:00
|
|
|
done:
|
2015-01-30 00:09:51 +01:00
|
|
|
|
2010-04-15 22:44:10 +02:00
|
|
|
return ret;
|
2009-01-12 20:39:19 +01:00
|
|
|
#else /* CONFIG_NO_VLAN */
|
|
|
|
return 0;
|
|
|
|
#endif /* CONFIG_NO_VLAN */
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2008-08-31 10:04:47 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
|
|
|
2008-12-26 11:30:34 +01:00
|
|
|
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
|
2008-08-31 10:04:47 +02:00
|
|
|
{
|
2008-12-26 11:30:34 +01:00
|
|
|
u32 tu;
|
2013-11-25 21:56:09 +01:00
|
|
|
struct os_reltime now, passed;
|
|
|
|
os_get_reltime(&now);
|
|
|
|
os_reltime_sub(&now, &sta->sa_query_start, &passed);
|
2008-12-26 11:30:34 +01:00
|
|
|
tu = (passed.sec * 1000000 + passed.usec) / 1024;
|
|
|
|
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
2008-08-31 10:04:47 +02:00
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
2008-12-26 10:46:21 +01:00
|
|
|
"association SA Query timed out");
|
|
|
|
sta->sa_query_timed_out = 1;
|
|
|
|
os_free(sta->sa_query_trans_id);
|
|
|
|
sta->sa_query_trans_id = NULL;
|
|
|
|
sta->sa_query_count = 0;
|
2008-12-26 11:30:34 +01:00
|
|
|
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
|
|
|
|
return 1;
|
2008-08-31 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
2008-12-26 11:30:34 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
unsigned int timeout, sec, usec;
|
|
|
|
u8 *trans_id, *nbuf;
|
|
|
|
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
|
|
|
|
" (count=%d)",
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
|
|
|
|
|
2008-12-26 11:30:34 +01:00
|
|
|
if (sta->sa_query_count > 0 &&
|
|
|
|
ap_check_sa_query_timeout(hapd, sta))
|
|
|
|
return;
|
|
|
|
|
2012-08-13 20:21:23 +02:00
|
|
|
nbuf = os_realloc_array(sta->sa_query_trans_id,
|
|
|
|
sta->sa_query_count + 1,
|
|
|
|
WLAN_SA_QUERY_TR_ID_LEN);
|
2008-08-31 10:04:47 +02:00
|
|
|
if (nbuf == NULL)
|
|
|
|
return;
|
2008-12-26 11:30:34 +01:00
|
|
|
if (sta->sa_query_count == 0) {
|
|
|
|
/* Starting a new SA Query procedure */
|
2013-11-25 21:56:09 +01:00
|
|
|
os_get_reltime(&sta->sa_query_start);
|
2008-12-26 11:30:34 +01:00
|
|
|
}
|
2008-12-26 10:46:21 +01:00
|
|
|
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
|
|
|
|
sta->sa_query_trans_id = nbuf;
|
|
|
|
sta->sa_query_count++;
|
2008-08-31 10:04:47 +02:00
|
|
|
|
2014-10-11 18:38:45 +02:00
|
|
|
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
|
|
|
|
/*
|
|
|
|
* We don't really care which ID is used here, so simply
|
|
|
|
* hardcode this if the mostly theoretical os_get_random()
|
|
|
|
* failure happens.
|
|
|
|
*/
|
|
|
|
trans_id[0] = 0x12;
|
|
|
|
trans_id[1] = 0x34;
|
|
|
|
}
|
2008-08-31 10:04:47 +02:00
|
|
|
|
2008-12-26 11:30:34 +01:00
|
|
|
timeout = hapd->conf->assoc_sa_query_retry_timeout;
|
|
|
|
sec = ((timeout / 1000) * 1024) / 1000;
|
|
|
|
usec = (timeout % 1000) * 1024;
|
|
|
|
eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
|
|
|
|
|
2008-08-31 10:04:47 +02:00
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG,
|
2008-12-26 10:46:21 +01:00
|
|
|
"association SA Query attempt %d", sta->sa_query_count);
|
2008-08-31 10:04:47 +02:00
|
|
|
|
2008-12-26 10:46:21 +01:00
|
|
|
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
|
2008-08-31 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-26 10:46:21 +01:00
|
|
|
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
|
2008-08-31 10:04:47 +02:00
|
|
|
{
|
2008-12-26 10:46:21 +01:00
|
|
|
ap_sa_query_timer(hapd, sta);
|
2008-08-31 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-26 10:46:21 +01:00
|
|
|
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
|
2008-08-31 10:04:47 +02:00
|
|
|
{
|
2008-12-26 10:46:21 +01:00
|
|
|
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
|
|
|
|
os_free(sta->sa_query_trans_id);
|
|
|
|
sta->sa_query_trans_id = NULL;
|
|
|
|
sta->sa_query_count = 0;
|
2008-08-31 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_IEEE80211W */
|
2009-12-24 19:41:30 +01:00
|
|
|
|
|
|
|
|
2011-02-02 15:52:32 +01:00
|
|
|
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
int authorized)
|
|
|
|
{
|
2011-12-10 11:26:00 +01:00
|
|
|
const u8 *dev_addr = NULL;
|
2013-05-18 18:09:41 +02:00
|
|
|
char buf[100];
|
2012-06-17 10:58:46 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
u8 addr[ETH_ALEN];
|
2013-03-16 18:13:31 +01:00
|
|
|
u8 ip_addr_buf[4];
|
2012-06-17 10:58:46 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
2011-02-02 15:52:32 +01:00
|
|
|
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
|
|
|
|
return;
|
|
|
|
|
2014-10-01 14:36:53 +02:00
|
|
|
if (authorized)
|
|
|
|
sta->flags |= WLAN_STA_AUTHORIZED;
|
|
|
|
else
|
|
|
|
sta->flags &= ~WLAN_STA_AUTHORIZED;
|
|
|
|
|
2011-11-03 21:17:41 +01:00
|
|
|
#ifdef CONFIG_P2P
|
2012-06-17 10:58:46 +02:00
|
|
|
if (hapd->p2p_group == NULL) {
|
|
|
|
if (sta->p2p_ie != NULL &&
|
|
|
|
p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
|
|
|
|
dev_addr = addr;
|
|
|
|
} else
|
|
|
|
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
|
2011-12-10 11:26:00 +01:00
|
|
|
|
2013-05-18 18:09:41 +02:00
|
|
|
if (dev_addr)
|
|
|
|
os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
|
|
|
|
MAC2STR(sta->addr), MAC2STR(dev_addr));
|
|
|
|
else
|
2014-09-23 09:08:30 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
2013-05-18 18:09:41 +02:00
|
|
|
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
|
|
|
|
|
2014-10-01 14:36:53 +02:00
|
|
|
if (hapd->sta_authorized_cb)
|
|
|
|
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
|
|
|
|
sta->addr, authorized, dev_addr);
|
|
|
|
|
2011-12-10 11:26:00 +01:00
|
|
|
if (authorized) {
|
2013-03-16 18:13:31 +01:00
|
|
|
char ip_addr[100];
|
|
|
|
ip_addr[0] = '\0';
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
|
|
|
|
os_snprintf(ip_addr, sizeof(ip_addr),
|
|
|
|
" ip_addr=%u.%u.%u.%u",
|
|
|
|
ip_addr_buf[0], ip_addr_buf[1],
|
|
|
|
ip_addr_buf[2], ip_addr_buf[3]);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
|
|
|
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
|
|
|
|
buf, ip_addr);
|
2013-05-18 18:09:41 +02:00
|
|
|
|
2011-07-22 00:19:46 +02:00
|
|
|
if (hapd->msg_ctx_parent &&
|
2013-05-18 18:09:41 +02:00
|
|
|
hapd->msg_ctx_parent != hapd->msg_ctx)
|
2013-05-18 18:18:31 +02:00
|
|
|
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
|
2013-03-16 18:13:31 +01:00
|
|
|
AP_STA_CONNECTED "%s%s",
|
|
|
|
buf, ip_addr);
|
2011-11-03 21:17:41 +01:00
|
|
|
} else {
|
2013-05-18 18:09:41 +02:00
|
|
|
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
|
|
|
|
|
2011-07-22 00:19:46 +02:00
|
|
|
if (hapd->msg_ctx_parent &&
|
2013-05-18 18:09:41 +02:00
|
|
|
hapd->msg_ctx_parent != hapd->msg_ctx)
|
2013-05-18 18:18:31 +02:00
|
|
|
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
|
|
|
|
AP_STA_DISCONNECTED "%s", buf);
|
2011-11-03 21:17:41 +01:00
|
|
|
}
|
2015-01-21 14:30:48 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_FST
|
|
|
|
if (hapd->iface->fst) {
|
|
|
|
if (authorized)
|
|
|
|
fst_notify_peer_connected(hapd->iface->fst, sta->addr);
|
|
|
|
else
|
|
|
|
fst_notify_peer_disconnected(hapd->iface->fst,
|
|
|
|
sta->addr);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_FST */
|
2011-02-02 15:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-24 19:41:30 +01:00
|
|
|
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
|
|
|
const u8 *addr, u16 reason)
|
|
|
|
{
|
2016-01-15 18:17:40 +01:00
|
|
|
if (sta)
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
|
|
|
|
hapd->conf->iface, __func__, MAC2STR(sta->addr),
|
|
|
|
reason);
|
|
|
|
else if (addr)
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
|
|
|
|
hapd->conf->iface, __func__, MAC2STR(addr),
|
|
|
|
reason);
|
2009-12-24 19:41:30 +01:00
|
|
|
|
|
|
|
if (sta == NULL && addr)
|
|
|
|
sta = ap_get_sta(hapd, addr);
|
|
|
|
|
|
|
|
if (addr)
|
2010-11-24 14:36:02 +01:00
|
|
|
hostapd_drv_sta_deauth(hapd, addr, reason);
|
2009-12-24 19:41:30 +01:00
|
|
|
|
|
|
|
if (sta == NULL)
|
|
|
|
return;
|
2011-02-02 15:52:32 +01:00
|
|
|
ap_sta_set_authorized(hapd, sta, 0);
|
2012-01-25 21:32:58 +01:00
|
|
|
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
|
|
|
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
2011-02-02 15:52:32 +01:00
|
|
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
2016-01-15 18:17:40 +01:00
|
|
|
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
|
2012-04-11 13:09:40 +02:00
|
|
|
"for " MACSTR " (%d seconds - "
|
|
|
|
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
|
2016-01-15 18:17:40 +01:00
|
|
|
hapd->conf->iface, __func__, MAC2STR(sta->addr),
|
2012-04-11 13:09:40 +02:00
|
|
|
AP_MAX_INACTIVITY_AFTER_DEAUTH);
|
2009-12-24 19:41:30 +01:00
|
|
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
2011-08-28 22:07:02 +02:00
|
|
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
|
|
|
ap_handle_timer, hapd, sta);
|
2009-12-24 19:41:30 +01:00
|
|
|
sta->timeout_next = STA_REMOVE;
|
2011-08-28 22:07:02 +02:00
|
|
|
|
2016-12-26 20:00:51 +01:00
|
|
|
if (hapd->iface->current_mode &&
|
|
|
|
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
|
|
|
/* Deauthentication is not used in DMG/IEEE 802.11ad;
|
|
|
|
* disassociate the STA instead. */
|
|
|
|
sta->disassoc_reason = reason;
|
|
|
|
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
|
|
|
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
|
|
|
eloop_register_timeout(hapd->iface->drv_flags &
|
|
|
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
|
|
|
|
2 : 0, 0, ap_sta_disassoc_cb_timeout,
|
|
|
|
hapd, sta);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-28 22:07:02 +02:00
|
|
|
sta->deauth_reason = reason;
|
2011-09-06 20:03:02 +02:00
|
|
|
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
|
2011-08-28 22:07:02 +02:00
|
|
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
|
|
|
eloop_register_timeout(hapd->iface->drv_flags &
|
|
|
|
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
|
|
|
|
ap_sta_deauth_cb_timeout, hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
2011-09-06 20:03:02 +02:00
|
|
|
if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
|
2011-08-28 22:07:02 +02:00
|
|
|
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
|
|
|
ap_sta_deauth_cb_timeout(hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
|
|
|
|
{
|
2011-09-06 20:03:02 +02:00
|
|
|
if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
|
|
|
|
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
|
|
|
ap_sta_disassoc_cb_timeout(hapd, sta);
|
2009-12-24 19:41:30 +01:00
|
|
|
}
|
2013-12-27 18:24:24 +01:00
|
|
|
|
|
|
|
|
2016-01-15 18:28:58 +01:00
|
|
|
void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta)
|
|
|
|
{
|
|
|
|
if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"%s: Removed ap_sta_deauth_cb_timeout timeout for "
|
|
|
|
MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
|
|
|
if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"%s: Removed ap_sta_disassoc_cb_timeout timeout for "
|
|
|
|
MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
2016-12-06 17:12:11 +01:00
|
|
|
if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
|
|
|
|
{
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
|
|
"%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
|
|
|
|
MACSTR,
|
|
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
|
|
|
if (sta->flags & WLAN_STA_WPS)
|
|
|
|
hostapd_wps_eap_completed(hapd);
|
|
|
|
}
|
2016-01-15 18:28:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-27 18:24:24 +01:00
|
|
|
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
2014-11-10 16:12:29 +01:00
|
|
|
res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
2013-12-27 18:24:24 +01:00
|
|
|
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
|
|
|
|
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
|
|
|
|
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
|
|
|
|
(flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
|
|
|
|
""),
|
|
|
|
(flags & WLAN_STA_SHORT_PREAMBLE ?
|
|
|
|
"[SHORT_PREAMBLE]" : ""),
|
|
|
|
(flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
|
|
|
|
(flags & WLAN_STA_WMM ? "[WMM]" : ""),
|
|
|
|
(flags & WLAN_STA_MFP ? "[MFP]" : ""),
|
|
|
|
(flags & WLAN_STA_WPS ? "[WPS]" : ""),
|
|
|
|
(flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
|
|
|
|
(flags & WLAN_STA_WDS ? "[WDS]" : ""),
|
|
|
|
(flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
|
|
|
|
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
|
|
|
|
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
|
|
|
|
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
|
2014-11-10 16:12:29 +01:00
|
|
|
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
|
2013-12-27 18:24:24 +01:00
|
|
|
(flags & WLAN_STA_WNM_SLEEP_MODE ?
|
|
|
|
"[WNM_SLEEP_MODE]" : ""));
|
2014-12-07 14:45:02 +01:00
|
|
|
if (os_snprintf_error(buflen, res))
|
|
|
|
res = -1;
|
2013-12-27 18:24:24 +01:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
2016-12-06 17:12:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
|
|
|
|
{
|
|
|
|
struct hostapd_data *hapd = eloop_ctx;
|
|
|
|
struct sta_info *sta = timeout_ctx;
|
|
|
|
|
|
|
|
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"IEEE 802.1X: Scheduled disconnection of " MACSTR
|
|
|
|
" after EAP-Failure", MAC2STR(sta->addr));
|
|
|
|
|
|
|
|
ap_sta_disconnect(hapd, sta, sta->addr,
|
|
|
|
WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
|
|
|
|
if (sta->flags & WLAN_STA_WPS)
|
|
|
|
hostapd_wps_eap_completed(hapd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta)
|
|
|
|
{
|
|
|
|
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
|
|
|
"IEEE 802.1X: Force disconnection of " MACSTR
|
|
|
|
" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add a small sleep to increase likelihood of previously requested
|
|
|
|
* EAP-Failure TX getting out before this should the driver reorder
|
|
|
|
* operations.
|
|
|
|
*/
|
|
|
|
eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
|
|
|
|
eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
|
|
|
|
hapd, sta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
|
|
|
struct sta_info *sta)
|
|
|
|
{
|
|
|
|
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
|
|
|
|
hapd, sta);
|
|
|
|
}
|