From 1d91f504e43de9cc673be8fae73a443145f299c2 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 10 Feb 2014 16:04:17 +0100 Subject: [PATCH] hostapd: Process management frames only once per BSS At least in nl80211, broadcast management frames like Probe Request frames, may be processed multiple times per BSS if multi-BSS is active and NL80211_CMD_FRAME event is used to deliver them. In the case of Probe Request frames, hostapd will create multiple redundant Probe Response frames which are problematic when many BSS are on one channel. This problem is caused by driver_nl80211 generating an event for wpa_supplicant_event() for each BSS, and hostapd_mgmt_rx() calls ieee802_11_mgmt() for each BSS, too. Fix this by processing broadcast events only for the BSS the driver intended to. The behavior is not changed for drivers not setting a BSS. Signed-hostap: Simon Wunderlich --- src/ap/drv_callbacks.c | 6 ++++++ src/drivers/driver.h | 9 +++++++++ src/drivers/driver_nl80211.c | 6 ++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 3318f7a58..a8c24ebdf 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -721,6 +721,12 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) size_t i; ret = 0; for (i = 0; i < iface->num_bss; i++) { + /* if bss is set, driver will call this function for + * each bss individually. */ + if (rx_mgmt->drv_priv && + (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) + continue; + if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, rx_mgmt->frame_len, &fi) > 0) ret = 1; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index a92de5604..2eafc14cb 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3584,6 +3584,15 @@ union wpa_event_data { size_t frame_len; u32 datarate; + /** + * drv_priv - Pointer to store driver private BSS information + * + * If not set to NULL, this is used for comparison with + * hostapd_data->drv_priv to determine which BSS should process + * the frame. + */ + void *drv_priv; + /** * freq - Frequency (in MHz) on which the frame was received */ diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 2d0284814..bd2c39b1a 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1681,10 +1681,11 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, } -static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, +static void mlme_event_mgmt(struct i802_bss *bss, struct nlattr *freq, struct nlattr *sig, const u8 *frame, size_t len) { + struct wpa_driver_nl80211_data *drv = bss->drv; const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 fc, stype; @@ -1715,6 +1716,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; event.rx_mgmt.ssi_signal = ssi_signal; + event.rx_mgmt.drv_priv = bss; wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } @@ -1939,7 +1941,7 @@ static void mlme_event(struct i802_bss *bss, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME: - mlme_event_mgmt(drv, freq, sig, nla_data(frame), + mlme_event_mgmt(bss, freq, sig, nla_data(frame), nla_len(frame)); break; case NL80211_CMD_FRAME_TX_STATUS: