Skip to content

Commit

Permalink
mt76: let mac80211 validate CCMP PN for fragmented frames
Browse files Browse the repository at this point in the history
The rules for those are more complex and performance is not an issue
here

Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 committed Jan 25, 2018
1 parent 9f685fe commit c6f8cac
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
16 changes: 15 additions & 1 deletion mac80211.c
Expand Up @@ -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))
Expand All @@ -444,14 +445,27 @@ 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));
if (ret <= 0)
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;
}
Expand Down
49 changes: 42 additions & 7 deletions mt7603_mac.c
Expand Up @@ -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)
{
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 20 additions & 10 deletions mt76x2_mac.c
Expand Up @@ -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) {
Expand All @@ -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;

Expand Down

0 comments on commit c6f8cac

Please sign in to comment.