@@ -341,6 +341,8 @@ struct ieee80211_vif_chanctx_switch {
* @BSS_CHANGED_UNSOL_BCAST_PROBE_RESP: Unsolicited broadcast probe response
* status changed.
* @BSS_CHANGED_EHT_PUNCTURING: The channel puncturing bitmap changed.
+ * @BSS_CHANGED_TEMP_ADDR: Temporary self address allowed for authentication and
+ * deauthentication frames is changed.
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -376,6 +378,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_FILS_DISCOVERY = 1<<30,
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
BSS_CHANGED_EHT_PUNCTURING = BIT_ULL(32),
+ BSS_CHANGED_TEMP_ADDR = BIT_ULL(33),
/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -1805,6 +1808,14 @@ enum ieee80211_offload_flags {
* your driver/device needs to do.
* @ap_addr: AP MLD address, or BSSID for non-MLO connections
* (station mode only)
+ * @temp_addr: Temporary self address allowed for the authentication and
+ * deauthentication frames till the response waiting time offchannel period
+ * complete. Driver should allow TX and RX of the frames with the temporary
+ * address as TA and RA respectively when it is non zero. This will be set
+ * to zero address when no temporary self address is active.
+ * Change in the value of this will be indicated with
+ * %BSS_CHANGED_TEMP_ADDR. This will be used only when driver supports
+ * %NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA.
*/
struct ieee80211_vif_cfg {
/* association related data */
@@ -1820,6 +1831,7 @@ struct ieee80211_vif_cfg {
bool s1g;
bool idle;
u8 ap_addr[ETH_ALEN] __aligned(2);
+ u8 temp_addr[ETH_ALEN] __aligned(2);
};
/**
@@ -205,7 +205,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
BSS_CHANGED_PS |\
BSS_CHANGED_IBSS |\
BSS_CHANGED_ARP_FILTER |\
- BSS_CHANGED_SSID)
+ BSS_CHANGED_SSID |\
+ BSS_CHANGED_TEMP_ADDR)
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
u64 changed)
@@ -187,6 +187,12 @@ static void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
roc->mgmt_tx_cookie,
roc->chan, GFP_KERNEL);
+ if (!is_zero_ether_addr(roc->sdata->vif.cfg.temp_addr)) {
+ eth_zero_addr(roc->sdata->vif.cfg.temp_addr);
+ ieee80211_vif_cfg_change_notify(roc->sdata,
+ BSS_CHANGED_TEMP_ADDR);
+ }
+
list_del(&roc->list);
kfree(roc);
}
@@ -234,6 +240,36 @@ static bool ieee80211_recalc_sw_work(struct ieee80211_local *local,
return true;
}
+static void ieee80211_config_temp_addr(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_hdr *hdr)
+{
+ unsigned int link;
+
+ if (!wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+ NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA))
+ return;
+
+ if (ether_addr_equal(sdata->vif.cfg.temp_addr, hdr->addr2))
+ return;
+
+ rcu_read_lock();
+ for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) {
+ struct ieee80211_bss_conf *link_conf;
+
+ link_conf = rcu_dereference(sdata->vif.link_conf[link]);
+ if (!link_conf)
+ continue;
+ if (ether_addr_equal(link_conf->addr, hdr->addr2)) {
+ rcu_read_unlock();
+ return;
+ }
+ }
+ rcu_read_unlock();
+
+ memcpy(sdata->vif.cfg.temp_addr, hdr->addr2, ETH_ALEN);
+ ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_TEMP_ADDR);
+}
+
static void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc,
unsigned long start_time)
{
@@ -245,6 +281,8 @@ static void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc,
if (roc->mgmt_tx_cookie) {
if (!WARN_ON(!roc->frame)) {
+ ieee80211_config_temp_addr(roc->sdata,
+ (void *) roc->frame->data);
ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
roc->chan->band);
roc->frame = NULL;
@@ -4255,6 +4255,12 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
bool multicast = is_multicast_ether_addr(hdr->addr1) ||
ieee80211_is_s1g_beacon(hdr->frame_control);
+ bool skip_addr1_check = false;
+
+ if ((ieee80211_is_auth(hdr->frame_control) ||
+ ieee80211_is_deauth(hdr->frame_control)) &&
+ ether_addr_equal(sdata->vif.cfg.temp_addr, hdr->addr1))
+ skip_addr1_check = true;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -4265,6 +4271,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
if (multicast)
return true;
+ if (skip_addr1_check)
+ return true;
return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id);
case NL80211_IFTYPE_ADHOC:
if (!bssid)
@@ -4277,7 +4285,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return true;
if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
return false;
- if (!multicast &&
+ if (!multicast && !skip_addr1_check &&
!ether_addr_equal(sdata->vif.addr, hdr->addr1))
return false;
if (!rx->sta) {
@@ -4297,7 +4305,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
if (!is_broadcast_ether_addr(bssid))
return false;
- if (!multicast &&
+ if (!multicast && !skip_addr1_check &&
!ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
return false;
if (!rx->sta) {
@@ -4315,10 +4323,12 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
if (multicast)
return true;
+ if (skip_addr1_check)
+ return true;
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_AP:
- if (!bssid)
+ if (!bssid && !skip_addr1_check)
return ieee80211_is_our_addr(sdata, hdr->addr1,
&rx->link_id);
@@ -4330,7 +4340,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
* and location updates. Note that mac80211
* itself never looks at these frames.
*/
- if (!multicast &&
+ if (!multicast && !skip_addr1_check &&
!ieee80211_is_our_addr(sdata, hdr->addr1,
&rx->link_id))
return false;
@@ -2614,7 +2614,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
unsigned int link_id;
- u32 changed;
+ u64 changed;
if (!ieee80211_sdata_running(sdata))
continue;
@@ -2663,6 +2663,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_TXPOWER |
BSS_CHANGED_MCAST_RATE;
+ if (!is_zero_ether_addr(sdata->vif.cfg.temp_addr)) {
+ eth_zero_addr(sdata->vif.cfg.temp_addr);
+ changed |= BSS_CHANGED_TEMP_ADDR;
+ }
+
if (sdata->vif.bss_conf.mu_mimo_owner)
changed |= BSS_CHANGED_MU_GROUPS;