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;