[PATCH] mac80211: add QBSS load element to beacons
Arthur Léna
arthur at lena.im
Fri Aug 7 10:05:33 CEST 2015
The QBSS load element is specified in IEEE 802.11-2012 $8.4.2.30.
It is used to transmit population at a STA and a ratio of the
utilization of the operating channel. This implementation fills
the channel utilization field and the station count field. The
available admission capacity is always set to 0.
---
net/mac80211/ieee80211_i.h | 7 +++++
net/mac80211/main.c | 3 ++
net/mac80211/tx.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 36f217e..b4dacde 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -83,6 +83,8 @@ struct ieee80211_local;
#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
+#define DOT11_CHANNEL_UTILIZATION_BEACON_INTERVAL 50
+
struct ieee80211_fragment_entry {
struct sk_buff_head skb_list;
unsigned long first_frag_time;
@@ -1354,6 +1356,11 @@ struct ieee80211_local {
/* TDLS channel switch */
struct work_struct tdls_chsw_work;
struct sk_buff_head skb_queue_tdls_chsw;
+
+ /* BSS load element */
+ u64 qbss_last_time_busy;
+ u32 qbss_interval_cnt;
+ u8 qbss_chan_util;
};
static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ff79a13..f38f836 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -157,6 +157,9 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
local->hw.conf.power_level = power;
}
+ local->qbss_sending_interval_cnt = 0;
+ local->qbss_last_time_busy = 0;
+ local->qbss_chan_util = 0;
return changed;
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2079d48..881618d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3167,6 +3167,70 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
return 0;
}
+static void ieee80211_beacon_add_qbss(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_local *local = sdata->local;
+ u8 *hdr;
+
+ if (++local->qbss_interval_cnt >=
+ DOT11_CHANNEL_UTILIZATION_BEACON_INTERVAL) {
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *current_chan;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ int band_idx, chan_idx = 0, idx = 0;
+ struct survey_info survey;
+ u64 busy_time;
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (chanctx_conf)
+ current_chan = chanctx_conf->def.chan;
+ else
+ current_chan = NULL;
+ rcu_read_unlock();
+ if (!current_chan)
+ return;
+
+ for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
+ sband = local->hw.wiphy->bands[band_idx];
+ chan_idx += sband->n_channels;
+ while (idx < chan_idx &&
+ current_chan != &sband->channels[idx])
+ idx++;
+ if (idx < chan_idx)
+ break;
+ band_idx++;
+ }
+ if (idx == chan_idx)
+ return;
+
+ memset(&survey, 0, sizeof(survey));
+ if (drv_get_survey(local, idx, &survey) != 0)
+ return;
+ if (!(survey.filled & SURVEY_INFO_TIME_BUSY))
+ return;
+ busy_time = survey.time_busy - local->qbss_last_time_busy;
+ local->qbss_chan_util = (u8)div64_u64(busy_time * 255,
+ local->qbss_interval_cnt *
+ sdata->vif.bss_conf.beacon_int);
+ local->qbss_interval_cnt = 0;
+ local->qbss_last_time_busy = survey.time_busy;
+ }
+ hdr = (u8 *)skb_put(skb, 7);
+ if (!hdr)
+ return;
+ *hdr++ = WLAN_EID_QBSS_LOAD;
+ *hdr++ = 5;
+ mutex_lock(&local->sta_mtx);
+ *((u16 *)hdr) = cpu_to_le16(local->num_sta);
+ mutex_unlock(&local->sta_mtx);
+ hdr += 2;
+ *hdr++ = local->qbss_last_time_busy ? local->qbss_chan_util : 255;
+ *hdr++ = 0;
+ *hdr++ = 0;
+}
+
static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
struct beacon_data *beacon)
{
@@ -3352,7 +3416,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
*/
skb = dev_alloc_skb(local->tx_headroom +
beacon->head_len +
- beacon->tail_len + 256 +
+ beacon->tail_len + 256 + 7 +
local->hw.extra_beacon_tailroom);
if (!skb)
goto out;
@@ -3364,6 +3428,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
ieee80211_beacon_add_tim(sdata, &ap->ps, skb,
is_template);
+ ieee80211_beacon_add_qbss(sdata, skb);
if (offs) {
offs->tim_offset = beacon->head_len;
offs->tim_length = skb->len - beacon->head_len;
@@ -3392,13 +3457,14 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
ieee80211_set_csa(sdata, beacon);
}
- skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + 7 +
local->hw.extra_beacon_tailroom);
if (!skb)
goto out;
skb_reserve(skb, local->tx_headroom);
memcpy(skb_put(skb, beacon->head_len), beacon->head,
beacon->head_len);
+ ieee80211_beacon_add_qbss(sdata, skb);
hdr = (struct ieee80211_hdr *) skb->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
--
2.4.6
--------------050803060603050305090704--
More information about the Battlemesh
mailing list