Commit 72bbe3d1 authored by Johannes Berg's avatar Johannes Berg

Merge branch 'mac80211' into mac80211-next

This is necessary to merge the new TDLS and mesh patches,
as they depend on some fixes.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parents 322cd406 923b352f
...@@ -4867,6 +4867,23 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, ...@@ -4867,6 +4867,23 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef, struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype); enum nl80211_iftype iftype);
/**
* cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
* @wiphy: the wiphy
* @chandef: the channel definition
* @iftype: interface type
*
* Return: %true if there is no secondary channel or the secondary channel(s)
* can be used for beaconing (i.e. is not a radar channel etc.). This version
* also checks if IR-relaxation conditions apply, to allow beaconing under
* more permissive conditions.
*
* Requires the RTNL to be held.
*/
bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype);
/* /*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace * cfg80211_ch_switch_notify - update wdev channel and notify userspace
* @dev: the device which switched channels * @dev: the device which switched channels
......
...@@ -723,6 +723,7 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) ...@@ -723,6 +723,7 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
debugfs_remove_recursive(sdata->vif.debugfs_dir); debugfs_remove_recursive(sdata->vif.debugfs_dir);
sdata->vif.debugfs_dir = NULL; sdata->vif.debugfs_dir = NULL;
sdata->debugfs.subdir_stations = NULL;
} }
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
......
...@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) ...@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
ieee80211_teardown_sdata(sdata); ieee80211_teardown_sdata(sdata);
} }
/*
* Remove all interfaces, may only be called at hardware unregistration
* time because it doesn't do RCU-safe list removals.
*/
void ieee80211_remove_interfaces(struct ieee80211_local *local) void ieee80211_remove_interfaces(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata, *tmp; struct ieee80211_sub_if_data *sdata, *tmp;
...@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) ...@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
ASSERT_RTNL(); ASSERT_RTNL();
/* /* Before destroying the interfaces, make sure they're all stopped so
* Close all AP_VLAN interfaces first, as otherwise they * that the hardware is stopped. Otherwise, the driver might still be
* might be closed while the AP interface they belong to * iterating the interfaces during the shutdown, e.g. from a worker
* is closed, causing unregister_netdevice_many() to crash. * or from RX processing or similar, and if it does so (using atomic
* iteration) while we're manipulating the list, the iteration will
* crash.
*
* After this, the hardware should be stopped and the driver should
* have stopped all of its activities, so that we can do RCU-unaware
* manipulations of the interface list below.
*/ */
list_for_each_entry(sdata, &local->interfaces, list) cfg80211_shutdown_all_interfaces(local->hw.wiphy);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
dev_close(sdata->dev); WARN(local->open_count, "%s: open count remains %d\n",
wiphy_name(local->hw.wiphy), local->open_count);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
......
...@@ -306,7 +306,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -306,7 +306,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
if (action == WLAN_SP_MESH_PEERING_CONFIRM) { if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
/* AID */ /* AID */
pos = skb_put(skb, 2); pos = skb_put(skb, 2);
put_unaligned_le16(plid, pos + 2); put_unaligned_le16(plid, pos);
} }
if (ieee80211_add_srates_ie(sdata, skb, true, band) || if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
...@@ -1123,6 +1123,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, ...@@ -1123,6 +1123,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
WLAN_SP_MESH_PEERING_CONFIRM) { WLAN_SP_MESH_PEERING_CONFIRM) {
baseaddr += 4; baseaddr += 4;
baselen += 4; baselen += 4;
if (baselen > len)
return;
} }
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
mesh_process_plink_frame(sdata, mgmt, &elems); mesh_process_plink_frame(sdata, mgmt, &elems);
......
...@@ -76,6 +76,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -76,6 +76,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (sdata->vif.type != NL80211_IFTYPE_STATION) if (sdata->vif.type != NL80211_IFTYPE_STATION)
continue; continue;
ieee80211_mgd_quiesce(sdata); ieee80211_mgd_quiesce(sdata);
/* If suspended during TX in progress, and wowlan
* is enabled (connection will be active) there
* can be a race where the driver is put out
* of power-save due to TX and during suspend
* dynamic_ps_timer is cancelled and TX packet
* is flushed, leaving the driver in ACTIVE even
* after resuming until dynamic_ps_timer puts
* driver back in DOZE.
*/
if (sdata->u.mgd.associated &&
sdata->u.mgd.powersave &&
!(local->hw.conf.flags & IEEE80211_CONF_PS)) {
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_PS);
}
} }
err = drv_suspend(local, wowlan); err = drv_suspend(local, wowlan);
......
...@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, ...@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *ch; struct ieee80211_channel *ch;
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
int i, subband_start; int i, subband_start;
struct wiphy *wiphy = sdata->local->hw.wiphy;
for (i = start; i <= end; i += spacing) { for (i = start; i <= end; i += spacing) {
if (!ch_cnt) if (!ch_cnt)
...@@ -79,8 +80,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, ...@@ -79,8 +80,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
/* we will be active on the channel */ /* we will be active on the channel */
cfg80211_chandef_create(&chandef, ch, cfg80211_chandef_create(&chandef, ch,
NL80211_CHAN_NO_HT); NL80211_CHAN_NO_HT);
if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy, if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
&chandef,
sdata->wdev.iftype)) { sdata->wdev.iftype)) {
ch_cnt++; ch_cnt++;
/* /*
......
...@@ -1113,7 +1113,9 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, ...@@ -1113,7 +1113,9 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
queued = true; queued = true;
info->control.vif = &tx->sdata->vif; info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS |
IEEE80211_TX_CTL_NO_PS_BUFFER |
IEEE80211_TX_STATUS_EOSP;
__skb_queue_tail(&tid_tx->pending, skb); __skb_queue_tail(&tid_tx->pending, skb);
if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
purge_skb = __skb_dequeue(&tid_tx->pending); purge_skb = __skb_dequeue(&tid_tx->pending);
......
...@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, ...@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
return false; return false;
} }
bool cfg80211_reg_can_beacon(struct wiphy *wiphy, static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef, struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype) enum nl80211_iftype iftype,
bool check_no_ir)
{ {
bool res; bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED | u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR; IEEE80211_CHAN_RADAR;
trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype); trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
/* if (check_no_ir)
* Under certain conditions suggested by some regulatory bodies a
* GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
* only if such relaxations are not enabled and the conditions are not
* met.
*/
if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
prohibited_flags |= IEEE80211_CHAN_NO_IR; prohibited_flags |= IEEE80211_CHAN_NO_IR;
if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 && if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
...@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, ...@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
trace_cfg80211_return_bool(res); trace_cfg80211_return_bool(res);
return res; return res;
} }
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype)
{
return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
}
EXPORT_SYMBOL(cfg80211_reg_can_beacon); EXPORT_SYMBOL(cfg80211_reg_can_beacon);
bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype)
{
bool check_no_ir;
ASSERT_RTNL();
/*
* Under certain conditions suggested by some regulatory bodies a
* GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
* only if such relaxations are not enabled and the conditions are not
* met.
*/
check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
chandef->chan);
return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
}
EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
......
...@@ -2003,7 +2003,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, ...@@ -2003,7 +2003,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
switch (iftype) { switch (iftype) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) { if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
iftype)) {
result = -EINVAL; result = -EINVAL;
break; break;
} }
...@@ -3403,7 +3404,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -3403,7 +3404,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
} else if (!nl80211_get_ap_channel(rdev, &params)) } else if (!nl80211_get_ap_channel(rdev, &params))
return -EINVAL; return -EINVAL;
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef, if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
wdev->iftype)) wdev->iftype))
return -EINVAL; return -EINVAL;
...@@ -6492,7 +6493,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) ...@@ -6492,7 +6493,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return err; return err;
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef, if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
wdev->iftype)) wdev->iftype))
return -EINVAL; return -EINVAL;
...@@ -10170,7 +10171,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb, ...@@ -10170,7 +10171,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
return -EINVAL; return -EINVAL;
/* we will be active on the TDLS link */ /* we will be active on the TDLS link */
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype)) if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
wdev->iftype))
return -EINVAL; return -EINVAL;
/* don't allow switching to DFS channels */ /* don't allow switching to DFS channels */
......
...@@ -544,15 +544,15 @@ static int call_crda(const char *alpha2) ...@@ -544,15 +544,15 @@ static int call_crda(const char *alpha2)
reg_regdb_query(alpha2); reg_regdb_query(alpha2);
if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n"); pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
return -EINVAL; return -EINVAL;
} }
if (!is_world_regdom((char *) alpha2)) if (!is_world_regdom((char *) alpha2))
pr_info("Calling CRDA for country: %c%c\n", pr_debug("Calling CRDA for country: %c%c\n",
alpha2[0], alpha2[1]); alpha2[0], alpha2[1]);
else else
pr_info("Calling CRDA to update world regulatory domain\n"); pr_debug("Calling CRDA to update world regulatory domain\n");
return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env); return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
} }
...@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
return cfg80211_reg_can_beacon(wiphy, &chandef, iftype); return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
return cfg80211_chandef_usable(wiphy, &chandef, return cfg80211_chandef_usable(wiphy, &chandef,
......
...@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, ...@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
TRACE_EVENT(cfg80211_reg_can_beacon, TRACE_EVENT(cfg80211_reg_can_beacon,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype), enum nl80211_iftype iftype, bool check_no_ir),
TP_ARGS(wiphy, chandef, iftype), TP_ARGS(wiphy, chandef, iftype, check_no_ir),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
CHAN_DEF_ENTRY CHAN_DEF_ENTRY
__field(enum nl80211_iftype, iftype) __field(enum nl80211_iftype, iftype)
__field(bool, check_no_ir)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef); CHAN_DEF_ASSIGN(chandef);
__entry->iftype = iftype; __entry->iftype = iftype;
__entry->check_no_ir = check_no_ir;
), ),
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d", TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype) WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
BOOL_TO_STR(__entry->check_no_ir))
); );
TRACE_EVENT(cfg80211_chandef_dfs_required, TRACE_EVENT(cfg80211_chandef_dfs_required,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment