mac80211: consolidate MIC failure report handling
Currently, mac80211 handles MIC failures differently depending on whenever they are detected by the stack's own software crypto or when are handed down from the driver. This patch tries to unify both by moving the special branch out of mac80211 rx hotpath and into into the software crypto part. This has the advantage that we can run a few more sanity checks on the data and verify if the key type was TKIP. This is very handy because several devices generate false postive MIC failure reports. Like carl9170, ath9k and wl12xx: <http://www.spinics.net/lists/linux-wireless/msg68494.html> "mac80211: report MIC failure for truncated packets in AP mode" Cc: Luciano Coelho <coelho@ti.com> Cc: Arik Nemtsov <arik@wizery.com> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
0ca699552c
Коммит
816c04fe7e
|
@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
|
|||
return RX_QUEUED;
|
||||
}
|
||||
|
||||
static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
|
||||
struct ieee80211_rx_data *rx)
|
||||
{
|
||||
int keyidx;
|
||||
unsigned int hdrlen;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (rx->skb->len >= hdrlen + 4)
|
||||
keyidx = rx->skb->data[hdrlen + 3] >> 6;
|
||||
else
|
||||
keyidx = -1;
|
||||
|
||||
if (!rx->sta) {
|
||||
/*
|
||||
* Some hardware seem to generate incorrect Michael MIC
|
||||
* reports; ignore them to avoid triggering countermeasures.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return;
|
||||
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
|
||||
/*
|
||||
* APs with pairwise keys should never receive Michael MIC
|
||||
* errors for non-zero keyidx because these are reserved for
|
||||
* group keys and only the AP is sending real multicast
|
||||
* frames in the BSS.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control))
|
||||
return;
|
||||
|
||||
mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
|
||||
/* TODO: use IEEE80211_RX_FRAGMENTED */
|
||||
static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
||||
struct ieee80211_rate *rate)
|
||||
|
@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
if (!prepares)
|
||||
return false;
|
||||
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR) {
|
||||
if (status->rx_flags & IEEE80211_RX_RA_MATCH)
|
||||
ieee80211_rx_michael_mic_report(hdr, rx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!consume) {
|
||||
skb = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
|
|
|
@ -87,14 +87,50 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
/* No way to verify the MIC if the hardware stripped it */
|
||||
if (status->flag & RX_FLAG_MMIC_STRIPPED)
|
||||
/*
|
||||
* it makes no sense to check for MIC errors on anything other
|
||||
* than data frames.
|
||||
*/
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
|
||||
!ieee80211_has_protected(hdr->frame_control) ||
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
/*
|
||||
* No way to verify the MIC if the hardware stripped it or
|
||||
* the IV with the key index. In this case we have solely rely
|
||||
* on the driver to set RX_FLAG_MMIC_ERROR in the event of a
|
||||
* MIC failure report.
|
||||
*/
|
||||
if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR)
|
||||
goto mic_fail;
|
||||
|
||||
if (!(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
goto update_iv;
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some hardware seems to generate Michael MIC failure reports; even
|
||||
* though, the frame was not encrypted with TKIP and therefore has no
|
||||
* MIC. Ignore the flag them to avoid triggering countermeasures.
|
||||
*/
|
||||
if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
|
||||
!(status->flag & RX_FLAG_DECRYPTED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
|
||||
/*
|
||||
* APs with pairwise keys should never receive Michael MIC
|
||||
* errors for non-zero keyidx because these are reserved for
|
||||
* group keys and only the AP is sending real multicast
|
||||
* frames in the BSS. (
|
||||
*/
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_MMIC_ERROR)
|
||||
goto mic_fail;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (skb->len < hdrlen + MICHAEL_MIC_LEN)
|
||||
|
@ -102,27 +138,25 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
|
||||
data = skb->data + hdrlen;
|
||||
data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
|
||||
|
||||
key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
|
||||
michael_mic(key, hdr, data, data_len, mic);
|
||||
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) {
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
|
||||
(void *) skb->data, NULL,
|
||||
GFP_ATOMIC);
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
|
||||
goto mic_fail;
|
||||
|
||||
/* remove Michael MIC from payload */
|
||||
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
|
||||
|
||||
update_iv:
|
||||
/* update IV in key information to be able to detect replays */
|
||||
rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
|
||||
rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
||||
mic_fail:
|
||||
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
|
||||
(void *) skb->data, NULL, GFP_ATOMIC);
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче