Merge git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg <johannes@sipsolutions.net> says: "This time I have Felix's no-status rate control work, which will allow drivers to work better with rate control even if they don't have perfect status reporting. In addition to this, a small hwsim fix from Patrik, one of the regulatory patches from Arik, and a number of cleanups and fixes I did myself. Of note is a patch where I disable CFG80211_WEXT so that compatibility is no longer selectable - this is intended as a wake-up call for anyone who's still using it, and is still easily worked around (it's a one-line patch) before we fully remove the code as well in the future." Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Коммит
de51f1649a
|
@ -2388,7 +2388,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||||
sband->vht_cap.cap =
|
sband->vht_cap.cap =
|
||||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
|
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
|
||||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
|
||||||
IEEE80211_VHT_CAP_RXLDPC |
|
IEEE80211_VHT_CAP_RXLDPC |
|
||||||
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||||
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
||||||
|
@ -2543,7 +2542,9 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb,
|
||||||
if (cb)
|
if (cb)
|
||||||
genl_dump_check_consistent(cb, hdr, &hwsim_genl_family);
|
genl_dump_check_consistent(cb, hdr, &hwsim_genl_family);
|
||||||
|
|
||||||
param.reg_alpha2 = data->alpha2;
|
if (data->alpha2[0] && data->alpha2[1])
|
||||||
|
param.reg_alpha2 = data->alpha2;
|
||||||
|
|
||||||
param.reg_strict = !!(data->hw->wiphy->regulatory_flags &
|
param.reg_strict = !!(data->hw->wiphy->regulatory_flags &
|
||||||
REGULATORY_STRICT_REG);
|
REGULATORY_STRICT_REG);
|
||||||
param.p2p_device = !!(data->hw->wiphy->interface_modes &
|
param.p2p_device = !!(data->hw->wiphy->interface_modes &
|
||||||
|
|
|
@ -259,10 +259,7 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
|
||||||
&wlvif->connection_loss_work,
|
&wlvif->connection_loss_work,
|
||||||
msecs_to_jiffies(delay));
|
msecs_to_jiffies(delay));
|
||||||
|
|
||||||
ieee80211_cqm_rssi_notify(
|
ieee80211_cqm_beacon_loss_notify(vif, GFP_KERNEL);
|
||||||
vif,
|
|
||||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
|
||||||
GFP_KERNEL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
|
EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
|
||||||
|
|
|
@ -4642,33 +4642,6 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||||
gfp_t gfp);
|
gfp_t gfp);
|
||||||
|
|
||||||
/**
|
|
||||||
* cfg80211_radar_event - radar detection event
|
|
||||||
* @wiphy: the wiphy
|
|
||||||
* @chandef: chandef for the current channel
|
|
||||||
* @gfp: context flags
|
|
||||||
*
|
|
||||||
* This function is called when a radar is detected on the current chanenl.
|
|
||||||
*/
|
|
||||||
void cfg80211_radar_event(struct wiphy *wiphy,
|
|
||||||
struct cfg80211_chan_def *chandef, gfp_t gfp);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cfg80211_cac_event - Channel availability check (CAC) event
|
|
||||||
* @netdev: network device
|
|
||||||
* @chandef: chandef for the current channel
|
|
||||||
* @event: type of event
|
|
||||||
* @gfp: context flags
|
|
||||||
*
|
|
||||||
* This function is called when a Channel availability check (CAC) is finished
|
|
||||||
* or aborted. This must be called to notify the completion of a CAC process,
|
|
||||||
* also by full-MAC drivers.
|
|
||||||
*/
|
|
||||||
void cfg80211_cac_event(struct net_device *netdev,
|
|
||||||
const struct cfg80211_chan_def *chandef,
|
|
||||||
enum nl80211_radar_event event, gfp_t gfp);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
|
* cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
|
||||||
* @dev: network device
|
* @dev: network device
|
||||||
|
@ -4696,6 +4669,42 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
||||||
void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
|
void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
|
||||||
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
|
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_cqm_beacon_loss_notify - beacon loss event
|
||||||
|
* @dev: network device
|
||||||
|
* @gfp: context flags
|
||||||
|
*
|
||||||
|
* Notify userspace about beacon loss from the connected AP.
|
||||||
|
*/
|
||||||
|
void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_radar_event - radar detection event
|
||||||
|
* @wiphy: the wiphy
|
||||||
|
* @chandef: chandef for the current channel
|
||||||
|
* @gfp: context flags
|
||||||
|
*
|
||||||
|
* This function is called when a radar is detected on the current chanenl.
|
||||||
|
*/
|
||||||
|
void cfg80211_radar_event(struct wiphy *wiphy,
|
||||||
|
struct cfg80211_chan_def *chandef, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_cac_event - Channel availability check (CAC) event
|
||||||
|
* @netdev: network device
|
||||||
|
* @chandef: chandef for the current channel
|
||||||
|
* @event: type of event
|
||||||
|
* @gfp: context flags
|
||||||
|
*
|
||||||
|
* This function is called when a Channel availability check (CAC) is finished
|
||||||
|
* or aborted. This must be called to notify the completion of a CAC process,
|
||||||
|
* also by full-MAC drivers.
|
||||||
|
*/
|
||||||
|
void cfg80211_cac_event(struct net_device *netdev,
|
||||||
|
const struct cfg80211_chan_def *chandef,
|
||||||
|
enum nl80211_radar_event event, gfp_t gfp);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
|
* cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
|
||||||
* @dev: network device
|
* @dev: network device
|
||||||
|
|
|
@ -3618,6 +3618,26 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
|
||||||
void ieee80211_tx_status(struct ieee80211_hw *hw,
|
void ieee80211_tx_status(struct ieee80211_hw *hw,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_tx_status_noskb - transmit status callback without skb
|
||||||
|
*
|
||||||
|
* This function can be used as a replacement for ieee80211_tx_status
|
||||||
|
* in drivers that cannot reliably map tx status information back to
|
||||||
|
* specific skbs.
|
||||||
|
*
|
||||||
|
* Calls to this function for a single hardware must be synchronized
|
||||||
|
* against each other. Calls to this function, ieee80211_tx_status_ni()
|
||||||
|
* and ieee80211_tx_status_irqsafe() may not be mixed for a single hardware.
|
||||||
|
*
|
||||||
|
* @hw: the hardware the frame was transmitted by
|
||||||
|
* @sta: the receiver station to which this packet is sent
|
||||||
|
* (NULL for multicast packets)
|
||||||
|
* @info: tx status information
|
||||||
|
*/
|
||||||
|
void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
struct ieee80211_tx_info *info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_tx_status_ni - transmit status callback (in process context)
|
* ieee80211_tx_status_ni - transmit status callback (in process context)
|
||||||
*
|
*
|
||||||
|
@ -4671,6 +4691,14 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
|
||||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||||
gfp_t gfp);
|
gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_cqm_beacon_loss_notify - inform CQM of beacon loss
|
||||||
|
*
|
||||||
|
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||||
|
* @gfp: context flags
|
||||||
|
*/
|
||||||
|
void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_radar_detected - inform that a radar was detected
|
* ieee80211_radar_detected - inform that a radar was detected
|
||||||
*
|
*
|
||||||
|
@ -4829,6 +4857,10 @@ struct rate_control_ops {
|
||||||
void (*free_sta)(void *priv, struct ieee80211_sta *sta,
|
void (*free_sta)(void *priv, struct ieee80211_sta *sta,
|
||||||
void *priv_sta);
|
void *priv_sta);
|
||||||
|
|
||||||
|
void (*tx_status_noskb)(void *priv,
|
||||||
|
struct ieee80211_supported_band *sband,
|
||||||
|
struct ieee80211_sta *sta, void *priv_sta,
|
||||||
|
struct ieee80211_tx_info *info);
|
||||||
void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
|
void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
|
||||||
struct ieee80211_sta *sta, void *priv_sta,
|
struct ieee80211_sta *sta, void *priv_sta,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
|
|
|
@ -136,6 +136,17 @@ struct regulatory_request {
|
||||||
* otherwise initiating radiation is not allowed. This will enable the
|
* otherwise initiating radiation is not allowed. This will enable the
|
||||||
* relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
|
* relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
|
||||||
* option
|
* option
|
||||||
|
* @REGULATORY_IGNORE_STALE_KICKOFF: the regulatory core will _not_ make sure
|
||||||
|
* all interfaces on this wiphy reside on allowed channels. If this flag
|
||||||
|
* is not set, upon a regdomain change, the interfaces are given a grace
|
||||||
|
* period (currently 60 seconds) to disconnect or move to an allowed
|
||||||
|
* channel. Interfaces on forbidden channels are forcibly disconnected.
|
||||||
|
* Currently these types of interfaces are supported for enforcement:
|
||||||
|
* NL80211_IFTYPE_ADHOC, NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP,
|
||||||
|
* NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_MONITOR,
|
||||||
|
* NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
|
||||||
|
* NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
|
||||||
|
* includes any modes unsupported for enforcement checking.
|
||||||
*/
|
*/
|
||||||
enum ieee80211_regulatory_flags {
|
enum ieee80211_regulatory_flags {
|
||||||
REGULATORY_CUSTOM_REG = BIT(0),
|
REGULATORY_CUSTOM_REG = BIT(0),
|
||||||
|
@ -144,6 +155,7 @@ enum ieee80211_regulatory_flags {
|
||||||
REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
|
REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
|
||||||
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
|
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
|
||||||
REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
|
REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
|
||||||
|
REGULATORY_IGNORE_STALE_KICKOFF = BIT(6),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ieee80211_freq_range {
|
struct ieee80211_freq_range {
|
||||||
|
|
|
@ -3451,6 +3451,8 @@ enum nl80211_ps_state {
|
||||||
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
|
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
|
||||||
* %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
|
* %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
|
||||||
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
|
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
|
||||||
|
* @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
|
||||||
|
* loss event
|
||||||
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
|
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
|
||||||
* @NL80211_ATTR_CQM_MAX: highest key attribute
|
* @NL80211_ATTR_CQM_MAX: highest key attribute
|
||||||
*/
|
*/
|
||||||
|
@ -3463,6 +3465,7 @@ enum nl80211_attr_cqm {
|
||||||
NL80211_ATTR_CQM_TXE_RATE,
|
NL80211_ATTR_CQM_TXE_RATE,
|
||||||
NL80211_ATTR_CQM_TXE_PKTS,
|
NL80211_ATTR_CQM_TXE_PKTS,
|
||||||
NL80211_ATTR_CQM_TXE_INTVL,
|
NL80211_ATTR_CQM_TXE_INTVL,
|
||||||
|
NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
|
||||||
|
|
||||||
/* keep last */
|
/* keep last */
|
||||||
__NL80211_ATTR_CQM_AFTER_LAST,
|
__NL80211_ATTR_CQM_AFTER_LAST,
|
||||||
|
@ -3475,9 +3478,7 @@ enum nl80211_attr_cqm {
|
||||||
* configured threshold
|
* configured threshold
|
||||||
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
|
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
|
||||||
* configured threshold
|
* configured threshold
|
||||||
* @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
|
* @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
|
||||||
* (Note that deauth/disassoc will still follow if the AP is not
|
|
||||||
* available. This event might get used as roaming event, etc.)
|
|
||||||
*/
|
*/
|
||||||
enum nl80211_cqm_rssi_threshold_event {
|
enum nl80211_cqm_rssi_threshold_event {
|
||||||
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
|
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
|
||||||
|
|
|
@ -932,6 +932,21 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata,
|
||||||
|
const struct cfg80211_chan_def *chandef)
|
||||||
|
{
|
||||||
|
struct ieee80211_sub_if_data *vlan;
|
||||||
|
|
||||||
|
sdata->vif.bss_conf.chandef = *chandef;
|
||||||
|
|
||||||
|
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||||
|
vlan->vif.bss_conf.chandef = *chandef;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
|
ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
|
@ -994,7 +1009,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
|
||||||
if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
|
if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
|
||||||
changed = BSS_CHANGED_BANDWIDTH;
|
changed = BSS_CHANGED_BANDWIDTH;
|
||||||
|
|
||||||
sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
ieee80211_bss_info_change_notify(sdata, changed);
|
ieee80211_bss_info_change_notify(sdata, changed);
|
||||||
|
@ -1336,7 +1351,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
|
||||||
sdata->reserved_chandef.width)
|
sdata->reserved_chandef.width)
|
||||||
changed = BSS_CHANGED_BANDWIDTH;
|
changed = BSS_CHANGED_BANDWIDTH;
|
||||||
|
|
||||||
sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||||
if (changed)
|
if (changed)
|
||||||
ieee80211_bss_info_change_notify(sdata,
|
ieee80211_bss_info_change_notify(sdata,
|
||||||
changed);
|
changed);
|
||||||
|
@ -1507,7 +1522,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdata->vif.bss_conf.chandef = *chandef;
|
ieee80211_vif_update_chandef(sdata, chandef);
|
||||||
|
|
||||||
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
|
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1649,7 +1664,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdata->vif.bss_conf.chandef = *chandef;
|
ieee80211_vif_update_chandef(sdata, chandef);
|
||||||
|
|
||||||
ieee80211_recalc_chanctx_chantype(local, ctx);
|
ieee80211_recalc_chanctx_chantype(local, ctx);
|
||||||
|
|
||||||
|
|
|
@ -520,6 +520,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||||
sdata->vif.cab_queue = master->vif.cab_queue;
|
sdata->vif.cab_queue = master->vif.cab_queue;
|
||||||
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
|
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
|
||||||
sizeof(sdata->vif.hw_queue));
|
sizeof(sdata->vif.hw_queue));
|
||||||
|
sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
|
|
|
@ -552,13 +552,17 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
cap = vht_cap.cap;
|
cap = vht_cap.cap;
|
||||||
|
|
||||||
if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
|
if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
|
||||||
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
|
u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||||
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
|
||||||
|
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||||
|
if (bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
|
||||||
|
bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
|
||||||
|
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) {
|
if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) {
|
||||||
cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
|
cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
|
||||||
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2263,9 +2267,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
||||||
"detected beacon loss from AP (missed %d beacons) - probing\n",
|
"detected beacon loss from AP (missed %d beacons) - probing\n",
|
||||||
beacon_loss_count);
|
beacon_loss_count);
|
||||||
|
|
||||||
ieee80211_cqm_rssi_notify(&sdata->vif,
|
ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL);
|
||||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
|
||||||
GFP_KERNEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4898,3 +4900,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
|
||||||
cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
|
cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
|
EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
|
||||||
|
|
||||||
|
void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||||
|
|
||||||
|
trace_api_cqm_beacon_loss_notify(sdata->local, sdata);
|
||||||
|
|
||||||
|
cfg80211_cqm_beacon_loss_notify(sdata->dev, gfp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_cqm_beacon_loss_notify);
|
||||||
|
|
|
@ -446,7 +446,8 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif,
|
||||||
*
|
*
|
||||||
* XXX: Should this check all retry rates?
|
* XXX: Should this check all retry rates?
|
||||||
*/
|
*/
|
||||||
if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
if (!(rates[0].flags &
|
||||||
|
(IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) {
|
||||||
u32 basic_rates = vif->bss_conf.basic_rates;
|
u32 basic_rates = vif->bss_conf.basic_rates;
|
||||||
s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
|
s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,35 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
|
||||||
struct rate_control_ref *ref = local->rate_ctrl;
|
struct rate_control_ref *ref = local->rate_ctrl;
|
||||||
struct ieee80211_sta *ista = &sta->sta;
|
struct ieee80211_sta *ista = &sta->sta;
|
||||||
void *priv_sta = sta->rate_ctrl_priv;
|
void *priv_sta = sta->rate_ctrl_priv;
|
||||||
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
|
||||||
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
if (ref->ops->tx_status)
|
||||||
|
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||||
|
else
|
||||||
|
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
rate_control_tx_status_noskb(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_supported_band *sband,
|
||||||
|
struct sta_info *sta,
|
||||||
|
struct ieee80211_tx_info *info)
|
||||||
|
{
|
||||||
|
struct rate_control_ref *ref = local->rate_ctrl;
|
||||||
|
struct ieee80211_sta *ista = &sta->sta;
|
||||||
|
void *priv_sta = sta->rate_ctrl_priv;
|
||||||
|
|
||||||
|
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void rate_control_rate_init(struct sta_info *sta)
|
static inline void rate_control_rate_init(struct sta_info *sta)
|
||||||
{
|
{
|
||||||
|
|
|
@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
||||||
static void
|
static void
|
||||||
minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||||
struct ieee80211_sta *sta, void *priv_sta,
|
struct ieee80211_sta *sta, void *priv_sta,
|
||||||
struct sk_buff *skb)
|
struct ieee80211_tx_info *info)
|
||||||
{
|
{
|
||||||
struct minstrel_priv *mp = priv;
|
struct minstrel_priv *mp = priv;
|
||||||
struct minstrel_sta_info *mi = priv_sta;
|
struct minstrel_sta_info *mi = priv_sta;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||||
int i, ndx;
|
int i, ndx;
|
||||||
int success;
|
int success;
|
||||||
|
@ -674,7 +673,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta)
|
||||||
|
|
||||||
const struct rate_control_ops mac80211_minstrel = {
|
const struct rate_control_ops mac80211_minstrel = {
|
||||||
.name = "minstrel",
|
.name = "minstrel",
|
||||||
.tx_status = minstrel_tx_status,
|
.tx_status_noskb = minstrel_tx_status,
|
||||||
.get_rate = minstrel_get_rate,
|
.get_rate = minstrel_get_rate,
|
||||||
.rate_init = minstrel_rate_init,
|
.rate_init = minstrel_rate_init,
|
||||||
.alloc = minstrel_alloc,
|
.alloc = minstrel_alloc,
|
||||||
|
|
|
@ -709,11 +709,10 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
|
||||||
static void
|
static void
|
||||||
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||||
struct ieee80211_sta *sta, void *priv_sta,
|
struct ieee80211_sta *sta, void *priv_sta,
|
||||||
struct sk_buff *skb)
|
struct ieee80211_tx_info *info)
|
||||||
{
|
{
|
||||||
struct minstrel_ht_sta_priv *msp = priv_sta;
|
struct minstrel_ht_sta_priv *msp = priv_sta;
|
||||||
struct minstrel_ht_sta *mi = &msp->ht;
|
struct minstrel_ht_sta *mi = &msp->ht;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||||
struct minstrel_rate_stats *rate, *rate2;
|
struct minstrel_rate_stats *rate, *rate2;
|
||||||
struct minstrel_priv *mp = priv;
|
struct minstrel_priv *mp = priv;
|
||||||
|
@ -721,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!msp->is_ht)
|
if (!msp->is_ht)
|
||||||
return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
|
return mac80211_minstrel.tx_status_noskb(priv, sband, sta,
|
||||||
|
&msp->legacy, info);
|
||||||
|
|
||||||
/* This packet was aggregated but doesn't carry status info */
|
/* This packet was aggregated but doesn't carry status info */
|
||||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||||
|
@ -782,9 +782,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||||
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
|
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
|
||||||
update = true;
|
update = true;
|
||||||
minstrel_ht_update_stats(mp, mi);
|
minstrel_ht_update_stats(mp, mi);
|
||||||
if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
|
||||||
mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
|
|
||||||
minstrel_aggr_check(sta, skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update)
|
if (update)
|
||||||
|
@ -1026,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||||
if (!msp->is_ht)
|
if (!msp->is_ht)
|
||||||
return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
|
return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
|
||||||
|
|
||||||
|
if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||||
|
mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
|
||||||
|
minstrel_aggr_check(sta, txrc->skb);
|
||||||
|
|
||||||
info->flags |= mi->tx_flags;
|
info->flags |= mi->tx_flags;
|
||||||
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
|
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
|
||||||
|
|
||||||
|
@ -1342,7 +1343,7 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
|
||||||
|
|
||||||
static const struct rate_control_ops mac80211_minstrel_ht = {
|
static const struct rate_control_ops mac80211_minstrel_ht = {
|
||||||
.name = "minstrel_ht",
|
.name = "minstrel_ht",
|
||||||
.tx_status = minstrel_ht_tx_status,
|
.tx_status_noskb = minstrel_ht_tx_status,
|
||||||
.get_rate = minstrel_ht_get_rate,
|
.get_rate = minstrel_ht_get_rate,
|
||||||
.rate_init = minstrel_ht_rate_init,
|
.rate_init = minstrel_ht_rate_init,
|
||||||
.rate_update = minstrel_ht_rate_update,
|
.rate_update = minstrel_ht_rate_update,
|
||||||
|
|
|
@ -592,10 +592,9 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
|
||||||
#define STA_LOST_TDLS_PKT_THRESHOLD 10
|
#define STA_LOST_TDLS_PKT_THRESHOLD 10
|
||||||
#define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */
|
#define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */
|
||||||
|
|
||||||
static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
|
static void ieee80211_lost_packet(struct sta_info *sta,
|
||||||
|
struct ieee80211_tx_info *info)
|
||||||
{
|
{
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
|
|
||||||
/* This packet was aggregated but doesn't carry status info */
|
/* This packet was aggregated but doesn't carry status info */
|
||||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||||
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||||
|
@ -622,24 +621,13 @@ static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
|
||||||
sta->lost_packets = 0;
|
sta->lost_packets = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_tx_info *info,
|
||||||
|
int *retry_count)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb2;
|
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
|
||||||
struct ieee80211_local *local = hw_to_local(hw);
|
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
__le16 fc;
|
|
||||||
struct ieee80211_supported_band *sband;
|
|
||||||
struct ieee80211_sub_if_data *sdata;
|
|
||||||
struct net_device *prev_dev = NULL;
|
|
||||||
struct sta_info *sta, *tmp;
|
|
||||||
int retry_count = -1, i;
|
|
||||||
int rates_idx = -1;
|
int rates_idx = -1;
|
||||||
bool send_to_cooked;
|
int count = -1;
|
||||||
bool acked;
|
int i;
|
||||||
struct ieee80211_bar *bar;
|
|
||||||
int rtap_len;
|
|
||||||
int shift = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||||
|
@ -657,12 +645,91 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
retry_count += info->status.rates[i].count;
|
count += info->status.rates[i].count;
|
||||||
}
|
}
|
||||||
rates_idx = i - 1;
|
rates_idx = i - 1;
|
||||||
|
|
||||||
if (retry_count < 0)
|
if (count < 0)
|
||||||
retry_count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
*retry_count = count;
|
||||||
|
return rates_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_sta *pubsta,
|
||||||
|
struct ieee80211_tx_info *info)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
int retry_count;
|
||||||
|
int rates_idx;
|
||||||
|
bool acked;
|
||||||
|
|
||||||
|
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||||
|
|
||||||
|
sband = hw->wiphy->bands[info->band];
|
||||||
|
|
||||||
|
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
|
||||||
|
if (pubsta) {
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
sta = container_of(pubsta, struct sta_info, sta);
|
||||||
|
|
||||||
|
if (!acked)
|
||||||
|
sta->tx_retry_failed++;
|
||||||
|
sta->tx_retry_count += retry_count;
|
||||||
|
|
||||||
|
if (acked) {
|
||||||
|
sta->last_rx = jiffies;
|
||||||
|
|
||||||
|
if (sta->lost_packets)
|
||||||
|
sta->lost_packets = 0;
|
||||||
|
|
||||||
|
/* Track when last TDLS packet was ACKed */
|
||||||
|
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
|
||||||
|
sta->last_tdls_pkt_time = jiffies;
|
||||||
|
} else {
|
||||||
|
ieee80211_lost_packet(sta, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
rate_control_tx_status_noskb(local, sband, sta, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acked) {
|
||||||
|
local->dot11TransmittedFrameCount++;
|
||||||
|
if (!pubsta)
|
||||||
|
local->dot11MulticastTransmittedFrameCount++;
|
||||||
|
if (retry_count > 0)
|
||||||
|
local->dot11RetryCount++;
|
||||||
|
if (retry_count > 1)
|
||||||
|
local->dot11MultipleRetryCount++;
|
||||||
|
} else {
|
||||||
|
local->dot11FailedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_tx_status_noskb);
|
||||||
|
|
||||||
|
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb2;
|
||||||
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
__le16 fc;
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
struct ieee80211_sub_if_data *sdata;
|
||||||
|
struct net_device *prev_dev = NULL;
|
||||||
|
struct sta_info *sta, *tmp;
|
||||||
|
int retry_count;
|
||||||
|
int rates_idx;
|
||||||
|
bool send_to_cooked;
|
||||||
|
bool acked;
|
||||||
|
struct ieee80211_bar *bar;
|
||||||
|
int rtap_len;
|
||||||
|
int shift = 0;
|
||||||
|
|
||||||
|
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
|
@ -767,7 +834,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
|
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
|
||||||
sta->last_tdls_pkt_time = jiffies;
|
sta->last_tdls_pkt_time = jiffies;
|
||||||
} else {
|
} else {
|
||||||
ieee80211_lost_packet(sta, skb);
|
ieee80211_lost_packet(sta, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1829,6 +1829,12 @@ TRACE_EVENT(api_cqm_rssi_notify,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(local_sdata_evt, api_cqm_beacon_loss_notify,
|
||||||
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata),
|
||||||
|
TP_ARGS(local, sdata)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(api_scan_completed,
|
TRACE_EVENT(api_scan_completed,
|
||||||
TP_PROTO(struct ieee80211_local *local, bool aborted),
|
TP_PROTO(struct ieee80211_local *local, bool aborted),
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
/* assume HW handles this */
|
/* assume HW handles this */
|
||||||
if (tx->rate.flags & IEEE80211_TX_RC_MCS)
|
if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* uh huh? */
|
/* uh huh? */
|
||||||
|
|
|
@ -1339,6 +1339,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||||
int ext_rates_len;
|
int ext_rates_len;
|
||||||
int shift;
|
int shift;
|
||||||
u32 rate_flags;
|
u32 rate_flags;
|
||||||
|
bool have_80mhz = false;
|
||||||
|
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
|
|
||||||
|
@ -1467,7 +1468,15 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||||
*offset = noffset;
|
*offset = noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sband->vht_cap.vht_supported) {
|
/* Check if any channel in this sband supports at least 80 MHz */
|
||||||
|
for (i = 0; i < sband->n_channels; i++) {
|
||||||
|
if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) {
|
||||||
|
have_80mhz = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sband->vht_cap.vht_supported && have_80mhz) {
|
||||||
if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
|
if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
|
||||||
goto out_err;
|
goto out_err;
|
||||||
pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
|
pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
|
||||||
|
|
|
@ -175,7 +175,7 @@ config CFG80211_INTERNAL_REGDB
|
||||||
Most distributions have a CRDA package. So if unsure, say N.
|
Most distributions have a CRDA package. So if unsure, say N.
|
||||||
|
|
||||||
config CFG80211_WEXT
|
config CFG80211_WEXT
|
||||||
bool "cfg80211 wireless extensions compatibility"
|
bool
|
||||||
depends on CFG80211
|
depends on CFG80211
|
||||||
select WEXT_CORE
|
select WEXT_CORE
|
||||||
help
|
help
|
||||||
|
|
|
@ -546,6 +546,20 @@ int wiphy_register(struct wiphy *wiphy)
|
||||||
!rdev->ops->tdls_cancel_channel_switch)))
|
!rdev->ops->tdls_cancel_channel_switch)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if a wiphy has unsupported modes for regulatory channel enforcement,
|
||||||
|
* opt-out of enforcement checking
|
||||||
|
*/
|
||||||
|
if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) |
|
||||||
|
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||||
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
|
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||||
|
BIT(NL80211_IFTYPE_ADHOC) |
|
||||||
|
BIT(NL80211_IFTYPE_P2P_DEVICE) |
|
||||||
|
BIT(NL80211_IFTYPE_AP_VLAN) |
|
||||||
|
BIT(NL80211_IFTYPE_MONITOR)))
|
||||||
|
wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
|
||||||
|
|
||||||
if (WARN_ON(wiphy->coalesce &&
|
if (WARN_ON(wiphy->coalesce &&
|
||||||
(!wiphy->coalesce->n_rules ||
|
(!wiphy->coalesce->n_rules ||
|
||||||
!wiphy->coalesce->n_patterns) &&
|
!wiphy->coalesce->n_patterns) &&
|
||||||
|
|
|
@ -2317,7 +2317,8 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
|
||||||
static int nl80211_send_chandef(struct sk_buff *msg,
|
static int nl80211_send_chandef(struct sk_buff *msg,
|
||||||
const struct cfg80211_chan_def *chandef)
|
const struct cfg80211_chan_def *chandef)
|
||||||
{
|
{
|
||||||
WARN_ON(!cfg80211_chandef_valid(chandef));
|
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||||
chandef->chan->center_freq))
|
chandef->chan->center_freq))
|
||||||
|
@ -5421,11 +5422,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
|
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
|
||||||
struct nlattr *nl_reg_rule;
|
struct nlattr *nl_reg_rule;
|
||||||
char *alpha2 = NULL;
|
char *alpha2;
|
||||||
int rem_reg_rules = 0, r = 0;
|
int rem_reg_rules, r;
|
||||||
u32 num_rules = 0, rule_idx = 0, size_of_regd;
|
u32 num_rules = 0, rule_idx = 0, size_of_regd;
|
||||||
enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
|
enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
|
||||||
struct ieee80211_regdomain *rd = NULL;
|
struct ieee80211_regdomain *rd;
|
||||||
|
|
||||||
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
|
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -6562,8 +6563,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct ieee80211_channel *chan;
|
|
||||||
|
|
||||||
res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
|
res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
|
||||||
if (res == -ENOENT)
|
if (res == -ENOENT)
|
||||||
break;
|
break;
|
||||||
|
@ -6576,9 +6575,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan = ieee80211_get_channel(&rdev->wiphy,
|
if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
|
||||||
survey.channel->center_freq);
|
|
||||||
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
|
|
||||||
survey_idx++;
|
survey_idx++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -11770,55 +11767,155 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
||||||
|
|
||||||
void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
|
||||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
const char *mac, gfp_t gfp)
|
||||||
gfp_t gfp)
|
|
||||||
{
|
{
|
||||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||||
struct wiphy *wiphy = wdev->wiphy;
|
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||||
struct sk_buff *msg;
|
void **cb;
|
||||||
struct nlattr *pinfoattr;
|
|
||||||
void *hdr;
|
|
||||||
|
|
||||||
trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
|
|
||||||
|
|
||||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
cb = (void **)msg->cb;
|
||||||
if (!hdr) {
|
|
||||||
|
cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
||||||
|
if (!cb[0]) {
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
|
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
|
||||||
if (!pinfoattr)
|
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
|
||||||
|
if (!cb[1])
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
cb[2] = rdev;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
|
||||||
|
{
|
||||||
|
void **cb = (void **)msg->cb;
|
||||||
|
struct cfg80211_registered_device *rdev = cb[2];
|
||||||
|
|
||||||
|
nla_nest_end(msg, cb[1]);
|
||||||
|
genlmsg_end(msg, cb[0]);
|
||||||
|
|
||||||
|
memset(msg->cb, 0, sizeof(msg->cb));
|
||||||
|
|
||||||
|
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||||
|
NL80211_MCGRP_MLME, gfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||||
|
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||||
|
gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
|
||||||
|
trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
|
||||||
|
|
||||||
|
if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
|
||||||
|
rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
|
||||||
|
return;
|
||||||
|
|
||||||
|
msg = cfg80211_prepare_cqm(dev, NULL, gfp);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
|
if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
|
||||||
rssi_event))
|
rssi_event))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
nla_nest_end(msg, pinfoattr);
|
cfg80211_send_cqm(msg, gfp);
|
||||||
|
|
||||||
genlmsg_end(msg, hdr);
|
|
||||||
|
|
||||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
|
||||||
NL80211_MCGRP_MLME, gfp);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
genlmsg_cancel(msg, hdr);
|
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
|
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
|
||||||
|
|
||||||
|
void cfg80211_cqm_txe_notify(struct net_device *dev,
|
||||||
|
const u8 *peer, u32 num_packets,
|
||||||
|
u32 rate, u32 intvl, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
|
||||||
|
msg = cfg80211_prepare_cqm(dev, peer, gfp);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
cfg80211_send_cqm(msg, gfp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
|
||||||
|
|
||||||
|
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
||||||
|
const u8 *peer, u32 num_packets, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
|
||||||
|
trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
|
||||||
|
|
||||||
|
msg = cfg80211_prepare_cqm(dev, peer, gfp);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
cfg80211_send_cqm(msg, gfp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
|
||||||
|
|
||||||
|
void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct sk_buff *msg;
|
||||||
|
|
||||||
|
msg = cfg80211_prepare_cqm(dev, NULL, gfp);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
cfg80211_send_cqm(msg, gfp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
|
||||||
|
|
||||||
static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
|
static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
|
||||||
struct net_device *netdev, const u8 *bssid,
|
struct net_device *netdev, const u8 *bssid,
|
||||||
const u8 *replay_ctr, gfp_t gfp)
|
const u8 *replay_ctr, gfp_t gfp)
|
||||||
|
@ -12007,59 +12104,6 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
|
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
|
||||||
|
|
||||||
void cfg80211_cqm_txe_notify(struct net_device *dev,
|
|
||||||
const u8 *peer, u32 num_packets,
|
|
||||||
u32 rate, u32 intvl, gfp_t gfp)
|
|
||||||
{
|
|
||||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
||||||
struct wiphy *wiphy = wdev->wiphy;
|
|
||||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
|
||||||
struct sk_buff *msg;
|
|
||||||
struct nlattr *pinfoattr;
|
|
||||||
void *hdr;
|
|
||||||
|
|
||||||
msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
|
|
||||||
if (!msg)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
|
||||||
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) ||
|
|
||||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
|
||||||
if (!pinfoattr)
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
nla_nest_end(msg, pinfoattr);
|
|
||||||
|
|
||||||
genlmsg_end(msg, hdr);
|
|
||||||
|
|
||||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
|
||||||
NL80211_MCGRP_MLME, gfp);
|
|
||||||
return;
|
|
||||||
|
|
||||||
nla_put_failure:
|
|
||||||
genlmsg_cancel(msg, hdr);
|
|
||||||
nlmsg_free(msg);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
|
@ -12108,54 +12152,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
|
||||||
const u8 *peer, u32 num_packets, gfp_t gfp)
|
|
||||||
{
|
|
||||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
||||||
struct wiphy *wiphy = wdev->wiphy;
|
|
||||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
|
||||||
struct sk_buff *msg;
|
|
||||||
struct nlattr *pinfoattr;
|
|
||||||
void *hdr;
|
|
||||||
|
|
||||||
trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
|
|
||||||
|
|
||||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
|
||||||
if (!msg)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
|
||||||
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) ||
|
|
||||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
|
||||||
if (!pinfoattr)
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
|
|
||||||
goto nla_put_failure;
|
|
||||||
|
|
||||||
nla_nest_end(msg, pinfoattr);
|
|
||||||
|
|
||||||
genlmsg_end(msg, hdr);
|
|
||||||
|
|
||||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
|
||||||
NL80211_MCGRP_MLME, gfp);
|
|
||||||
return;
|
|
||||||
|
|
||||||
nla_put_failure:
|
|
||||||
genlmsg_cancel(msg, hdr);
|
|
||||||
nlmsg_free(msg);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
|
|
||||||
|
|
||||||
void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
||||||
u64 cookie, bool acked, gfp_t gfp)
|
u64 cookie, bool acked, gfp_t gfp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include <net/cfg80211.h>
|
#include <net/cfg80211.h>
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
|
#include "rdev-ops.h"
|
||||||
#include "regdb.h"
|
#include "regdb.h"
|
||||||
#include "nl80211.h"
|
#include "nl80211.h"
|
||||||
|
|
||||||
|
@ -66,6 +67,12 @@
|
||||||
#define REG_DBG_PRINT(args...)
|
#define REG_DBG_PRINT(args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Grace period we give before making sure all current interfaces reside on
|
||||||
|
* channels allowed by the current regulatory domain.
|
||||||
|
*/
|
||||||
|
#define REG_ENFORCE_GRACE_MS 60000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum reg_request_treatment - regulatory request treatment
|
* enum reg_request_treatment - regulatory request treatment
|
||||||
*
|
*
|
||||||
|
@ -210,6 +217,9 @@ struct reg_beacon {
|
||||||
struct ieee80211_channel chan;
|
struct ieee80211_channel chan;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void reg_check_chans_work(struct work_struct *work);
|
||||||
|
static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
|
||||||
|
|
||||||
static void reg_todo(struct work_struct *work);
|
static void reg_todo(struct work_struct *work);
|
||||||
static DECLARE_WORK(reg_work, reg_todo);
|
static DECLARE_WORK(reg_work, reg_todo);
|
||||||
|
|
||||||
|
@ -1518,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy,
|
||||||
wiphy->reg_notifier(wiphy, request);
|
wiphy->reg_notifier(wiphy, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||||
|
{
|
||||||
|
struct ieee80211_channel *ch;
|
||||||
|
struct cfg80211_chan_def chandef;
|
||||||
|
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
wdev_lock(wdev);
|
||||||
|
|
||||||
|
if (!wdev->netdev || !netif_running(wdev->netdev))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
switch (wdev->iftype) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
case NL80211_IFTYPE_P2P_GO:
|
||||||
|
if (!wdev->beacon_interval)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = cfg80211_reg_can_beacon(wiphy,
|
||||||
|
&wdev->chandef, wdev->iftype);
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_STATION:
|
||||||
|
case NL80211_IFTYPE_P2P_CLIENT:
|
||||||
|
case NL80211_IFTYPE_ADHOC:
|
||||||
|
if (!wdev->current_bss ||
|
||||||
|
!wdev->current_bss->pub.channel)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ch = wdev->current_bss->pub.channel;
|
||||||
|
if (rdev->ops->get_channel &&
|
||||||
|
!rdev_get_channel(rdev, wdev, &chandef))
|
||||||
|
ret = cfg80211_chandef_usable(wiphy, &chandef,
|
||||||
|
IEEE80211_CHAN_DISABLED);
|
||||||
|
else
|
||||||
|
ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_MONITOR:
|
||||||
|
case NL80211_IFTYPE_AP_VLAN:
|
||||||
|
case NL80211_IFTYPE_P2P_DEVICE:
|
||||||
|
/* no enforcement required */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* others not implemented for now */
|
||||||
|
WARN_ON(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
wdev_unlock(wdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reg_leave_invalid_chans(struct wiphy *wiphy)
|
||||||
|
{
|
||||||
|
struct wireless_dev *wdev;
|
||||||
|
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||||
|
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||||
|
if (!reg_wdev_chan_valid(wiphy, wdev))
|
||||||
|
cfg80211_leave(rdev, wdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reg_check_chans_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct cfg80211_registered_device *rdev;
|
||||||
|
|
||||||
|
REG_DBG_PRINT("Verifying active interfaces after reg change\n");
|
||||||
|
rtnl_lock();
|
||||||
|
|
||||||
|
list_for_each_entry(rdev, &cfg80211_rdev_list, list)
|
||||||
|
if (!(rdev->wiphy.regulatory_flags &
|
||||||
|
REGULATORY_IGNORE_STALE_KICKOFF))
|
||||||
|
reg_leave_invalid_chans(&rdev->wiphy);
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reg_check_channels(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Give usermode a chance to do something nicer (move to another
|
||||||
|
* channel, orderly disconnection), before forcing a disconnection.
|
||||||
|
*/
|
||||||
|
mod_delayed_work(system_power_efficient_wq,
|
||||||
|
®_check_chans,
|
||||||
|
msecs_to_jiffies(REG_ENFORCE_GRACE_MS));
|
||||||
|
}
|
||||||
|
|
||||||
static void wiphy_update_regulatory(struct wiphy *wiphy,
|
static void wiphy_update_regulatory(struct wiphy *wiphy,
|
||||||
enum nl80211_reg_initiator initiator)
|
enum nl80211_reg_initiator initiator)
|
||||||
{
|
{
|
||||||
|
@ -1557,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
|
||||||
wiphy = &rdev->wiphy;
|
wiphy = &rdev->wiphy;
|
||||||
wiphy_update_regulatory(wiphy, initiator);
|
wiphy_update_regulatory(wiphy, initiator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reg_check_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_channel_custom(struct wiphy *wiphy,
|
static void handle_channel_custom(struct wiphy *wiphy,
|
||||||
|
@ -1976,8 +2078,10 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
||||||
|
|
||||||
/* This is required so that the orig_* parameters are saved */
|
/* This is required so that the orig_* parameters are saved */
|
||||||
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
|
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
|
||||||
wiphy->regulatory_flags & REGULATORY_STRICT_REG)
|
wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
||||||
wiphy_update_regulatory(wiphy, reg_request->initiator);
|
wiphy_update_regulatory(wiphy, reg_request->initiator);
|
||||||
|
reg_check_channels();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2858,6 +2962,7 @@ void regulatory_exit(void)
|
||||||
|
|
||||||
cancel_work_sync(®_work);
|
cancel_work_sync(®_work);
|
||||||
cancel_delayed_work_sync(®_timeout);
|
cancel_delayed_work_sync(®_timeout);
|
||||||
|
cancel_delayed_work_sync(®_check_chans);
|
||||||
|
|
||||||
/* Lock to suppress warnings */
|
/* Lock to suppress warnings */
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче