Allow user space to use a temporary random MAC address for a Management
frame exchange with drivers that indicate support for this. The main use
for this is to allow GAS/ANQP exchanges to be performed before a
connection without having to expose a persistent MAC address similarly
to the way active scanning can be done with a random MAC address.
Signed-off-by: Jouni Malinen <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/offchannel.c | 9 +++++++++
net/mac80211/rx.c | 5 +++++
3 files changed, 17 insertions(+)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9407cf44305c..d58f9acc90a3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1251,6 +1251,9 @@ struct ieee80211_local {
struct timer_list sta_cleanup;
int sta_generation;
+ /* temporary random address for a Management frame exchange */
+ u8 mgmt_tx_rand_addr[ETH_ALEN];
+
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
struct tasklet_struct wake_txqs_tasklet;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index db3b8bf75656..afdfced696ec 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -955,6 +955,12 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
IEEE80211_SKB_CB(skb)->hw_queue =
local->hw.offchannel_tx_hw_queue;
+ /* remember a random MAC address for Management frame exchange */
+ if (wiphy_ext_feature_isset(wiphy,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA) &&
+ !ether_addr_equal(mgmt->sa, wdev_address(wdev)))
+ memcpy(local->mgmt_tx_rand_addr, mgmt->sa, ETH_ALEN);
+
/* This will handle all kinds of coalescing and immediate TX */
ret = ieee80211_start_roc_work(local, sdata, params->chan,
params->wait, cookie, skb,
@@ -971,6 +977,9 @@ int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
{
struct ieee80211_local *local = wiphy_priv(wiphy);
+ /* stop using the random MAC address for Management frame exchange */
+ eth_zero_addr(local->mgmt_tx_rand_addr);
+
return ieee80211_cancel_roc(local, cookie, true);
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index eaf8931e4627..60dc2406171f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3898,6 +3898,7 @@ EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = rx->skb;
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -3912,6 +3913,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
if (multicast)
return true;
+ if (is_valid_ether_addr(local->mgmt_tx_rand_addr) &&
+ ether_addr_equal(local->mgmt_tx_rand_addr, hdr->addr1))
+ return true;
+
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
case NL80211_IFTYPE_ADHOC:
if (!bssid)
--
2.20.1
Use the Beacon frame specific legacy rate configuration, if specified
for AP or mesh, instead of the generic rate mask when selecting the TX
rate for Beacon frames.
Signed-off-by: Jouni Malinen <[email protected]>
---
net/mac80211/cfg.c | 26 +++++++++++++++++++++++++-
net/mac80211/ieee80211_i.h | 4 ++++
net/mac80211/mesh.c | 1 +
net/mac80211/tx.c | 5 ++++-
4 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ae3e06375a28..548a384b0509 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -994,7 +994,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_TWT |
BSS_CHANGED_HE_OBSS_PD |
BSS_CHANGED_HE_BSS_COLOR;
- int err;
+ int i, err;
int prev_beacon_int;
old = sdata_dereference(sdata->u.ap.beacon, sdata);
@@ -1085,6 +1085,17 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
IEEE80211_P2P_OPPPS_ENABLE_BIT;
+ sdata->beacon_rate_set = false;
+ if (wiphy_ext_feature_isset(local->hw.wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
+ for (i = 0; i < NUM_NL80211_BANDS; i++) {
+ sdata->beacon_rateidx_mask[i] =
+ params->beacon_rate.control[i].legacy;
+ if (sdata->beacon_rateidx_mask[i])
+ sdata->beacon_rate_set = true;
+ }
+ }
+
err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL);
if (err < 0) {
ieee80211_vif_release_channel(sdata);
@@ -1189,6 +1200,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
ieee80211_free_keys(sdata, true);
sdata->vif.bss_conf.enable_beacon = false;
+ sdata->beacon_rate_set = false;
sdata->vif.bss_conf.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
@@ -1949,6 +1961,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
const u8 *old_ie;
struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
struct ieee80211_sub_if_data, u.mesh);
+ int i;
/* allocate information elements */
new_ie = NULL;
@@ -1987,6 +2000,17 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
sdata->vif.bss_conf.dtim_period = setup->dtim_period;
+ sdata->beacon_rate_set = false;
+ if (wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
+ for (i = 0; i < NUM_NL80211_BANDS; i++) {
+ sdata->beacon_rateidx_mask[i] =
+ setup->beacon_rate.control[i].legacy;
+ if (sdata->beacon_rateidx_mask[i])
+ sdata->beacon_rate_set = true;
+ }
+ }
+
return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d58f9acc90a3..fc3278b74977 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -962,6 +962,10 @@ struct ieee80211_sub_if_data {
bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS];
u16 rc_rateidx_vht_mcs_mask[NUM_NL80211_BANDS][NL80211_VHT_NSS_MAX];
+ /* Beacon frame (non-MCS) rate (as a bitmap) */
+ u32 beacon_rateidx_mask[NUM_NL80211_BANDS];
+ bool beacon_rate_set;
+
union {
struct ieee80211_if_ap ap;
struct ieee80211_if_wds wds;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 36978a0e5000..5930d07b1e43 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -994,6 +994,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
/* stop the beacon */
ifmsh->mesh_id_len = 0;
sdata->vif.bss_conf.enable_beacon = false;
+ sdata->beacon_rate_set = false;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3dc1990e15c5..6dad67eb60b2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4883,7 +4883,10 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
txrc.bss_conf = &sdata->vif.bss_conf;
txrc.skb = skb;
txrc.reported_rate.idx = -1;
- txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
+ if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
+ txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
+ else
+ txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
txrc.bss = true;
rate_control_get_rate(sdata, NULL, &txrc);
--
2.20.1
mac80211 takes care of rate control for the Beacon frames, so all
mac80211_hwsim needs to do here is advertise support for this.
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index bd67de740a65..8a0fd2474d5e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3074,6 +3074,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
hw->wiphy->interface_modes = param->iftypes;
--
2.20.1
While mac80211_hwsim does not need this to configure RX filters, it is
convenient to have this enabled for testing purposes.
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a05e9c778f21..bd67de740a65 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1836,6 +1836,8 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
data->rx_filter = 0;
if (*total_flags & FIF_ALLMULTI)
data->rx_filter |= FIF_ALLMULTI;
+ if (*total_flags & FIF_MCAST_ACTION)
+ data->rx_filter |= FIF_MCAST_ACTION;
*total_flags = data->rx_filter;
}
@@ -3070,6 +3072,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
hw->wiphy->interface_modes = param->iftypes;
--
2.20.1
Allow a temporary random MAC address to be used for a Management frame
exchange. This can be used to test pre-association GAS/ANQP exchanges
with random addresses.
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 05e8203aa6d9..a05e9c778f21 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -535,6 +535,7 @@ struct mac80211_hwsim_data {
unsigned long next_start, start, end;
} survey_data[ARRAY_SIZE(hwsim_channels_2ghz) +
ARRAY_SIZE(hwsim_channels_5ghz)];
+ u8 mgmt_tx_rand_addr[ETH_ALEN];
struct ieee80211_channel *channel;
u64 beacon_int /* beacon interval in us */;
@@ -1006,7 +1007,9 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
.ret = false,
};
- if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0)
+ if ((data->scanning && ether_addr_equal(addr, data->scan_addr)) ||
+ (is_valid_ether_addr(data->mgmt_tx_rand_addr) &&
+ ether_addr_equal(addr, data->mgmt_tx_rand_addr)))
return true;
memcpy(md.addr, addr, ETH_ALEN);
@@ -1507,6 +1510,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return;
}
+ if (txi->control.vif &&
+ !ether_addr_equal(hdr->addr2, txi->control.vif->addr))
+ memcpy(data->mgmt_tx_rand_addr, hdr->addr2, ETH_ALEN);
+ else
+ eth_zero_addr(data->mgmt_tx_rand_addr);
+
if (txi->control.vif)
hwsim_check_magic(txi->control.vif);
if (control->sta)
@@ -3060,6 +3069,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA);
hw->wiphy->interface_modes = param->iftypes;
--
2.20.1
On Sat, 2020-04-25 at 18:57 +0300, Jouni Malinen wrote:
> +++ b/net/mac80211/offchannel.c
> @@ -955,6 +955,12 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
> IEEE80211_SKB_CB(skb)->hw_queue =
> local->hw.offchannel_tx_hw_queue;
>
> + /* remember a random MAC address for Management frame exchange */
> + if (wiphy_ext_feature_isset(wiphy,
> + NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA) &&
> + !ether_addr_equal(mgmt->sa, wdev_address(wdev)))
> + memcpy(local->mgmt_tx_rand_addr, mgmt->sa, ETH_ALEN);
> +
> /* This will handle all kinds of coalescing and immediate TX */
> ret = ieee80211_start_roc_work(local, sdata, params->chan,
> params->wait, cookie, skb,
This feels wrong to me. It seems it should be made part of the roc work
item, and only copied over when that item actually starts, and also used
to not coalesce different items if they specify conflicting temporary
addresses.
> @@ -971,6 +977,9 @@ int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
> {
> struct ieee80211_local *local = wiphy_priv(wiphy);
>
> + /* stop using the random MAC address for Management frame exchange */
> + eth_zero_addr(local->mgmt_tx_rand_addr);
> +
> return ieee80211_cancel_roc(local, cookie, true);
Similar here, not clear that the ROC item even started yet at this
point.
It seems to me it needs to be pushed a layer deeper, say into
ieee80211_handle_roc_started() and ieee80211_offchannel_return() or so.
johannes
Applied 3-5, please check the comments on 1 and reply or resend 1/2.
Thanks,
johannes