diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 12 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 36 | ||||
-rw-r--r-- | net/wireless/scan.c | 53 |
4 files changed, 64 insertions, 39 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index c22ef3492ee..880dbe2e6f9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -366,6 +366,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); + mutex_init(&rdev->sched_scan_mtx); INIT_LIST_HEAD(&rdev->netdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); @@ -701,6 +702,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) rfkill_destroy(rdev->rfkill); mutex_destroy(&rdev->mtx); mutex_destroy(&rdev->devlist_mtx); + mutex_destroy(&rdev->sched_scan_mtx); list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); cfg80211_rdev_free_wowlan(rdev); @@ -737,12 +739,16 @@ static void wdev_cleanup_work(struct work_struct *work) ___cfg80211_scan_done(rdev, true); } + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->sched_scan_mtx); + if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { __cfg80211_stop_sched_scan(rdev, false); } - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_lock(&rdev->devlist_mtx); rdev->opencount--; @@ -830,9 +836,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, false); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT diff --git a/net/wireless/core.h b/net/wireless/core.h index 3dce1f167eb..a570ff9214e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -65,6 +65,8 @@ struct cfg80211_registered_device { struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; + struct mutex sched_scan_mtx; + #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; #endif diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ec83f413a7e..cea338150d0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3406,12 +3406,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) i = 0; if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { - if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) { + if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { err = -EINVAL; goto out_free; } - memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); request->ssids[i].ssid_len = nla_len(attr); + memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); i++; } } @@ -3461,9 +3461,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (rdev->sched_scan_req) - return -EINPROGRESS; - if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) return -EINVAL; @@ -3502,12 +3499,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (ie_len > wiphy->max_scan_ie_len) return -EINVAL; + mutex_lock(&rdev->sched_scan_mtx); + + if (rdev->sched_scan_req) { + err = -EINPROGRESS; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); - if (!request) - return -ENOMEM; + if (!request) { + err = -ENOMEM; + goto out; + } if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3572,14 +3578,13 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { - if (request->ssids[i].ssid_len > - IEEE80211_MAX_SSID_LEN) { + if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { err = -EINVAL; goto out_free; } + request->ssids[i].ssid_len = nla_len(attr); memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); - request->ssids[i].ssid_len = nla_len(attr); i++; } } @@ -3606,6 +3611,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, out_free: kfree(request); out: + mutex_unlock(&rdev->sched_scan_mtx); return err; } @@ -3613,12 +3619,17 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || !rdev->ops->sched_scan_stop) return -EOPNOTSUPP; - return __cfg80211_stop_sched_scan(rdev, false); + mutex_lock(&rdev->sched_scan_mtx); + err = __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + return err; } static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, @@ -6464,7 +6475,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (key_id != -1) + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); if (tsc) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 73a441d237b..ae0c2256ba3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -100,14 +100,14 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); /* we don't have sched_scan_req anymore if the scan is stopping */ if (rdev->sched_scan_req) nl80211_send_sched_scan_results(rdev, rdev->sched_scan_req->dev); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } void cfg80211_sched_scan_results(struct wiphy *wiphy) @@ -123,9 +123,9 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, true); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } EXPORT_SYMBOL(cfg80211_sched_scan_stopped); @@ -135,7 +135,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, int err; struct net_device *dev; - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (!rdev->sched_scan_req) return 0; @@ -267,13 +267,35 @@ static bool is_bss(struct cfg80211_bss *a, return memcmp(ssidie + 2, ssid, ssid_len) == 0; } +static bool is_mesh_bss(struct cfg80211_bss *a) +{ + const u8 *ie; + + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + return true; +} + static bool is_mesh(struct cfg80211_bss *a, const u8 *meshid, size_t meshidlen, const u8 *meshcfg) { const u8 *ie; - if (!WLAN_CAPABILITY_IS_MBSS(a->capability)) + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) return false; ie = cfg80211_find_ie(WLAN_EID_MESH_ID, @@ -311,7 +333,7 @@ static int cmp_bss(struct cfg80211_bss *a, if (a->channel != b->channel) return b->channel->center_freq - a->channel->center_freq; - if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) { + if (is_mesh_bss(a) && is_mesh_bss(b)) { r = cmp_ies(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements, @@ -457,7 +479,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *res) { struct cfg80211_internal_bss *found = NULL; - const u8 *meshid, *meshcfg; /* * The reference to "res" is donated to this function. @@ -470,22 +491,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, res->ts = jiffies; - if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) { - /* must be mesh, verify */ - meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, - res->pub.information_elements, - res->pub.len_information_elements); - meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - res->pub.information_elements, - res->pub.len_information_elements); - if (!meshid || !meshcfg || - meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { - /* bogus mesh */ - kref_put(&res->ref, bss_release); - return NULL; - } - } - spin_lock_bh(&dev->bss_lock); found = rb_find_bss(dev, res); |