Le Fri, 15 May 2020 11:02:46 +0200,
Stefan Sperling <[email protected]> a écrit :
> 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 */
> >
> >
>
No regression found with following devices, ok solene@
iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 5100" rev 0x00: msi, MIMO 1T2R,
MoW, address 00:1e:65:41:f4:14
urtwn0 at uhub0 port 1 configuration 1 interface 0 "Realtek 802.11n NIC" rev
2.00/0.00 addr 2
athn0 at uhub0 port 1 configuration 1 interface 0 "ATHEROS USB2.0 WLAN" rev
2.00/1.08 addr 2