mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
mt76: let mac80211 validate CCMP PN for fragmented frames
The rules for those are more complex and performance is not an issue here Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
+15
-1
@@ -436,6 +436,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
|
||||
{
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int ret;
|
||||
|
||||
if (!(status->flag & RX_FLAG_DECRYPTED))
|
||||
@@ -444,6 +445,17 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
|
||||
if (!wcid || !wcid->rx_check_pn)
|
||||
return 0;
|
||||
|
||||
if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
|
||||
/*
|
||||
* Validate the first fragment both here and in mac80211
|
||||
* All further fragments will be validated by mac80211 only.
|
||||
*/
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
if (ieee80211_is_frag(hdr) &&
|
||||
!ieee80211_is_first_frag(hdr->frame_control))
|
||||
return 0;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
|
||||
ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
|
||||
sizeof(status->iv));
|
||||
@@ -451,7 +463,9 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
|
||||
return -EINVAL; /* replay */
|
||||
|
||||
memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
|
||||
status->flag |= RX_FLAG_PN_VALIDATED;
|
||||
|
||||
if (status->flag & RX_FLAG_IV_STRIPPED)
|
||||
status->flag |= RX_FLAG_PN_VALIDATED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+42
-7
@@ -367,6 +367,30 @@ mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
|
||||
return &sta->vif->wcid;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
|
||||
{
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
|
||||
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
|
||||
u8 *pn = status->iv;
|
||||
u8 *hdr;
|
||||
|
||||
__skb_push(skb, 8);
|
||||
memmove(skb->data, skb->data + 8, hdr_len);
|
||||
hdr = skb->data + hdr_len;
|
||||
|
||||
hdr[0] = pn[5];
|
||||
hdr[1] = pn[4];
|
||||
hdr[2] = 0;
|
||||
hdr[3] = 0x20 | (key_id << 6);
|
||||
hdr[4] = pn[3];
|
||||
hdr[5] = pn[2];
|
||||
hdr[6] = pn[1];
|
||||
hdr[7] = pn[0];
|
||||
|
||||
status->flag &= ~RX_FLAG_IV_STRIPPED;
|
||||
}
|
||||
|
||||
int
|
||||
mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
@@ -378,6 +402,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
u32 rxd1 = le32_to_cpu(rxd[1]);
|
||||
u32 rxd2 = le32_to_cpu(rxd[2]);
|
||||
bool unicast = rxd1 & MT_RXD1_NORMAL_U2M;
|
||||
bool insert_ccmp_hdr = false;
|
||||
bool remove_pad;
|
||||
int idx;
|
||||
int i;
|
||||
@@ -404,7 +429,8 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
|
||||
!(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED;
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
|
||||
}
|
||||
|
||||
remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
|
||||
@@ -424,12 +450,16 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
|
||||
u8 *data = (u8 *) rxd;
|
||||
|
||||
status->iv[0] = data[5];
|
||||
status->iv[1] = data[4];
|
||||
status->iv[2] = data[3];
|
||||
status->iv[3] = data[2];
|
||||
status->iv[4] = data[1];
|
||||
status->iv[5] = data[0];
|
||||
if (status->flag & RX_FLAG_DECRYPTED) {
|
||||
status->iv[0] = data[5];
|
||||
status->iv[1] = data[4];
|
||||
status->iv[2] = data[3];
|
||||
status->iv[3] = data[2];
|
||||
status->iv[4] = data[1];
|
||||
status->iv[5] = data[0];
|
||||
|
||||
insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
|
||||
}
|
||||
|
||||
rxd += 4;
|
||||
if ((u8 *) rxd - skb->data >= skb->len)
|
||||
@@ -486,6 +516,11 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
|
||||
skb_pull(skb, (u8 *) rxd - skb->data + 2 * remove_pad);
|
||||
|
||||
if (insert_ccmp_hdr) {
|
||||
u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
|
||||
mt7603_insert_ccmp_hdr(skb, key_id);
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
+20
-10
@@ -317,6 +317,16 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
|
||||
if (rxinfo & MT_RXINFO_L2PAD)
|
||||
pad_len += 2;
|
||||
|
||||
if (rxinfo & MT_RXINFO_DECRYPT) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_MIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED;
|
||||
}
|
||||
|
||||
wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
|
||||
status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast);
|
||||
|
||||
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
|
||||
pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
|
||||
if (pn_len) {
|
||||
@@ -330,23 +340,23 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
|
||||
status->iv[4] = data[1];
|
||||
status->iv[5] = data[0];
|
||||
|
||||
pad_len += pn_len << 2;
|
||||
len -= pn_len << 2;
|
||||
/*
|
||||
* Driver CCMP validation can't deal with fragments.
|
||||
* Let mac80211 take care of it.
|
||||
*/
|
||||
if (rxinfo & MT_RXINFO_FRAG) {
|
||||
status->flag &= ~RX_FLAG_IV_STRIPPED;
|
||||
} else {
|
||||
pad_len += pn_len << 2;
|
||||
len -= pn_len << 2;
|
||||
}
|
||||
}
|
||||
|
||||
mt76x2_remove_hdr_pad(skb, pad_len);
|
||||
|
||||
wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
|
||||
status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast);
|
||||
|
||||
if (rxinfo & MT_RXINFO_BA)
|
||||
status->aggr = true;
|
||||
|
||||
if (rxinfo & MT_RXINFO_DECRYPT) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(len > skb->len))
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user