aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2015-09-05 14:11:11 (GMT)
committerJouni Malinen <j@w1.fi>2015-09-05 14:11:11 (GMT)
commita65a9b8d677b5b3ed9a77f5fe3a3fa6bc34e5d32 (patch)
treeee3504b4fc463b37b130881a578351c12934b7c9 /src
parent6ebe816be00702904332744547180bdb27b126f3 (diff)
downloadhostap-a65a9b8d677b5b3ed9a77f5fe3a3fa6bc34e5d32.zip
hostap-a65a9b8d677b5b3ed9a77f5fe3a3fa6bc34e5d32.tar.gz
hostap-a65a9b8d677b5b3ed9a77f5fe3a3fa6bc34e5d32.tar.bz2
hostapd: Add mechanism to track unconnected stations
hostapd can now be configured to track unconnected stations based on Probe Request frames seen from them. This can be used, e.g., to detect dualband capable station before they have associated. Such information could then be used to provide guidance on which colocated BSS to use in case of a dualband AP that operates concurrently on multiple bands under the control of a single hostapd process. Signed-off-by: Jouni Malinen <j@w1.fi>
Diffstat (limited to 'src')
-rw-r--r--src/ap/ap_config.c1
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/beacon.c72
-rw-r--r--src/ap/beacon.h1
-rw-r--r--src/ap/hostapd.c18
-rw-r--r--src/ap/hostapd.h9
6 files changed, 104 insertions, 0 deletions
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 8727375..be2fa8b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -172,6 +172,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
+ conf->track_sta_max_age = 180;
#ifdef CONFIG_TESTING_OPTIONS
conf->ignore_probe_probability = 0.0;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c9a3764..3434214 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -586,6 +586,9 @@ struct hostapd_config {
int ap_table_max_size;
int ap_table_expiration_time;
+ unsigned int track_sta_max_num;
+ unsigned int track_sta_max_age;
+
char country[3]; /* first two octets: country code as described in
* ISO/IEC 3166-1. Third octet:
* ' ' (ascii 32): all environments
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 98d6832..46fff82 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -552,6 +552,76 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
}
+void sta_track_expire(struct hostapd_iface *iface, int force)
+{
+ struct os_reltime now;
+ struct hostapd_sta_info *info;
+
+ if (!iface->num_sta_seen)
+ return;
+
+ os_get_reltime(&now);
+ while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
+ list))) {
+ if (!force &&
+ !os_reltime_expired(&now, &info->last_seen,
+ iface->conf->track_sta_max_age))
+ break;
+ force = 0;
+
+ wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
+ MACSTR, iface->bss[0]->conf->iface,
+ MAC2STR(info->addr));
+ dl_list_del(&info->list);
+ iface->num_sta_seen--;
+ os_free(info);
+ }
+}
+
+
+static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
+ const u8 *addr)
+{
+ struct hostapd_sta_info *info;
+
+ dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
+ if (os_memcmp(addr, info->addr, ETH_ALEN) == 0)
+ return info;
+
+ return NULL;
+}
+
+
+static void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+{
+ struct hostapd_sta_info *info;
+
+ info = sta_track_get(iface, addr);
+ if (info) {
+ /* Move the most recent entry to the end of the list */
+ dl_list_del(&info->list);
+ dl_list_add_tail(&iface->sta_seen, &info->list);
+ os_get_reltime(&info->last_seen);
+ return;
+ }
+
+ /* Add a new entry */
+ info = os_zalloc(sizeof(*info));
+ os_memcpy(info->addr, addr, ETH_ALEN);
+ os_get_reltime(&info->last_seen);
+
+ if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
+ /* Expire oldest entry to make room for a new one */
+ sta_track_expire(iface, 1);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
+ MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
+ dl_list_add_tail(&iface->sta_seen, &info->list);
+ iface->num_sta_seen++;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -567,6 +637,8 @@ void handle_probe_req(struct hostapd_data *hapd,
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
return;
+ if (hapd->iconf->track_sta_max_num)
+ sta_track_add(hapd->iface, mgmt->sa);
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index 722159a..21df9fa 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -21,5 +21,6 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
+void sta_track_expire(struct hostapd_iface *iface, int force);
#endif /* BEACON_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cf8c93d..e4d7bfc 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -355,6 +355,22 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
}
+static void sta_track_deinit(struct hostapd_iface *iface)
+{
+ struct hostapd_sta_info *info;
+
+ if (!iface->num_sta_seen)
+ return;
+
+ while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
+ list))) {
+ dl_list_del(&info->list);
+ iface->num_sta_seen--;
+ os_free(info);
+ }
+}
+
+
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
@@ -370,6 +386,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
os_free(iface->basic_rates);
iface->basic_rates = NULL;
ap_list_deinit(iface);
+ sta_track_deinit(iface);
}
@@ -1623,6 +1640,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_tx_queue_params(iface);
ap_list_init(iface);
+ dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 89a1e8b..dcf51f0 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -281,6 +281,12 @@ struct hostapd_data {
};
+struct hostapd_sta_info {
+ struct dl_list list;
+ u8 addr[ETH_ALEN];
+ struct os_reltime last_seen;
+};
+
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
@@ -409,6 +415,9 @@ struct hostapd_iface {
void (*scan_cb)(struct hostapd_iface *iface);
int num_ht40_scan_tries;
+
+ struct dl_list sta_seen; /* struct hostapd_sta_info */
+ unsigned int num_sta_seen;
};
/* hostapd.c */