1281681Srpaulo/*
2281681Srpaulo * BSS Load Element / Channel Utilization
3281681Srpaulo * Copyright (c) 2014, Qualcomm Atheros, Inc.
4281681Srpaulo *
5281681Srpaulo * This software may be distributed under the terms of the BSD license.
6281681Srpaulo * See README for more details.
7281681Srpaulo */
8281681Srpaulo
9281681Srpaulo#include "utils/includes.h"
10281681Srpaulo
11281681Srpaulo#include "utils/common.h"
12281681Srpaulo#include "utils/eloop.h"
13281681Srpaulo#include "hostapd.h"
14281681Srpaulo#include "bss_load.h"
15281681Srpaulo#include "ap_drv_ops.h"
16281681Srpaulo#include "beacon.h"
17281681Srpaulo
18281681Srpaulo
19346981Scystatic int get_bss_load_update_timeout(struct hostapd_data *hapd,
20346981Scy				       unsigned int *sec, unsigned int *usec)
21346981Scy{
22346981Scy	unsigned int update_period = hapd->conf->bss_load_update_period;
23346981Scy	unsigned int beacon_int = hapd->iconf->beacon_int;
24346981Scy	unsigned int update_timeout;
25346981Scy
26346981Scy	if (!update_period || !beacon_int) {
27346981Scy		wpa_printf(MSG_ERROR,
28346981Scy			   "BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
29346981Scy			   update_period, beacon_int);
30346981Scy		return -1;
31346981Scy	}
32346981Scy
33346981Scy	update_timeout = update_period * beacon_int;
34346981Scy
35346981Scy	*sec = ((update_timeout / 1000) * 1024) / 1000;
36346981Scy	*usec = (update_timeout % 1000) * 1024;
37346981Scy
38346981Scy	return 0;
39346981Scy}
40346981Scy
41346981Scy
42281681Srpaulostatic void update_channel_utilization(void *eloop_data, void *user_data)
43281681Srpaulo{
44281681Srpaulo	struct hostapd_data *hapd = eloop_data;
45281681Srpaulo	unsigned int sec, usec;
46281681Srpaulo	int err;
47346981Scy	struct hostapd_iface *iface = hapd->iface;
48281681Srpaulo
49281681Srpaulo	if (!(hapd->beacon_set_done && hapd->started))
50281681Srpaulo		return;
51281681Srpaulo
52281681Srpaulo	err = hostapd_drv_get_survey(hapd, hapd->iface->freq);
53281681Srpaulo	if (err) {
54281681Srpaulo		wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data");
55281681Srpaulo		return;
56281681Srpaulo	}
57281681Srpaulo
58281681Srpaulo	ieee802_11_set_beacon(hapd);
59281681Srpaulo
60346981Scy	if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
61346981Scy		return;
62346981Scy
63346981Scy	if (hapd->conf->chan_util_avg_period) {
64346981Scy		iface->chan_util_samples_sum += iface->channel_utilization;
65346981Scy		iface->chan_util_num_sample_periods +=
66346981Scy			hapd->conf->bss_load_update_period;
67346981Scy		if (iface->chan_util_num_sample_periods >=
68346981Scy		    hapd->conf->chan_util_avg_period) {
69346981Scy			iface->chan_util_average =
70346981Scy				iface->chan_util_samples_sum /
71346981Scy				(iface->chan_util_num_sample_periods /
72346981Scy				 hapd->conf->bss_load_update_period);
73346981Scy			iface->chan_util_samples_sum = 0;
74346981Scy			iface->chan_util_num_sample_periods = 0;
75346981Scy		}
76346981Scy	}
77346981Scy
78281681Srpaulo	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
79281681Srpaulo			       NULL);
80281681Srpaulo}
81281681Srpaulo
82281681Srpaulo
83281681Srpauloint bss_load_update_init(struct hostapd_data *hapd)
84281681Srpaulo{
85281681Srpaulo	unsigned int sec, usec;
86281681Srpaulo
87346981Scy	if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
88281681Srpaulo		return -1;
89281681Srpaulo
90281681Srpaulo	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
91281681Srpaulo			       NULL);
92281681Srpaulo	return 0;
93281681Srpaulo}
94281681Srpaulo
95281681Srpaulo
96281681Srpaulovoid bss_load_update_deinit(struct hostapd_data *hapd)
97281681Srpaulo{
98281681Srpaulo	eloop_cancel_timeout(update_channel_utilization, hapd, NULL);
99281681Srpaulo}
100