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:
Felix Fietkau
2018-01-25 11:29:25 +01:00
parent 9f685fea72
commit c6f8caced2
3 changed files with 77 additions and 18 deletions
+15 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;