From ec8f36afca731aa6a30a314c54bb83441180719d Mon Sep 17 00:00:00 2001 From: Kyeyoon Park Date: Wed, 15 Oct 2014 16:36:04 -0700 Subject: [PATCH] AP: Add support for BSS load element (STA Count, Channel Utilization) The new "bss_load_update_period" parameter can be used to configure hostapd to advertise its BSS Load element in Beacon and Probe Response frames. This parameter is in the units of BUs (Beacon Units). When enabled, the STA Count and the Channel Utilization value will be updated periodically in the BSS Load element. The AAC is set to 0 sinze explicit admission control is not supported. Channel Utilization is calculated based on the channel survey information from the driver and as such, requires a driver that supports providing that information for the current operating channel. Signed-off-by: Kyeyoon Park --- hostapd/Android.mk | 1 + hostapd/Makefile | 1 + hostapd/config_file.c | 9 ++++++ hostapd/hostapd.conf | 5 +++ src/ap/ap_config.h | 1 + src/ap/beacon.c | 15 +++++++-- src/ap/bss_load.c | 65 +++++++++++++++++++++++++++++++++++++++ src/ap/bss_load.h | 17 ++++++++++ src/ap/drv_callbacks.c | 41 ++++++++++++++++++++++++ src/ap/hostapd.c | 8 +++++ src/ap/hostapd.h | 8 +++++ wpa_supplicant/Android.mk | 1 + wpa_supplicant/Makefile | 1 + 13 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 src/ap/bss_load.c create mode 100644 src/ap/bss_load.h diff --git a/hostapd/Android.mk b/hostapd/Android.mk index edaf6fc8e..84a877819 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -95,6 +95,7 @@ OBJS += src/ap/preauth_auth.c OBJS += src/ap/pmksa_cache_auth.c OBJS += src/ap/ieee802_11_shared.c OBJS += src/ap/beacon.c +OBJS += src/ap/bss_load.c OBJS_d = OBJS_p = LIBS = diff --git a/hostapd/Makefile b/hostapd/Makefile index ac6373e6c..dc5eacdb7 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -59,6 +59,7 @@ OBJS += ../src/ap/preauth_auth.o OBJS += ../src/ap/pmksa_cache_auth.o OBJS += ../src/ap/ieee802_11_shared.o OBJS += ../src/ap/beacon.o +OBJS += ../src/ap/bss_load.o OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o diff --git a/hostapd/config_file.c b/hostapd/config_file.c index d4ba7cc0c..ddebf1f46 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2489,6 +2489,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, bss->dtim_period); return 1; } + } else if (os_strcmp(buf, "bss_load_update_period") == 0) { + bss->bss_load_update_period = atoi(pos); + if (bss->bss_load_update_period < 0 || + bss->bss_load_update_period > 100) { + wpa_printf(MSG_ERROR, + "Line %d: invalid bss_load_update_period %d", + line, bss->bss_load_update_period); + return 1; + } } else if (os_strcmp(buf, "rts_threshold") == 0) { conf->rts_threshold = atoi(pos); if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index d4e5bf0af..2e6f841bf 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -435,6 +435,11 @@ wmm_ac_vo_acm=0 # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 +# BSS Load update period (in BUs) +# This field is used to enable and configure adding a BSS Load element into +# Beacon and Probe Response frames. +#bss_load_update_period=50 + # Fixed BSS Load value for testing purposes # This field can be used to configure hostapd to add a fixed BSS Load element # into Beacon and Probe Response frames for testing purposes. The format is diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index e37a79659..b693664e4 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -196,6 +196,7 @@ struct hostapd_bss_config { int max_num_sta; /* maximum number of STAs in station table */ int dtim_period; + int bss_load_update_period; int ieee802_1x; /* use IEEE 802.1X */ int eapol_version; diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 4cae0d993..22aef9f60 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -34,16 +34,27 @@ static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) { + if (len < 2 + 5) + return eid; + #ifdef CONFIG_TESTING_OPTIONS if (hapd->conf->bss_load_test_set) { - if (2 + 5 > len) - return eid; *eid++ = WLAN_EID_BSS_LOAD; *eid++ = 5; os_memcpy(eid, hapd->conf->bss_load_test, 5); eid += 5; + return eid; } #endif /* CONFIG_TESTING_OPTIONS */ + if (hapd->conf->bss_load_update_period) { + *eid++ = WLAN_EID_BSS_LOAD; + *eid++ = 5; + WPA_PUT_LE16(eid, hapd->num_sta); + eid += 2; + *eid++ = hapd->iface->channel_utilization; + WPA_PUT_LE16(eid, 0); /* no available admission capabity */ + eid += 2; + } return eid; } diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c new file mode 100644 index 000000000..fb6394232 --- /dev/null +++ b/src/ap/bss_load.c @@ -0,0 +1,65 @@ +/* + * BSS Load Element / Channel Utilization + * Copyright (c) 2014, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "hostapd.h" +#include "bss_load.h" +#include "ap_drv_ops.h" +#include "beacon.h" + + +static void update_channel_utilization(void *eloop_data, void *user_data) +{ + struct hostapd_data *hapd = eloop_data; + unsigned int sec, usec; + int err; + + if (!(hapd->beacon_set_done && hapd->started)) + return; + + err = hostapd_drv_get_survey(hapd, hapd->iface->freq); + if (err) { + wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data"); + return; + } + + ieee802_11_set_beacon(hapd); + + sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000; + usec = (hapd->bss_load_update_timeout % 1000) * 1024; + eloop_register_timeout(sec, usec, update_channel_utilization, hapd, + NULL); +} + + +int bss_load_update_init(struct hostapd_data *hapd) +{ + struct hostapd_bss_config *conf = hapd->conf; + struct hostapd_config *iconf = hapd->iconf; + unsigned int sec, usec; + + if (!conf->bss_load_update_period || !iconf->beacon_int) + return -1; + + hapd->bss_load_update_timeout = conf->bss_load_update_period * + iconf->beacon_int; + sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000; + usec = (hapd->bss_load_update_timeout % 1000) * 1024; + eloop_register_timeout(sec, usec, update_channel_utilization, hapd, + NULL); + return 0; +} + + +void bss_load_update_deinit(struct hostapd_data *hapd) +{ + eloop_cancel_timeout(update_channel_utilization, hapd, NULL); +} diff --git a/src/ap/bss_load.h b/src/ap/bss_load.h new file mode 100644 index 000000000..ac3c793c9 --- /dev/null +++ b/src/ap/bss_load.h @@ -0,0 +1,17 @@ +/* + * BSS load update + * Copyright (c) 2014, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BSS_LOAD_UPDATE_H +#define BSS_LOAD_UPDATE_H + + +int bss_load_update_init(struct hostapd_data *hapd); +void bss_load_update_deinit(struct hostapd_data *hapd); + + +#endif /* BSS_LOAD_UPDATE_H */ diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 3bde7205d..9beb32245 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -858,6 +858,42 @@ static void hostapd_update_nf(struct hostapd_iface *iface, } +static void hostapd_single_channel_get_survey(struct hostapd_iface *iface, + struct survey_results *survey_res) +{ + struct hostapd_channel_data *chan; + struct freq_survey *survey; + u64 divisor, dividend; + + survey = dl_list_first(&survey_res->survey_list, struct freq_survey, + list); + if (!survey || !survey->freq) + return; + + chan = hostapd_get_mode_channel(iface, survey->freq); + if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) + return; + + wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", + survey->freq, + (unsigned long int) survey->channel_time, + (unsigned long int) survey->channel_time_busy); + + if (survey->channel_time > iface->last_channel_time && + survey->channel_time > survey->channel_time_busy) { + dividend = survey->channel_time_busy - + iface->last_channel_time_busy; + divisor = survey->channel_time - iface->last_channel_time; + + iface->channel_utilization = dividend * 255 / divisor; + wpa_printf(MSG_DEBUG, "Channel Utilization: %d", + iface->channel_utilization); + } + iface->last_channel_time = survey->channel_time; + iface->last_channel_time_busy = survey->channel_time_busy; +} + + static void hostapd_event_get_survey(struct hostapd_data *hapd, struct survey_results *survey_results) { @@ -870,6 +906,11 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd, return; } + if (survey_results->freq_filter) { + hostapd_single_channel_get_survey(iface, survey_results); + return; + } + dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, struct freq_survey, list) { chan = hostapd_get_mode_channel(iface, survey->freq); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 764722f96..be7dfd8cc 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -35,6 +35,7 @@ #include "gas_serv.h" #include "dfs.h" #include "ieee802_11.h" +#include "bss_load.h" static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); @@ -310,6 +311,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd) gas_serv_deinit(hapd); #endif /* CONFIG_INTERWORKING */ + bss_load_update_deinit(hapd); + #ifdef CONFIG_SQLITE bin_clear_free(hapd->tmp_eap_user.identity, hapd->tmp_eap_user.identity_len); @@ -875,6 +878,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) } #endif /* CONFIG_INTERWORKING */ + if (conf->bss_load_update_period && bss_load_update_init(hapd)) { + wpa_printf(MSG_ERROR, "BSS Load initialization failed"); + return -1; + } + if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { wpa_printf(MSG_ERROR, "VLAN initialization failed."); return -1; diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index ca01a688e..50ebe0eff 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -218,6 +218,9 @@ struct hostapd_data { unsigned int cs_c_off_proberesp; int csa_in_progress; + /* BSS Load */ + unsigned int bss_load_update_timeout; + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -354,6 +357,11 @@ struct hostapd_iface { /* lowest observed noise floor in dBm */ s8 lowest_nf; + /* channel utilization calculation */ + u64 last_channel_time; + u64 last_channel_time_busy; + u8 channel_utilization; + unsigned int dfs_cac_ms; struct os_reltime dfs_cac_start; diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 8b7df6c77..7d1bb9eae 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -767,6 +767,7 @@ OBJS += src/ap/ieee802_11_shared.c OBJS += src/ap/drv_callbacks.c OBJS += src/ap/ap_drv_ops.c OBJS += src/ap/beacon.c +OBJS += src/ap/bss_load.c OBJS += src/ap/eap_user_db.c ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 7eee73a9d..6556ec48a 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -782,6 +782,7 @@ OBJS += ../src/ap/ieee802_11_shared.o OBJS += ../src/ap/drv_callbacks.o OBJS += ../src/ap/ap_drv_ops.o OBJS += ../src/ap/beacon.o +OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/eap_user_db.o ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o