aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r--net/wireless/mlme.c162
1 files changed, 110 insertions, 52 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 5e8123ee63fd..caddca35d686 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -58,7 +58,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
*/
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
cfg80211_sme_failed_reassoc(wdev)) {
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
goto out;
}
@@ -70,7 +70,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
* do not call connect_result() now because the
* sme will schedule work that does it later.
*/
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
goto out;
}
@@ -108,7 +108,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
if (wdev->current_bss &&
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
+ cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
was_current = true;
}
@@ -164,7 +164,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
cfg80211_sme_disassoc(dev, wdev->current_bss);
cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
+ cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
} else
WARN_ON(1);
@@ -324,7 +324,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
err = rdev_auth(rdev, dev, &req);
out:
- cfg80211_put_bss(req.bss);
+ cfg80211_put_bss(&rdev->wiphy, req.bss);
return err;
}
@@ -432,7 +432,7 @@ out:
if (err) {
if (was_connected)
wdev->sme_state = CFG80211_SME_CONNECTED;
- cfg80211_put_bss(req.bss);
+ cfg80211_put_bss(&rdev->wiphy, req.bss);
}
return err;
@@ -514,7 +514,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return -ENOTCONN;
- if (WARN_ON(!wdev->current_bss))
+ if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
return -ENOTCONN;
memset(&req, 0, sizeof(req));
@@ -572,7 +572,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
+ cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
}
}
@@ -988,64 +988,122 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
-void cfg80211_ch_switch_notify(struct net_device *dev,
- struct cfg80211_chan_def *chandef)
+void cfg80211_dfs_channels_update_work(struct work_struct *work)
{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct delayed_work *delayed_work;
+ struct cfg80211_registered_device *rdev;
+ struct cfg80211_chan_def chandef;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *c;
+ struct wiphy *wiphy;
+ bool check_again = false;
+ unsigned long timeout, next_time = 0;
+ int bandid, i;
+
+ delayed_work = container_of(work, struct delayed_work, work);
+ rdev = container_of(delayed_work, struct cfg80211_registered_device,
+ dfs_update_channels_wk);
+ wiphy = &rdev->wiphy;
+
+ mutex_lock(&cfg80211_mutex);
+ for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) {
+ sband = wiphy->bands[bandid];
+ if (!sband)
+ continue;
- trace_cfg80211_ch_switch_notify(dev, chandef);
+ for (i = 0; i < sband->n_channels; i++) {
+ c = &sband->channels[i];
- wdev_lock(wdev);
+ if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
+ continue;
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO))
- goto out;
+ timeout = c->dfs_state_entered +
+ IEEE80211_DFS_MIN_NOP_TIME_MS;
- wdev->channel = chandef->chan;
- nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
- wdev_unlock(wdev);
- return;
+ if (time_after_eq(jiffies, timeout)) {
+ c->dfs_state = NL80211_DFS_USABLE;
+ cfg80211_chandef_create(&chandef, c,
+ NL80211_CHAN_NO_HT);
+
+ nl80211_radar_notify(rdev, &chandef,
+ NL80211_RADAR_NOP_FINISHED,
+ NULL, GFP_ATOMIC);
+ continue;
+ }
+
+ if (!check_again)
+ next_time = timeout - jiffies;
+ else
+ next_time = min(next_time, timeout - jiffies);
+ check_again = true;
+ }
+ }
+ mutex_unlock(&cfg80211_mutex);
+
+ /* reschedule if there are other channels waiting to be cleared again */
+ if (check_again)
+ queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
+ next_time);
}
-EXPORT_SYMBOL(cfg80211_ch_switch_notify);
-bool cfg80211_rx_spurious_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp)
+
+void cfg80211_radar_event(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ gfp_t gfp)
{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- bool ret;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ unsigned long timeout;
- trace_cfg80211_rx_spurious_frame(dev, addr);
+ trace_cfg80211_radar_event(wiphy, chandef);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
- trace_cfg80211_return_bool(false);
- return false;
- }
- ret = nl80211_unexpected_frame(dev, addr, gfp);
- trace_cfg80211_return_bool(ret);
- return ret;
+ /* only set the chandef supplied channel to unavailable, in
+ * case the radar is detected on only one of multiple channels
+ * spanned by the chandef.
+ */
+ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
+
+ timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
+ queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
+ timeout);
+
+ nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
}
-EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
+EXPORT_SYMBOL(cfg80211_radar_event);
-bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp)
+void cfg80211_cac_event(struct net_device *netdev,
+ enum nl80211_radar_event event, gfp_t gfp)
{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- bool ret;
+ struct wireless_dev *wdev = netdev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct cfg80211_chan_def chandef;
+ unsigned long timeout;
- trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
+ trace_cfg80211_cac_event(netdev, event);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO &&
- wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
- trace_cfg80211_return_bool(false);
- return false;
+ if (WARN_ON(!wdev->cac_started))
+ return;
+
+ if (WARN_ON(!wdev->channel))
+ return;
+
+ cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
+
+ switch (event) {
+ case NL80211_RADAR_CAC_FINISHED:
+ timeout = wdev->cac_start_time +
+ msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
+ WARN_ON(!time_after_eq(jiffies, timeout));
+ cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ break;
+ default:
+ WARN_ON(1);
+ return;
}
- ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
- trace_cfg80211_return_bool(ret);
- return ret;
+ wdev->cac_started = false;
+
+ nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
}
-EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
+EXPORT_SYMBOL(cfg80211_cac_event);