|
@@ -610,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)
|
|
@@ -635,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 &&
|
|
|
|
- !crypto_memneq(key->conf.key, old_key->conf.key, key->conf.keylen)) {
|
|
|
|
|
|
+ if (ieee80211_key_identical(sdata, old_key, key)) {
|
|
ieee80211_key_free_unused(key);
|
|
ieee80211_key_free_unused(key);
|
|
ret = 0;
|
|
ret = 0;
|
|
goto out;
|
|
goto out;
|