Commit 9618aec3 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2017-10-25' of...

Merge tag 'mac80211-for-davem-2017-10-25' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
pull-request: mac80211 2017-10-25

Here are:
 * follow-up fixes for the WoWLAN security issue, to fix a
   partial TKIP key material problem and to use crypto_memneq()
 * a change for better enforcement of FQ's memory limit
 * a disconnect/connect handling fix, and
 * a user rate mask validation fix
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 78e0ea67 cfbb0d90
...@@ -146,6 +146,7 @@ static void fq_tin_enqueue(struct fq *fq, ...@@ -146,6 +146,7 @@ static void fq_tin_enqueue(struct fq *fq,
fq_flow_get_default_t get_default_func) fq_flow_get_default_t get_default_func)
{ {
struct fq_flow *flow; struct fq_flow *flow;
bool oom;
lockdep_assert_held(&fq->lock); lockdep_assert_held(&fq->lock);
...@@ -167,8 +168,8 @@ static void fq_tin_enqueue(struct fq *fq, ...@@ -167,8 +168,8 @@ static void fq_tin_enqueue(struct fq *fq,
} }
__skb_queue_tail(&flow->queue, skb); __skb_queue_tail(&flow->queue, skb);
oom = (fq->memory_usage > fq->memory_limit);
if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { while (fq->backlog > fq->limit || oom) {
flow = list_first_entry_or_null(&fq->backlogs, flow = list_first_entry_or_null(&fq->backlogs,
struct fq_flow, struct fq_flow,
backlogchain); backlogchain);
...@@ -183,8 +184,10 @@ static void fq_tin_enqueue(struct fq *fq, ...@@ -183,8 +184,10 @@ static void fq_tin_enqueue(struct fq *fq,
flow->tin->overlimit++; flow->tin->overlimit++;
fq->overlimit++; fq->overlimit++;
if (fq->memory_usage > fq->memory_limit) if (oom) {
fq->overmemory++; fq->overmemory++;
oom = (fq->memory_usage > fq->memory_limit);
}
} }
} }
......
...@@ -2727,12 +2727,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, ...@@ -2727,12 +2727,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
if (!ieee80211_sdata_running(sdata)) if (!ieee80211_sdata_running(sdata))
return -ENETDOWN; return -ENETDOWN;
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
ret = drv_set_bitrate_mask(local, sdata, mask);
if (ret)
return ret;
}
/* /*
* If active validate the setting and reject it if it doesn't leave * If active validate the setting and reject it if it doesn't leave
* at least one basic rate usable, since we really have to be able * at least one basic rate usable, since we really have to be able
...@@ -2748,6 +2742,12 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, ...@@ -2748,6 +2742,12 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
} }
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
ret = drv_set_bitrate_mask(local, sdata, mask);
if (ret)
return ret;
}
for (i = 0; i < NUM_NL80211_BANDS; i++) { for (i = 0; i < NUM_NL80211_BANDS; i++) {
struct ieee80211_supported_band *sband = wiphy->bands[i]; struct ieee80211_supported_band *sband = wiphy->bands[i];
int j; int j;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include <crypto/algapi.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
...@@ -609,6 +610,39 @@ void ieee80211_key_free_unused(struct ieee80211_key *key) ...@@ -609,6 +610,39 @@ void ieee80211_key_free_unused(struct ieee80211_key *key)
ieee80211_key_free_common(key); ieee80211_key_free_common(key);
} }
static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP];
u8 *tk_old, *tk_new;
if (!old || new->conf.keylen != old->conf.keylen)
return false;
tk_old = old->conf.key;
tk_new = new->conf.key;
/*
* In station mode, don't compare the TX MIC key, as it's never used
* and offloaded rekeying may not care to send it to the host. This
* is the case in iwlwifi, for example.
*/
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
new->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
new->conf.keylen == WLAN_KEY_LEN_TKIP &&
!(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP);
memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP);
memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
tk_old = tkip_old;
tk_new = tkip_new;
}
return !crypto_memneq(tk_old, tk_new, new->conf.keylen);
}
int ieee80211_key_link(struct ieee80211_key *key, int ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct sta_info *sta) struct sta_info *sta)
...@@ -634,8 +668,7 @@ int ieee80211_key_link(struct ieee80211_key *key, ...@@ -634,8 +668,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
* Silently accept key re-installation without really installing the * Silently accept key re-installation without really installing the
* new version of the key to avoid nonce reuse or replay issues. * new version of the key to avoid nonce reuse or replay issues.
*/ */
if (old_key && key->conf.keylen == old_key->conf.keylen && if (ieee80211_key_identical(sdata, old_key, key)) {
!memcmp(key->conf.key, old_key->conf.key, key->conf.keylen)) {
ieee80211_key_free_unused(key); ieee80211_key_free_unused(key);
ret = 0; ret = 0;
goto out; goto out;
......
...@@ -522,11 +522,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, ...@@ -522,11 +522,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (wdev->current_bss) { if (wdev->current_bss) {
if (!prev_bssid)
return -EALREADY;
if (prev_bssid &&
!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
return -ENOTCONN;
cfg80211_unhold_bss(wdev->current_bss); cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL; wdev->current_bss = NULL;
...@@ -1063,11 +1058,35 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, ...@@ -1063,11 +1058,35 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (WARN_ON(wdev->connect_keys)) { /*
kzfree(wdev->connect_keys); * If we have an ssid_len, we're trying to connect or are
wdev->connect_keys = NULL; * already connected, so reject a new SSID unless it's the
* same (which is the case for re-association.)
*/
if (wdev->ssid_len &&
(wdev->ssid_len != connect->ssid_len ||
memcmp(wdev->ssid, connect->ssid, wdev->ssid_len)))
return -EALREADY;
/*
* If connected, reject (re-)association unless prev_bssid
* matches the current BSSID.
*/
if (wdev->current_bss) {
if (!prev_bssid)
return -EALREADY;
if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
return -ENOTCONN;
} }
/*
* Reject if we're in the process of connecting with WEP,
* this case isn't very interesting and trying to handle
* it would make the code much more complex.
*/
if (wdev->connect_keys)
return -EINPROGRESS;
cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
rdev->wiphy.ht_capa_mod_mask); rdev->wiphy.ht_capa_mod_mask);
...@@ -1118,6 +1137,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, ...@@ -1118,6 +1137,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
if (err) { if (err) {
wdev->connect_keys = NULL; wdev->connect_keys = NULL;
/*
* This could be reassoc getting refused, don't clear
* ssid_len in that case.
*/
if (!wdev->current_bss)
wdev->ssid_len = 0; wdev->ssid_len = 0;
return err; return err;
} }
...@@ -1145,6 +1169,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, ...@@ -1145,6 +1169,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
else if (wdev->ssid_len) else if (wdev->ssid_len)
err = rdev_disconnect(rdev, dev, reason); err = rdev_disconnect(rdev, dev, reason);
/*
* Clear ssid_len unless we actually were fully connected,
* in which case cfg80211_disconnected() will take care of
* this later.
*/
if (!wdev->current_bss)
wdev->ssid_len = 0;
return err; return err;
} }
......
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