On Tue, Aug 13, 2019 at 10:47:24AM -0300, Martin Pieuchot wrote:
> if the crash is because of a missing key, put one :)

Yes, you've convinced me. With this patch we install the CCMP key
to both firmware and net80211. Until firmware confirms that the
key has been installed, we do software encrypt/decrypt.

Should the firmware fail to install the key for some reason, we will
just keep using our software fallback until the interface is reset.

This also fixes the race with incoming frames during WPA handshake,
i.e. while (ni->ni_flags & IEEE80211_NODE_RXPROT) == 0.
Such frames can be passed to net80211 and will be dropped there.

Lightly tested on a 7260 device.

Ok?

diff refs/heads/master refs/heads/ccmp-crash2
blob - 038e6a63dfff113b525bb1e9a30c935996535569
blob + 8afcce065eb0d85f4469a3f378cacba1513bc215
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -3595,10 +3595,17 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = device_timestamp;
 
-       /* Handle hardware decryption. */
+       /*
+        * Handle hardware decryption.
+        *
+        * If the WPA handshake has completed but firmware is not yet ready
+        * to decrypt frames, fall back to software decryption in net80211. 
+        * net80211 will drop encrypted frames until the handshake completes.
+        */
        if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
            && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
            !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+           (sc->sc_flags & IWM_FLAG_CCMP_READY) &&
            (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
            ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {
                if ((rx_pkt_status & IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK) !=
@@ -4402,7 +4409,8 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
 
        if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
                k = ieee80211_get_txkey(ic, wh, ni);
-               if  (k->k_cipher != IEEE80211_CIPHER_CCMP) {
+               if  (k->k_cipher != IEEE80211_CIPHER_CCMP ||
+                   (sc->sc_flags & IWM_FLAG_CCMP_READY) == 0) {
                        if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
                                return ENOBUFS;
 
@@ -4418,7 +4426,8 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
        /* Copy 802.11 header in TX command. */
        memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen);
 
-       if  (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) {
+       if  (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP &&
+           (sc->sc_flags & IWM_FLAG_CCMP_READY)) {
                /* Trim 802.11 header and prepend CCMP IV. */
                m_adj(m, hdrlen - IEEE80211_CCMP_HDRLEN);
                ivp = mtod(m, u_int8_t *);
@@ -6090,6 +6099,7 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
 {
        struct iwm_softc *sc = ic->ic_softc;
        struct iwm_add_sta_key_cmd cmd = { 0 };
+       int err;
 
        if ((k->k_flags & IEEE80211_KEY_GROUP) ||
            k->k_cipher != IEEE80211_CIPHER_CCMP)  {
@@ -6097,6 +6107,8 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
                return (ieee80211_set_key(ic, ni, k));
        }
 
+       sc->sc_flags &= ~(IWM_FLAG_CCMP_READY | IWM_FLAG_CCMP_KEY_SENT);
+
        cmd.key_flags = htole16(IWM_STA_KEY_FLG_CCM |
            IWM_STA_KEY_FLG_WEP_KEY_MAP |
            ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) &
@@ -6108,8 +6120,15 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_
        cmd.key_offset = 0;
        cmd.sta_id = IWM_STATION_ID;
 
-       return iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
-           sizeof(cmd), &cmd);
+       /* Allow for software CCMP encryption/decryption fallback. */
+       err = ieee80211_set_key(ic, ni, k);
+       if (!err) {
+               err = iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC,
+                   sizeof(cmd), &cmd);
+               if (!err)
+                       sc->sc_flags |= IWM_FLAG_CCMP_KEY_SENT;
+       }
+       return err;
 }
 
 void
@@ -6135,6 +6154,10 @@ iwm_delete_key(struct ieee80211com *ic, struct ieee802
        cmd.sta_id = IWM_STATION_ID;
 
        iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd);
+       sc->sc_flags &= ~(IWM_FLAG_CCMP_KEY_SENT | IWM_FLAG_CCMP_READY);
+
+       /* Delete software fallback CCMP key. */
+        ieee80211_delete_key(ic, ni, k);
 }
 
 void
@@ -6846,6 +6869,7 @@ iwm_stop(struct ifnet *ifp)
        sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
        sc->sc_flags &= ~IWM_FLAG_HW_ERR;
        sc->sc_flags &= ~IWM_FLAG_SHUTDOWN;
+       sc->sc_flags &= ~(IWM_FLAG_CCMP_KEY_SENT | IWM_FLAG_CCMP_READY);
 
        sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
 
@@ -7331,6 +7355,12 @@ iwm_notif_intr(struct iwm_softc *sc)
                        break;
 
                case IWM_ADD_STA_KEY:
+                       if (sc->sc_flags & IWM_FLAG_CCMP_KEY_SENT) {
+                               sc->sc_flags |= IWM_FLAG_CCMP_READY;
+                               sc->sc_flags &= ~IWM_FLAG_CCMP_KEY_SENT;
+                       }
+                       break;
+
                case IWM_PHY_CONFIGURATION_CMD:
                case IWM_TX_ANT_CONFIGURATION_CMD:
                case IWM_ADD_STA:
blob - e6593fbc840833a36d5a792042faaa85e3ac9719
blob + 747616074f868d8679f9f01232dec4ce09474f93
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -289,6 +289,8 @@ struct iwm_rx_ring {
 #define IWM_FLAG_HW_ERR                0x80    /* hardware error occurred */
 #define IWM_FLAG_SHUTDOWN      0x100   /* shutting down; new tasks forbidden */
 #define IWM_FLAG_BGSCAN                0x200   /* background scan in progress 
*/
+#define IWM_FLAG_CCMP_KEY_SENT 0x400   /* CCMP key sent to firmware */
+#define IWM_FLAG_CCMP_READY    0x800   /* CCMP key installed in firmware */
 
 struct iwm_ucode_status {
        uint32_t uc_error_event_table;

Reply via email to