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 =
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
IEEE80211_VHT_CAP_RXLDPC |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
||||
|
@ -2543,7 +2542,9 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb,
|
|||
if (cb)
|
||||
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 &
|
||||
REGULATORY_STRICT_REG);
|
||||
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,
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
ieee80211_cqm_rssi_notify(
|
||||
vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
||||
GFP_KERNEL);
|
||||
ieee80211_cqm_beacon_loss_notify(vif, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
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,
|
||||
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
|
||||
* @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,
|
||||
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
|
||||
* @dev: network device
|
||||
|
|
|
@ -3618,6 +3618,26 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
|
|||
void ieee80211_tx_status(struct ieee80211_hw *hw,
|
||||
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)
|
||||
*
|
||||
|
@ -4671,6 +4691,14 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
|
|||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||
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
|
||||
*
|
||||
|
@ -4829,6 +4857,10 @@ struct rate_control_ops {
|
|||
void (*free_sta)(void *priv, struct ieee80211_sta *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,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb);
|
||||
|
|
|
@ -136,6 +136,17 @@ struct regulatory_request {
|
|||
* otherwise initiating radiation is not allowed. This will enable the
|
||||
* relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
|
||||
* 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 {
|
||||
REGULATORY_CUSTOM_REG = BIT(0),
|
||||
|
@ -144,6 +155,7 @@ enum ieee80211_regulatory_flags {
|
|||
REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
|
||||
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
|
||||
REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
|
||||
REGULATORY_IGNORE_STALE_KICKOFF = BIT(6),
|
||||
};
|
||||
|
||||
struct ieee80211_freq_range {
|
||||
|
|
|
@ -3451,6 +3451,8 @@ enum nl80211_ps_state {
|
|||
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
|
||||
* %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_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
|
||||
* loss event
|
||||
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
|
||||
* @NL80211_ATTR_CQM_MAX: highest key attribute
|
||||
*/
|
||||
|
@ -3463,6 +3465,7 @@ enum nl80211_attr_cqm {
|
|||
NL80211_ATTR_CQM_TXE_RATE,
|
||||
NL80211_ATTR_CQM_TXE_PKTS,
|
||||
NL80211_ATTR_CQM_TXE_INTVL,
|
||||
NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_ATTR_CQM_AFTER_LAST,
|
||||
|
@ -3475,9 +3478,7 @@ enum nl80211_attr_cqm {
|
|||
* configured threshold
|
||||
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
|
||||
* configured threshold
|
||||
* @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
|
||||
* (Note that deauth/disassoc will still follow if the AP is not
|
||||
* available. This event might get used as roaming event, etc.)
|
||||
* @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
|
||||
*/
|
||||
enum nl80211_cqm_rssi_threshold_event {
|
||||
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
|
||||
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)
|
||||
changed = BSS_CHANGED_BANDWIDTH;
|
||||
|
||||
sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
||||
ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||
|
||||
if (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)
|
||||
changed = BSS_CHANGED_BANDWIDTH;
|
||||
|
||||
sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
||||
ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||
if (changed)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
changed);
|
||||
|
@ -1507,7 +1522,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
|||
goto out;
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.chandef = *chandef;
|
||||
ieee80211_vif_update_chandef(sdata, chandef);
|
||||
|
||||
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
|
||||
if (ret) {
|
||||
|
@ -1649,7 +1664,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
|
|||
break;
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.chandef = *chandef;
|
||||
ieee80211_vif_update_chandef(sdata, chandef);
|
||||
|
||||
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;
|
||||
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
|
||||
sizeof(sdata->vif.hw_queue));
|
||||
sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
|
||||
break;
|
||||
}
|
||||
case NL80211_IFTYPE_AP:
|
||||
|
|
|
@ -552,13 +552,17 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
|||
cap = vht_cap.cap;
|
||||
|
||||
if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
|
||||
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
|
||||
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
||||
u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||
|
||||
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) {
|
||||
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",
|
||||
beacon_loss_count);
|
||||
|
||||
ieee80211_cqm_rssi_notify(&sdata->vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
||||
GFP_KERNEL);
|
||||
ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4898,3 +4900,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
|
|||
cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
|
||||
}
|
||||
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?
|
||||
*/
|
||||
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;
|
||||
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 ieee80211_sta *ista = &sta->sta;
|
||||
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))
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
|||
static void
|
||||
minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb)
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct minstrel_priv *mp = priv;
|
||||
struct minstrel_sta_info *mi = priv_sta;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||
int i, ndx;
|
||||
int success;
|
||||
|
@ -674,7 +673,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta)
|
|||
|
||||
const struct rate_control_ops mac80211_minstrel = {
|
||||
.name = "minstrel",
|
||||
.tx_status = minstrel_tx_status,
|
||||
.tx_status_noskb = minstrel_tx_status,
|
||||
.get_rate = minstrel_get_rate,
|
||||
.rate_init = minstrel_rate_init,
|
||||
.alloc = minstrel_alloc,
|
||||
|
|
|
@ -709,11 +709,10 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
|
|||
static void
|
||||
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
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 *mi = &msp->ht;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||
struct minstrel_rate_stats *rate, *rate2;
|
||||
struct minstrel_priv *mp = priv;
|
||||
|
@ -721,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
int i;
|
||||
|
||||
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 */
|
||||
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)) {
|
||||
update = true;
|
||||
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)
|
||||
|
@ -1026,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|||
if (!msp->is_ht)
|
||||
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;
|
||||
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 = {
|
||||
.name = "minstrel_ht",
|
||||
.tx_status = minstrel_ht_tx_status,
|
||||
.tx_status_noskb = minstrel_ht_tx_status,
|
||||
.get_rate = minstrel_ht_get_rate,
|
||||
.rate_init = minstrel_ht_rate_init,
|
||||
.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_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 */
|
||||
if ((info->flags & IEEE80211_TX_CTL_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;
|
||||
}
|
||||
|
||||
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;
|
||||
bool send_to_cooked;
|
||||
bool acked;
|
||||
struct ieee80211_bar *bar;
|
||||
int rtap_len;
|
||||
int shift = 0;
|
||||
int count = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
|
@ -657,12 +645,91 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
break;
|
||||
}
|
||||
|
||||
retry_count += info->status.rates[i].count;
|
||||
count += info->status.rates[i].count;
|
||||
}
|
||||
rates_idx = i - 1;
|
||||
|
||||
if (retry_count < 0)
|
||||
retry_count = 0;
|
||||
if (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();
|
||||
|
||||
|
@ -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))
|
||||
sta->last_tdls_pkt_time = jiffies;
|
||||
} 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,
|
||||
TP_PROTO(struct ieee80211_local *local, bool aborted),
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
|||
rcu_read_unlock();
|
||||
|
||||
/* 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;
|
||||
|
||||
/* uh huh? */
|
||||
|
|
|
@ -1339,6 +1339,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
|||
int ext_rates_len;
|
||||
int shift;
|
||||
u32 rate_flags;
|
||||
bool have_80mhz = false;
|
||||
|
||||
*offset = 0;
|
||||
|
||||
|
@ -1467,7 +1468,15 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
|||
*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))
|
||||
goto out_err;
|
||||
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.
|
||||
|
||||
config CFG80211_WEXT
|
||||
bool "cfg80211 wireless extensions compatibility"
|
||||
bool
|
||||
depends on CFG80211
|
||||
select WEXT_CORE
|
||||
help
|
||||
|
|
|
@ -546,6 +546,20 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
!rdev->ops->tdls_cancel_channel_switch)))
|
||||
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 &&
|
||||
(!wiphy->coalesce->n_rules ||
|
||||
!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,
|
||||
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,
|
||||
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 *nl_reg_rule;
|
||||
char *alpha2 = NULL;
|
||||
int rem_reg_rules = 0, r = 0;
|
||||
char *alpha2;
|
||||
int rem_reg_rules, r;
|
||||
u32 num_rules = 0, rule_idx = 0, size_of_regd;
|
||||
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])
|
||||
return -EINVAL;
|
||||
|
@ -6562,8 +6563,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
while (1) {
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
|
||||
if (res == -ENOENT)
|
||||
break;
|
||||
|
@ -6576,9 +6575,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
|||
goto out;
|
||||
}
|
||||
|
||||
chan = ieee80211_get_channel(&rdev->wiphy,
|
||||
survey.channel->center_freq);
|
||||
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
|
||||
if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
|
||||
survey_idx++;
|
||||
continue;
|
||||
}
|
||||
|
@ -11770,55 +11767,155 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
||||
|
||||
void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||
gfp_t gfp)
|
||||
static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
|
||||
const char *mac, 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;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
void **cb;
|
||||
|
||||
trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
||||
if (!hdr) {
|
||||
cb = (void **)msg->cb;
|
||||
|
||||
cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
||||
if (!cb[0]) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
|
||||
goto nla_put_failure;
|
||||
|
||||
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
||||
if (!pinfoattr)
|
||||
if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
|
||||
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,
|
||||
rssi_event))
|
||||
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;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
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,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
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);
|
||||
|
||||
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
|
||||
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
|
@ -12108,54 +12152,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
|||
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,
|
||||
u64 cookie, bool acked, gfp_t gfp)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
#include "reg.h"
|
||||
#include "rdev-ops.h"
|
||||
#include "regdb.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
|
@ -66,6 +67,12 @@
|
|||
#define REG_DBG_PRINT(args...)
|
||||
#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
|
||||
*
|
||||
|
@ -210,6 +217,9 @@ struct reg_beacon {
|
|||
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 DECLARE_WORK(reg_work, reg_todo);
|
||||
|
||||
|
@ -1518,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy,
|
|||
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,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
|
@ -1557,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
|
|||
wiphy = &rdev->wiphy;
|
||||
wiphy_update_regulatory(wiphy, initiator);
|
||||
}
|
||||
|
||||
reg_check_channels();
|
||||
}
|
||||
|
||||
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 */
|
||||
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);
|
||||
reg_check_channels();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
|
@ -2858,6 +2962,7 @@ void regulatory_exit(void)
|
|||
|
||||
cancel_work_sync(®_work);
|
||||
cancel_delayed_work_sync(®_timeout);
|
||||
cancel_delayed_work_sync(®_check_chans);
|
||||
|
||||
/* Lock to suppress warnings */
|
||||
rtnl_lock();
|
||||
|
|
Загрузка…
Ссылка в новой задаче