2008-02-28 02:34:43 +01:00
|
|
|
/*
|
|
|
|
* hostapd / Station table
|
2013-09-01 16:37:22 +02:00
|
|
|
* Copyright (c) 2002-2013, 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"
|
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"
|
2014-11-01 07:33:41 +01:00
|
|
|
#include "ndisc_snoop.h"
|
2009-12-25 23:05:40 +01:00
|
|
|
#include "sta_info.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);
|
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 &&
|
|
|
|
!(sta->flags & WLAN_STA_PREAUTH))
|
2010-11-24 14:36:02 +01:00
|
|
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
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
|
|
|
|
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)
|
|
|
|
hapd->mesh_sta_free_cb(sta);
|
|
|
|
#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.
|
|
|
|
*/
|
|
|
|
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 */
|
|
|
|
|
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 */
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_WNM
|
|
|
|
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);
|
|
|
|
#endif /* CONFIG_WNM */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
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;
|
2013-03-16 11:35:49 +01:00
|
|
|
sta->flags &= ~(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_DEAUTH;
|
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)
|
|
|
|
{
|
|
|
|
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 */
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2015-04-20 23:33:25 +02:00
|
|
|
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
2008-02-28 02:34:43 +01:00
|
|
|
sta->vlan_id = 0;
|
|
|
|
else if (sta->vlan_id > 0) {
|
2013-08-04 20:45:50 +02:00
|
|
|
struct hostapd_vlan *wildcard_vlan = NULL;
|
2008-02-28 02:34:43 +01:00
|
|
|
vlan = hapd->conf->vlan;
|
|
|
|
while (vlan) {
|
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->vlan_id == VLAN_ID_WILDCARD)
|
|
|
|
wildcard_vlan = vlan;
|
2008-02-28 02:34:43 +01:00
|
|
|
vlan = vlan->next;
|
|
|
|
}
|
2013-08-04 20:45:50 +02:00
|
|
|
if (!vlan)
|
|
|
|
vlan = wildcard_vlan;
|
|
|
|
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;
|
2008-02-28 02:34:43 +01:00
|
|
|
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
|
|
|
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
|
|
|
|
if (vlan == NULL) {
|
|
|
|
hostapd_logger(hapd, sta->addr,
|
|
|
|
HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "could not add "
|
|
|
|
"dynamic VLAN interface for vlan_id=%d",
|
|
|
|
sta->vlan_id);
|
2015-01-30 00:09:51 +01:00
|
|
|
ret = -1;
|
|
|
|
goto done;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
iface = vlan->ifname;
|
|
|
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
|
|
|
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
|
|
|
|
"interface '%s'", iface);
|
2015-10-05 16:14:27 +02:00
|
|
|
} else if (vlan && vlan->vlan_id == sta->vlan_id &&
|
|
|
|
vlan->dynamic_vlan > 0) {
|
|
|
|
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
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|