summaryrefslogtreecommitdiff
path: root/net/wireless/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c78
1 files changed, 68 insertions, 10 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6783e0672dcb..d13310fef691 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -237,6 +237,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (!wdev_running(wdev))
return;
+ cfg80211_pmsr_wdev_down(wdev);
rdev_stop_p2p_device(rdev, wdev);
wdev->is_running = false;
@@ -264,6 +265,8 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
if (!wdev_running(wdev))
return;
+ cfg80211_pmsr_wdev_down(wdev);
+
/*
* If there is a scheduled update pending, mark it as canceled, so the
* empty schedule will be accepted
@@ -322,6 +325,28 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,
return 0;
}
+void cfg80211_stop_pd(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ lockdep_assert_held(&rdev->wiphy.mtx);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_PD))
+ return;
+
+ if (!rdev->ops->stop_pd)
+ return;
+
+ if (!wdev_running(wdev))
+ return;
+
+ cfg80211_pmsr_wdev_down(wdev);
+
+ rdev_stop_pd(rdev, wdev);
+ wdev->is_running = false;
+
+ rdev->opencount--;
+}
+
void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -351,6 +376,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
case NL80211_IFTYPE_NAN:
cfg80211_stop_nan(rdev, wdev);
break;
+ case NL80211_IFTYPE_PD:
+ cfg80211_stop_pd(rdev, wdev);
+ break;
default:
break;
}
@@ -804,6 +832,24 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
return ret;
}
+static bool wiphy_cipher_suites_valid(const struct wiphy *wiphy)
+{
+ int i, j;
+
+ if (wiphy->n_cipher_suites && !wiphy->cipher_suites)
+ return false;
+
+ for (i = 0; i < wiphy->n_cipher_suites; i++) {
+ for (j = 0; j < i; j++) {
+ if (wiphy->cipher_suites[i] ==
+ wiphy->cipher_suites[j])
+ return false;
+ }
+ }
+
+ return true;
+}
+
int wiphy_register(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -828,6 +874,9 @@ int wiphy_register(struct wiphy *wiphy)
(!rdev->ops->tdls_channel_switch ||
!rdev->ops->tdls_cancel_channel_switch)))
return -EINVAL;
+ if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_PD)) &&
+ (!rdev->ops->start_pd || !rdev->ops->stop_pd)))
+ return -EINVAL;
if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
(!rdev->ops->start_nan || !rdev->ops->stop_nan ||
@@ -836,7 +885,7 @@ int wiphy_register(struct wiphy *wiphy)
return -EINVAL;
if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN_DATA)) &&
- !wiphy->nan_capa.phy.ht.ht_supported))
+ (!wiphy->nan_capa.phy.ht.ht_supported || wiphy->n_radio > 1)))
return -EINVAL;
if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)))
@@ -871,9 +920,7 @@ int wiphy_register(struct wiphy *wiphy)
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_80P80) |
BIT(NL80211_CHAN_WIDTH_160) |
- BIT(NL80211_CHAN_WIDTH_320) |
- BIT(NL80211_CHAN_WIDTH_5) |
- BIT(NL80211_CHAN_WIDTH_10))))
+ BIT(NL80211_CHAN_WIDTH_320))))
return -EINVAL;
}
@@ -940,6 +987,9 @@ int wiphy_register(struct wiphy *wiphy)
if (res)
return res;
+ if (!wiphy_cipher_suites_valid(wiphy))
+ return -EINVAL;
+
/* sanity check supported bands/channels */
for (band = 0; band < NUM_NL80211_BANDS; band++) {
const struct ieee80211_sband_iftype_data *iftd;
@@ -1288,6 +1338,7 @@ void wiphy_unregister(struct wiphy *wiphy)
/* this has nothing to do now but make sure it's gone */
cancel_work_sync(&rdev->wiphy_work);
+ cancel_work_sync(&rdev->sched_scan_res_wk);
cancel_work_sync(&rdev->rfkill_block);
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
@@ -1377,6 +1428,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
list_del_rcu(&wdev->list);
synchronize_net();
rdev->devlist_generation++;
+ wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
cfg80211_mlme_purge_registrations(wdev);
@@ -1387,6 +1439,9 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
case NL80211_IFTYPE_NAN:
cfg80211_stop_nan(rdev, wdev);
break;
+ case NL80211_IFTYPE_PD:
+ cfg80211_stop_pd(rdev, wdev);
+ break;
default:
break;
}
@@ -1495,6 +1550,9 @@ void cfg80211_leave_locked(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_NAN:
cfg80211_stop_nan(rdev, wdev);
break;
+ case NL80211_IFTYPE_PD:
+ cfg80211_stop_pd(rdev, wdev);
+ break;
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_NAN_DATA:
@@ -1560,7 +1618,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
INIT_LIST_HEAD(&wdev->mgmt_registrations);
INIT_LIST_HEAD(&wdev->pmsr_list);
spin_lock_init(&wdev->pmsr_lock);
- INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
+ wiphy_work_init(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
#ifdef CONFIG_CFG80211_WEXT
wdev->wext.default_key = -1;
@@ -1584,7 +1642,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
wdev->netdev->priv_flags |= IFF_DONT_BRIDGE;
- INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
+ wiphy_work_init(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
}
void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
@@ -1690,11 +1748,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
case NETDEV_GOING_DOWN:
cfg80211_leave(rdev, wdev, -1);
- scoped_guard(wiphy, &rdev->wiphy)
+ scoped_guard(wiphy, &rdev->wiphy) {
cfg80211_remove_links(wdev);
- /* since we just did cfg80211_leave() nothing to do there */
- cancel_work_sync(&wdev->disconnect_wk);
- cancel_work_sync(&wdev->pmsr_free_wk);
+ /* since we just did cfg80211_leave() nothing to do there */
+ wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
+ }
break;
case NETDEV_DOWN:
wiphy_lock(&rdev->wiphy);