diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c529973b92d6..8f43b85da96e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -578,6 +578,11 @@ * On reception of this notification, userspace may decide to stop earlier * currently running scan with (@NL80211_CMD_SCAN_CANCEL). * + * @NL80211_CMD_ROAMING_SUPPORT: A notify event used to alert userspace + * regarding changes in roaming support by the driver. If roaming is + * disabled (marked by the presence of @NL80211_ATTR_ROAMING_DISABLED flag) + * userspace should disable background scans and roaming attempts. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -725,6 +730,8 @@ enum nl80211_commands { NL80211_CMD_IM_SCAN_RESULT, + NL80211_CMD_ROAMING_SUPPORT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1300,6 +1307,8 @@ enum nl80211_commands { * each short interval scheduled scan cycle in msecs. * @NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS: number of short * sched scan intervals before switching to the long interval + * @NL80211_ATTR_ROAMING_DISABLED: indicates that the driver can't do roaming + * currently. * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -1566,6 +1575,8 @@ enum nl80211_attrs { NL80211_ATTR_SCHED_SCAN_SHORT_INTERVAL, NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS, + NL80211_ATTR_ROAMING_DISABLED, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index cf95f8d26bd3..7bffb2ee5520 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3440,6 +3440,16 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); +/** + * cfg80211_roaming_status - notify userspace about changes in the driver + * ability to support roaming + * @dev: network device + * @enabled: indicates whether roaming is supported at the current time + * @gfp: allocation flags + */ +void cfg80211_roaming_status(struct net_device *dev, + bool enabled, gfp_t gfp); + /** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying * @dev: network device diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ef100d539917..3a700fd3187a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2820,6 +2820,17 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, */ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); +/** + * ieee80211_roaming_status - report if roaming support by the driver changed + * + * Some drivers have limitations on roaming in certain conditions (e.g. multi + * role) and need to report this back to userspace. + * + * @vif: interface + * @enabled: is roaming supported + */ +void ieee80211_roaming_status(struct ieee80211_vif *vif, bool enabled); + /** * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 8cd72914cdaf..e463b66bc6dd 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -623,6 +623,14 @@ void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) } EXPORT_SYMBOL(ieee80211_report_low_ack); + +void ieee80211_roaming_status(struct ieee80211_vif *vif, bool enabled) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + cfg80211_roaming_status(sdata->dev, enabled, GFP_KERNEL); +} +EXPORT_SYMBOL(ieee80211_roaming_status); + void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bcac275f6570..8bd1146cc22a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -362,6 +362,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_SCAN_NUM_PROBE] = { .type = NLA_U8 }, [NL80211_ATTR_SCHED_SCAN_SHORT_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS] = { .type = NLA_U8 }, + [NL80211_ATTR_ROAMING_DISABLED] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -8803,6 +8804,50 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, } EXPORT_SYMBOL(cfg80211_probe_status); + +void cfg80211_roaming_status(struct net_device *dev, bool enabled, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + int err; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAMING_SUPPORT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + if (!enabled) + if (nla_put_flag(msg, NL80211_ATTR_ROAMING_DISABLED)) + goto nla_put_failure; + + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_roaming_status); + + void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, int freq, int sig_dbm, gfp_t gfp)