1
0
Fork 0

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>
hifive-unleashed-5.1
John W. Linville 2014-12-04 11:29:10 -05:00
commit de51f1649a
21 changed files with 518 additions and 218 deletions

View File

@ -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 &

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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,

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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,

View File

@ -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,

View File

@ -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);
} }
} }

View File

@ -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),

View File

@ -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? */

View File

@ -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,

View File

@ -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

View File

@ -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) &&

View File

@ -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)
{ {

View File

@ -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,
&reg_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(&reg_work); cancel_work_sync(&reg_work);
cancel_delayed_work_sync(&reg_timeout); cancel_delayed_work_sync(&reg_timeout);
cancel_delayed_work_sync(&reg_check_chans);
/* Lock to suppress warnings */ /* Lock to suppress warnings */
rtnl_lock(); rtnl_lock();