On Fri, May 08, 2020 at 10:53:30AM +0200, Stefan Sperling wrote: > So the diff below contains just the reordering fix for drivers using > hardware acceleration for WPA.
Is there anybody who wants to OK this? To recap: Currently, CCMP replay checking is skipped for aggregated 11n frames on drivers which use CCMP hardware acceleration: athn(4) and iwn(4). This diff makes reply checking in that case possible without false positives, by updating the last-seen packet number after the aggregated subframes, which may be received out of order, have been put back into their intended order by ieee80211_input_ba(). The old code only works in the single-frame case for 11a/b/g modes where no such legitimate re-transmissions can occur. > diff refs/heads/master refs/heads/pn > blob - 9193ae3c7b5101a86b85b1b3ba48489d75f5150c > blob + 8bc189dc146562f7ab0af2f1690fa02676aecfcd > --- sys/dev/ic/ar5008.c > +++ sys/dev/ic/ar5008.c > @@ -794,9 +794,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf * > struct ieee80211_frame *wh; > struct ieee80211_rx_ba *ba; > uint64_t pn, *prsc; > - u_int8_t *ivp, *mmie; > + u_int8_t *ivp; > uint8_t tid; > - uint16_t kid; > int hdrlen, hasqos; > uintptr_t entry; > > @@ -805,35 +804,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf * > ivp = mtod(m, u_int8_t *) + hdrlen; > > /* find key for decryption */ > - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { > - k = &ni->ni_pairwise_key; > - } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != > - IEEE80211_FC0_TYPE_MGT) { > - /* retrieve group data key id from IV field */ > - /* check that IV field is present */ > - if (m->m_len < hdrlen + 4) > - return 1; > - kid = ivp[3] >> 6; > - k = &ic->ic_nw_keys[kid]; > - } else { > - /* retrieve integrity group key id from MMIE */ > - if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) { > - return 1; > - } > - /* it is assumed management frames are contiguous */ > - mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN; > - /* check that MMIE is valid */ > - if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) { > - return 1; > - } > - kid = LE_READ_2(&mmie[2]); > - if (kid != 4 && kid != 5) { > - return 1; > - } > - k = &ic->ic_nw_keys[kid]; > - } > - > - if (k->k_cipher != IEEE80211_CIPHER_CCMP) > + k = ieee80211_get_rxkey(ic, m, ni); > + if (k == NULL || k->k_cipher != IEEE80211_CIPHER_CCMP) > return 1; > > /* Sanity checks to ensure this is really a key we installed. */ > @@ -853,7 +825,7 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf * > hasqos = ieee80211_has_qos(wh); > tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > ba = hasqos ? &ni->ni_rx_ba[tid] : NULL; > - prsc = &k->k_rsc[0]; > + prsc = &k->k_rsc[tid]; > > /* Extract the 48-bit PN from the CCMP header. */ > pn = (uint64_t)ivp[0] | > @@ -863,30 +835,12 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf * > (uint64_t)ivp[6] << 32 | > (uint64_t)ivp[7] << 40; > if (pn <= *prsc) { > - if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) { > - /* > - * This is an A-MPDU subframe. > - * Such frames may be received out of order due to > - * legitimate retransmissions of failed subframes > - * in previous A-MPDUs. Duplicates will be handled > - * in ieee80211_inputm() as part of A-MPDU reordering. > - * > - * XXX TODO We can probably do better than this! Store > - * re-ordered PN in BA agreement state and check it? > - */ > - } else { > - ic->ic_stats.is_ccmp_replays++; > - return 1; > - } > + ic->ic_stats.is_ccmp_replays++; > + return 1; > } > - /* Update last seen packet number. */ > - *prsc = pn; > + /* Last seen packet number is updated in ieee80211_inputm(). */ > > - /* Clear Protected bit and strip IV. */ > - wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; > - memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); > - m_adj(m, IEEE80211_CCMP_HDRLEN); > - /* Strip MIC. */ > + /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ > m_adj(m, -IEEE80211_CCMP_MICLEN); > return 0; > } > blob - 6b6331d167a881a526b9d0a30f7f452882fee19a > blob + 620cbd4c138516398a4683d83c1b6bf8aac57c82 > --- sys/dev/pci/if_iwn.c > +++ sys/dev/pci/if_iwn.c > @@ -1936,47 +1936,13 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, s > (uint64_t)ivp[6] << 32 | > (uint64_t)ivp[7] << 40; > if (pn <= *prsc) { > - if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) { > - /* > - * This is an A-MPDU subframe. > - * Such frames may be received out of order due to > - * legitimate retransmissions of failed subframes > - * in previous A-MPDUs. Duplicates will be handled > - * in ieee80211_inputm() as part of A-MPDU reordering. > - */ > - } else if (ieee80211_has_seq(wh)) { > - /* > - * Not necessarily a replayed frame since we did not > - * check the sequence number of the 802.11 header yet. > - */ > - int nrxseq, orxseq; > - > - nrxseq = letoh16(*(u_int16_t *)wh->i_seq) >> > - IEEE80211_SEQ_SEQ_SHIFT; > - if (hasqos) > - orxseq = ni->ni_qos_rxseqs[tid]; > - else > - orxseq = ni->ni_rxseq; > - if (nrxseq < orxseq) { > - DPRINTF(("CCMP replayed (n=%d < o=%d)\n", > - nrxseq, orxseq)); > - ic->ic_stats.is_ccmp_replays++; > - return 1; > - } > - } else { > - DPRINTF(("CCMP replayed\n")); > - ic->ic_stats.is_ccmp_replays++; > - return 1; > - } > + DPRINTF(("CCMP replayed\n")); > + ic->ic_stats.is_ccmp_replays++; > + return 1; > } > - /* Update last seen packet number. */ > - *prsc = pn; > + /* Last seen packet number is updated in ieee80211_inputm(). */ > > - /* Clear Protected bit and strip IV. */ > - wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; > - memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); > - m_adj(m, IEEE80211_CCMP_HDRLEN); > - /* Strip MIC. */ > + /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ > m_adj(m, -IEEE80211_CCMP_MICLEN); > return 0; > } > blob - 23514161af1c3576b1f594a1068f95a359b4ea1b > blob + 87bbeeabbb06f66d1ecde98b147c18df98143ae9 > --- sys/dev/pci/if_wpi.c > +++ sys/dev/pci/if_wpi.c > @@ -1132,6 +1132,7 @@ wpi_calib_timeout(void *arg) > int > wpi_ccmp_decap(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_key *k) > { > + struct ieee80211com *ic = &sc->sc_ic; > struct ieee80211_frame *wh; > uint64_t pn, *prsc; > uint8_t *ivp; > @@ -1159,21 +1160,13 @@ wpi_ccmp_decap(struct wpi_softc *sc, struct mbuf *m, s > (uint64_t)ivp[6] << 32 | > (uint64_t)ivp[7] << 40; > if (pn <= *prsc) { > - /* > - * Not necessarily a replayed frame since we did not check > - * the sequence number of the 802.11 header yet. > - */ > DPRINTF(("CCMP replayed\n")); > + ic->ic_stats.is_ccmp_replays++; > return 1; > } > - /* Update last seen packet number. */ > - *prsc = pn; > + /* Last seen packet number is updated in ieee80211_inputm(). */ > > - /* Clear Protected bit and strip IV. */ > - wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; > - memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); > - m_adj(m, IEEE80211_CCMP_HDRLEN); > - /* Strip MIC. */ > + /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ > m_adj(m, -IEEE80211_CCMP_MICLEN); > return 0; > } > blob - f7683fc8f15fb5bdca674900571d0c9d0ca36079 > blob + bf287803d05a86f4f6113b44206382a26b188b05 > --- sys/net80211/ieee80211_crypto.c > +++ sys/net80211/ieee80211_crypto.c > @@ -209,6 +209,50 @@ ieee80211_get_txkey(struct ieee80211com *ic, const str > return &ic->ic_nw_keys[kid]; > } > > +struct ieee80211_key * > +ieee80211_get_rxkey(struct ieee80211com *ic, struct mbuf *m, > + struct ieee80211_node *ni) > +{ > + struct ieee80211_key *k = NULL; > + struct ieee80211_frame *wh; > + u_int16_t kid; > + u_int8_t *ivp, *mmie; > + int hdrlen; > + > + wh = mtod(m, struct ieee80211_frame *); > + if ((ic->ic_flags & IEEE80211_F_RSNON) && > + !IEEE80211_IS_MULTICAST(wh->i_addr1) && > + ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { > + k = &ni->ni_pairwise_key; > + } else if (!IEEE80211_IS_MULTICAST(wh->i_addr1) || > + (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != > + IEEE80211_FC0_TYPE_MGT) { > + /* retrieve group data key id from IV field */ > + hdrlen = ieee80211_get_hdrlen(wh); > + /* check that IV field is present */ > + if (m->m_len < hdrlen + 4) > + return NULL; > + ivp = (u_int8_t *)wh + hdrlen; > + kid = ivp[3] >> 6; > + k = &ic->ic_nw_keys[kid]; > + } else { > + /* retrieve integrity group key id from MMIE */ > + if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) > + return NULL; > + /* it is assumed management frames are contiguous */ > + mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN; > + /* check that MMIE is valid */ > + if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) > + return NULL; > + kid = LE_READ_2(&mmie[2]); > + if (kid != 4 && kid != 5) > + return NULL; > + k = &ic->ic_nw_keys[kid]; > + } > + > + return k; > +} > + > struct mbuf * > ieee80211_encrypt(struct ieee80211com *ic, struct mbuf *m0, > struct ieee80211_key *k) > @@ -241,54 +285,11 @@ struct mbuf * > ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0, > struct ieee80211_node *ni) > { > - struct ieee80211_frame *wh; > struct ieee80211_key *k; > - u_int8_t *ivp, *mmie; > - u_int16_t kid; > - int hdrlen; > > /* find key for decryption */ > - wh = mtod(m0, struct ieee80211_frame *); > - if ((ic->ic_flags & IEEE80211_F_RSNON) && > - !IEEE80211_IS_MULTICAST(wh->i_addr1) && > - ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { > - k = &ni->ni_pairwise_key; > - > - } else if (!IEEE80211_IS_MULTICAST(wh->i_addr1) || > - (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != > - IEEE80211_FC0_TYPE_MGT) { > - /* retrieve group data key id from IV field */ > - hdrlen = ieee80211_get_hdrlen(wh); > - /* check that IV field is present */ > - if (m0->m_len < hdrlen + 4) { > - m_freem(m0); > - return NULL; > - } > - ivp = (u_int8_t *)wh + hdrlen; > - kid = ivp[3] >> 6; > - k = &ic->ic_nw_keys[kid]; > - } else { > - /* retrieve integrity group key id from MMIE */ > - if (m0->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) { > - m_freem(m0); > - return NULL; > - } > - /* it is assumed management frames are contiguous */ > - mmie = (u_int8_t *)wh + m0->m_len - IEEE80211_MMIE_LEN; > - /* check that MMIE is valid */ > - if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) { > - m_freem(m0); > - return NULL; > - } > - kid = LE_READ_2(&mmie[2]); > - if (kid != 4 && kid != 5) { > - m_freem(m0); > - return NULL; > - } > - k = &ic->ic_nw_keys[kid]; > - } > - > - if ((k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) { > + k = ieee80211_get_rxkey(ic, m0, ni); > + if (k == NULL || (k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) { > m_free(m0); > return NULL; > } > blob - a3bc45c699af9a53dbdad4a39e984c00999b105a > blob + f54fff2981e70909d96a4c8ed66d0c1ea664d6ac > --- sys/net80211/ieee80211_crypto.h > +++ sys/net80211/ieee80211_crypto.h > @@ -160,6 +160,8 @@ void ieee80211_tkip_delete_key(struct ieee80211com *, > struct ieee80211_key *); > struct mbuf *ieee80211_tkip_encrypt(struct ieee80211com *, > struct mbuf *, struct ieee80211_key *); > +int ieee80211_tkip_get_tsc(uint64_t *, uint64_t **, struct mbuf *, > + struct ieee80211_key *); > struct mbuf *ieee80211_tkip_decrypt(struct ieee80211com *, > struct mbuf *, struct ieee80211_key *); > void ieee80211_tkip_mic(struct mbuf *, int, const u_int8_t *, > @@ -173,6 +175,8 @@ int ieee80211_ccmp_set_key(struct ieee80211com *, > stru > void ieee80211_ccmp_delete_key(struct ieee80211com *, > struct ieee80211_key *); > struct mbuf *ieee80211_ccmp_encrypt(struct ieee80211com *, struct mbuf > *, > + struct ieee80211_key *); > +int ieee80211_ccmp_get_pn(uint64_t *, uint64_t **, struct mbuf *, > struct ieee80211_key *); > struct mbuf *ieee80211_ccmp_decrypt(struct ieee80211com *, struct mbuf > *, > struct ieee80211_key *); > blob - f4c8748602f910f75ab4f4eea042df80e398d244 > blob + 5885e174818b83fc20e24e5fa31b721df6275c4a > --- sys/net80211/ieee80211_crypto_ccmp.c > +++ sys/net80211/ieee80211_crypto_ccmp.c > @@ -300,6 +300,45 @@ ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct > return NULL; > } > > +int > +ieee80211_ccmp_get_pn(uint64_t *pn, uint64_t **prsc, struct mbuf *m, > + struct ieee80211_key *k) > +{ > + struct ieee80211_frame *wh; > + int hdrlen; > + const u_int8_t *ivp; > + > + wh = mtod(m, struct ieee80211_frame *); > + hdrlen = ieee80211_get_hdrlen(wh); > + if (m->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN) > + return EINVAL; > + > + ivp = (u_int8_t *)wh + hdrlen; > + > + /* check that ExtIV bit is set */ > + if (!(ivp[3] & IEEE80211_WEP_EXTIV)) > + return EINVAL; > + > + /* retrieve last seen packet number for this frame type/priority */ > + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == > + IEEE80211_FC0_TYPE_DATA) { > + u_int8_t tid = ieee80211_has_qos(wh) ? > + ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > + *prsc = &k->k_rsc[tid]; > + } else /* 11w: management frames have their own counters */ > + *prsc = &k->k_mgmt_rsc; > + > + /* extract the 48-bit PN from the CCMP header */ > + *pn = (u_int64_t)ivp[0] | > + (u_int64_t)ivp[1] << 8 | > + (u_int64_t)ivp[4] << 16 | > + (u_int64_t)ivp[5] << 24 | > + (u_int64_t)ivp[6] << 32 | > + (u_int64_t)ivp[7] << 40; > + > + return 0; > +} > + > struct mbuf * > ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0, > struct ieee80211_key *k) > @@ -307,7 +346,7 @@ ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct > struct ieee80211_ccmp_ctx *ctx = k->k_priv; > struct ieee80211_frame *wh; > u_int64_t pn, *prsc; > - const u_int8_t *ivp, *src; > + const u_int8_t *src; > u_int8_t *dst; > u_int8_t mic0[IEEE80211_CCMP_MICLEN]; > u_int8_t a[16], b[16], s0[16], s[16]; > @@ -318,35 +357,20 @@ ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct > > wh = mtod(m0, struct ieee80211_frame *); > hdrlen = ieee80211_get_hdrlen(wh); > - ivp = (u_int8_t *)wh + hdrlen; > - > if (m0->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN + > IEEE80211_CCMP_MICLEN) { > m_freem(m0); > return NULL; > } > - /* check that ExtIV bit is set */ > - if (!(ivp[3] & IEEE80211_WEP_EXTIV)) { > + > + /* > + * Get the frame's Packet Number (PN) and a pointer to our last-seen > + * Receive Sequence Counter (RSC) which we can use to detect replays. > + */ > + if (ieee80211_ccmp_get_pn(&pn, &prsc, m0, k) != 0) { > m_freem(m0); > return NULL; > } > - > - /* retrieve last seen packet number for this frame type/priority */ > - if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == > - IEEE80211_FC0_TYPE_DATA) { > - u_int8_t tid = ieee80211_has_qos(wh) ? > - ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > - prsc = &k->k_rsc[tid]; > - } else /* 11w: management frames have their own counters */ > - prsc = &k->k_mgmt_rsc; > - > - /* extract the 48-bit PN from the CCMP header */ > - pn = (u_int64_t)ivp[0] | > - (u_int64_t)ivp[1] << 8 | > - (u_int64_t)ivp[4] << 16 | > - (u_int64_t)ivp[5] << 24 | > - (u_int64_t)ivp[6] << 32 | > - (u_int64_t)ivp[7] << 40; > if (pn <= *prsc) { > /* replayed frame, discard */ > ic->ic_stats.is_ccmp_replays++; > blob - 70fbe7c9769f9dbd5e9f3cc2fb1961d1282c9e2b > blob + 3473de8eb99d01dce20a0862275a3339e5031a10 > --- sys/net80211/ieee80211_crypto_tkip.c > +++ sys/net80211/ieee80211_crypto_tkip.c > @@ -313,6 +313,42 @@ ieee80211_tkip_encrypt(struct ieee80211com *ic, struct > return NULL; > } > > +int > +ieee80211_tkip_get_tsc(uint64_t *tsc, uint64_t **prsc, struct mbuf *m, > + struct ieee80211_key *k) > +{ > + struct ieee80211_frame *wh; > + int hdrlen; > + u_int8_t tid; > + const u_int8_t *ivp; > + > + wh = mtod(m, struct ieee80211_frame *); > + hdrlen = ieee80211_get_hdrlen(wh); > + > + if (m->m_pkthdr.len < hdrlen + IEEE80211_TKIP_HDRLEN) > + return EINVAL; > + > + ivp = (u_int8_t *)wh + hdrlen; > + /* check that ExtIV bit is set */ > + if (!(ivp[3] & IEEE80211_WEP_EXTIV)) > + return EINVAL; > + > + /* Retrieve last seen packet number for this frame priority. */ > + tid = ieee80211_has_qos(wh) ? > + ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > + *prsc = &k->k_rsc[tid]; > + > + /* extract the 48-bit TSC from the TKIP header */ > + *tsc = (u_int64_t)ivp[2] | > + (u_int64_t)ivp[0] << 8 | > + (u_int64_t)ivp[4] << 16 | > + (u_int64_t)ivp[5] << 24 | > + (u_int64_t)ivp[6] << 32 | > + (u_int64_t)ivp[7] << 40; > + > + return 0; > +} > + > struct mbuf * > ieee80211_tkip_decrypt(struct ieee80211com *ic, struct mbuf *m0, > struct ieee80211_key *k) > @@ -324,8 +360,7 @@ ieee80211_tkip_decrypt(struct ieee80211com *ic, struct > u_int8_t mic[IEEE80211_TKIP_MICLEN]; > u_int64_t tsc, *prsc; > u_int32_t crc, crc0; > - u_int8_t *ivp, *mic0; > - u_int8_t tid; > + u_int8_t *mic0; > struct mbuf *n0, *m, *n; > int hdrlen, left, moff, noff, len; > > @@ -337,25 +372,15 @@ ieee80211_tkip_decrypt(struct ieee80211com *ic, struct > return NULL; > } > > - ivp = (u_int8_t *)wh + hdrlen; > - /* check that ExtIV bit is set */ > - if (!(ivp[3] & IEEE80211_WEP_EXTIV)) { > + /* > + * Get the frame's Tansmit Sequence Counter (TSC), and a pointer to > + * our last-seen Receive Sequence Counter (RSC) with which we can > + * detect replays. > + */ > + if (ieee80211_tkip_get_tsc(&tsc, &prsc, m0, k) != 0) { > m_freem(m0); > return NULL; > } > - > - /* retrieve last seen packet number for this frame priority */ > - tid = ieee80211_has_qos(wh) ? > - ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; > - prsc = &k->k_rsc[tid]; > - > - /* extract the 48-bit TSC from the TKIP header */ > - tsc = (u_int64_t)ivp[2] | > - (u_int64_t)ivp[0] << 8 | > - (u_int64_t)ivp[4] << 16 | > - (u_int64_t)ivp[5] << 24 | > - (u_int64_t)ivp[6] << 32 | > - (u_int64_t)ivp[7] << 40; > if (tsc <= *prsc) { > /* replayed frame, discard */ > ic->ic_stats.is_tkip_replays++; > blob - d802a15ad6ca1eaca39e681fd5e59297fc2ef464 > blob + 2e4714aeaa9a7853b2ba65bacb7d45e6e338d8f8 > --- sys/net80211/ieee80211_input.c > +++ sys/net80211/ieee80211_input.c > @@ -58,6 +58,8 @@ > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_priv.h> > > +struct mbuf *ieee80211_input_hwdecrypt(struct ieee80211com *, > + struct ieee80211_node *, struct mbuf *); > struct mbuf *ieee80211_defrag(struct ieee80211com *, struct mbuf *, > int); > void ieee80211_defrag_timeout(void *); > void ieee80211_input_ba(struct ieee80211com *, struct mbuf *, > @@ -147,6 +149,86 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh) > return size; > } > > +/* Post-processing for drivers which perform decryption in hardware. */ > +struct mbuf * > +ieee80211_input_hwdecrypt(struct ieee80211com *ic, struct ieee80211_node *ni, > + struct mbuf *m) > +{ > + struct ieee80211_key *k; > + struct ieee80211_frame *wh; > + uint64_t pn, *prsc; > + int hdrlen; > + > + k = ieee80211_get_rxkey(ic, m, ni); > + if (k == NULL) > + return NULL; > + > + wh = mtod(m, struct ieee80211_frame *); > + hdrlen = ieee80211_get_hdrlen(wh); > + > + /* > + * Update the last-seen packet number (PN) for drivers using hardware > + * crypto offloading. This cannot be done by drivers because A-MPDU > + * reordering needs to occur before a valid lower bound can be > + * determined for the PN. Drivers will read the PN we write here and > + * are expected to discard replayed frames based on it. > + * Drivers are expected to leave the IV of decrypted frames intact > + * so we can update the last-seen PN and strip the IV here. > + */ > + switch (k->k_cipher) { > + case IEEE80211_CIPHER_CCMP: > + if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { > + /* drop unencrypted */ > + ic->ic_stats.is_rx_unencrypted++; > + return NULL; > + } > + if (ieee80211_ccmp_get_pn(&pn, &prsc, m, k) != 0) > + return NULL; > + if (pn <= *prsc) { > + ic->ic_stats.is_ccmp_replays++; > + return NULL; > + } > + > + /* Update last-seen packet number. */ > + *prsc = pn; > + > + /* Clear Protected bit and strip IV. */ > + wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; > + memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); > + m_adj(m, IEEE80211_CCMP_HDRLEN); > + /* Drivers are expected to strip the MIC. */ > + break; > + case IEEE80211_CIPHER_TKIP: > + if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { > + /* drop unencrypted */ > + ic->ic_stats.is_rx_unencrypted++; > + return NULL; > + } > + if (ieee80211_tkip_get_tsc(&pn, &prsc, m, k) != 0) > + return NULL; > + > + if (pn <= *prsc) { > + ic->ic_stats.is_tkip_replays++; > + return NULL; > + } > + > + /* Update last-seen packet number. */ > + *prsc = pn; > + > + /* Clear Protected bit and strip IV. */ > + wh = mtod(m, struct ieee80211_frame *); > + wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; > + memmove(mtod(m, caddr_t) + IEEE80211_TKIP_HDRLEN, wh, hdrlen); > + m_adj(m, IEEE80211_TKIP_HDRLEN); > + /* Drivers are expected to strip the MIC. */ > + break; > + default: > + break; > + } > + > + return m; > +} > + > /* > * Process a received frame. The node associated with the sender > * should be supplied. If nothing was found in the node table then > @@ -454,8 +536,12 @@ ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, st > ic->ic_stats.is_rx_wepfail++; > goto err; > } > - wh = mtod(m, struct ieee80211_frame *); > + } else { > + m = ieee80211_input_hwdecrypt(ic, ni, m); > + if (m == NULL) > + goto err; > } > + wh = mtod(m, struct ieee80211_frame *); > } else if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) || > (rxi->rxi_flags & IEEE80211_RXI_HWDEC)) { > /* frame encrypted but protection off for Rx */ > >