--- include/net/cfg80211.h | 1 + include/uapi/linux/nl80211.h | 1 + net/wireless/core.h | 1 + net/wireless/nl80211.c | 11 +++++++++++ net/wireless/sme.c | 7 +++++++ net/wireless/util.c | 11 +++++++++++ 6 files changed, 32 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5253e7f667bd..25eacbebfa29 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2553,6 +2553,7 @@ struct cfg80211_connect_params { size_t fils_erp_rrk_len; bool want_1x; struct ieee80211_edmg edmg; + const u8 *mac_to_use; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 0ceb945a08fb..1bb4ce58da67 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2834,6 +2834,7 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_EDMG_CHANNELS, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, + NL80211_ATTR_MAC_TO_USE, /* add attributes here, update the policy in nl80211.c */ diff --git a/net/wireless/core.h b/net/wireless/core.h index 77556c58d9ac..29e6ab2cf343 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -454,6 +454,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); void cfg80211_process_wdev_events(struct wireless_dev *wdev); +int cfg80211_set_mac_to_use(struct net_device *dev, const u8 *mac); bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, u32 center_freq_khz, u32 bw_khz); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4565d7385884..0202a762b5c8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -591,6 +591,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .len = SAE_PASSWORD_MAX_LEN }, [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG }, [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy), + [NL80211_ATTR_MAC_TO_USE] = { .type = NLA_EXACT_LEN_WARN, + .len = ETH_ALEN }, }; /* policy for the key attributes */ @@ -10045,6 +10047,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_MAC_TO_USE]) { + if (!wiphy_ext_feature_isset(wiphy, + NL80211_EXT_FEATURE_LIVE_ADDRESS_CHANGE)) + return -EOPNOTSUPP; + + connect.mac_to_use = + nla_data(info->attrs[NL80211_ATTR_MAC_TO_USE]); + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 7a6c38ddc65a..f164af33655f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1242,11 +1242,18 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : IEEE80211_BSS_TYPE_ESS; + if (connect->mac_to_use) { + err = cfg80211_set_mac_to_use(dev, connect->mac_to_use); + if (err) + goto fail; + } + if (!rdev->ops->connect) err = cfg80211_sme_connect(wdev, connect, prev_bssid); else err = rdev_connect(rdev, dev, connect); +fail: if (err) { wdev->connect_keys = NULL; /* diff --git a/net/wireless/util.c b/net/wireless/util.c index 92cb2cbb179b..06700431cba0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2148,3 +2148,14 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, return false; } EXPORT_SYMBOL(cfg80211_iftype_allowed); + +int cfg80211_set_mac_to_use(struct net_device *dev, const u8 *mac) +{ + struct sockaddr sa; + + sa.sa_family = dev->type; + memcpy(sa.sa_data, mac, ETH_ALEN); + + return dev_set_mac_address(dev, &sa, NULL); +} +EXPORT_SYMBOL(cfg80211_set_mac_to_use); -- 2.17.1