@@ -601,6 +601,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
hw->wiphy->features |= NL80211_FEATURE_HT_IBSS;
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_LIVE_ADDR_CHANGE);
+
hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
if (iwl_mvm_is_lar_supported(mvm))
hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
@@ -2433,6 +2433,7 @@ struct cfg80211_connect_params {
const u8 *fils_erp_rrk;
size_t fils_erp_rrk_len;
bool want_1x;
+ const u8 *random_mac;
};
/**
@@ -2794,6 +2794,8 @@ enum nl80211_attrs {
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
+ NL80211_ATTR_RANDOM_MAC_ADDR,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5466,6 +5468,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_LIVE_ADDR_CHANGE,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -205,9 +205,6 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
bool check_dup = true;
int ret;
- if (ieee80211_sdata_running(sdata))
- return -EBUSY;
-
if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
check_dup = false;
@@ -216,6 +213,8 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
if (ret)
return ret;
+ dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
ret = eth_mac_addr(dev, sa);
if (ret == 0)
@@ -9887,6 +9887,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
}
+ if (info->attrs[NL80211_ATTR_RANDOM_MAC_ADDR]) {
+ if (!wiphy_ext_feature_isset(wiphy,
+ NL80211_EXT_FEATURE_LIVE_ADDR_CHANGE))
+ return -EINVAL;
+
+ connect.random_mac = nla_data(
+ info->attrs[NL80211_ATTR_RANDOM_MAC_ADDR]);
+ }
+
wdev_lock(dev->ieee80211_ptr);
err = cfg80211_connect(rdev, dev, &connect, connkeys,
@@ -1218,6 +1218,26 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
IEEE80211_BSS_TYPE_ESS;
+ if (connect->random_mac) {
+ struct sockaddr *sa;
+ int len;
+
+ len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
+ sizeof(*sa));
+ sa = kmalloc(len, GFP_KERNEL);
+ if (!sa)
+ return -ENOMEM;
+
+ sa->sa_family = dev->type;
+ memcpy(sa->sa_data, connect->random_mac,
+ dev->addr_len);
+
+ err = dev_set_mac_address(dev, sa, NULL);
+ kfree(sa);
+ if (err < 0)
+ return err;
+ }
+
if (!rdev->ops->connect)
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
else