From 2d7dec1c1858399ca8e7a45f29825f577f2feeae Mon Sep 17 00:00:00 2001 From: adrian <adrian@FreeBSD.org> Date: Mon, 25 Apr 2016 16:13:04 +0000 Subject: [PATCH] [iwn] fix firmware command use in iwm_auth(). The iwm firmware has separate commands for add, modify and delete for various things (mac, phy context, etc.) The openbsd driver has a habit of just completely resetting the NIC each time, which is technically mostly okay (as long as the reset doesn't actually fail!) but it means a lot of the code is doing ADD when it should do MODIFY. The firmware responds in kind - it just asserts. This fixes auth attempts that occur after the NIC has been already configured. (I'm sure there are more instances of this!) Tested: iwm0: <Intel Dual Band Wireless AC 7260> mem 0xf1400000-0xf1401fff irq 17 at device 0.0 on pci2 iwm0: revision: 0x140, firmware 25.228 (API ver. 9) .. STA mode. Submitted by: Masachika ISHIZUKA <ish@amail.plala.or.jp> --- sys/dev/iwm/if_iwm.c | 92 +++++++++++++++------------------ sys/dev/iwm/if_iwm_binding.c | 6 +-- sys/dev/iwm/if_iwm_binding.h | 3 +- sys/dev/iwm/if_iwm_time_event.c | 2 +- sys/dev/iwm/if_iwm_time_event.h | 2 +- 5 files changed, 48 insertions(+), 57 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index d325d647d3e6..d94657f64739 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -3159,7 +3159,6 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *sc) struct iwm_node *in; struct iwm_vap *iv = IWM_VAP(vap); uint32_t duration; - uint32_t min_duration; int error; /* @@ -3201,7 +3200,25 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *sc) if (iv->is_uploaded) { if ((error = iwm_mvm_mac_ctxt_changed(sc, vap)) != 0) { device_printf(sc->sc_dev, - "%s: failed to add MAC\n", __func__); + "%s: failed to update MAC\n", __func__); + goto out; + } + if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], + in->in_ni.ni_chan, 1, 1)) != 0) { + device_printf(sc->sc_dev, + "%s: failed update phy ctxt\n", __func__); + goto out; + } + in->in_phyctxt = &sc->sc_phyctxt[0]; + + if ((error = iwm_mvm_binding_update(sc, in)) != 0) { + device_printf(sc->sc_dev, + "%s: binding update cmd\n", __func__); + goto out; + } + if ((error = iwm_mvm_update_sta(sc, in)) != 0) { + device_printf(sc->sc_dev, + "%s: failed to update sta\n", __func__); goto out; } } else { @@ -3210,61 +3227,36 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *sc) "%s: failed to add MAC\n", __func__); goto out; } - } - - if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], - in->in_ni.ni_chan, 1, 1)) != 0) { - device_printf(sc->sc_dev, - "%s: failed add phy ctxt\n", __func__); - goto out; - } - in->in_phyctxt = &sc->sc_phyctxt[0]; - - if ((error = iwm_mvm_binding_add_vif(sc, in)) != 0) { - device_printf(sc->sc_dev, - "%s: binding cmd\n", __func__); - goto out; - } - - if ((error = iwm_mvm_add_sta(sc, in)) != 0) { - device_printf(sc->sc_dev, - "%s: failed to add MAC\n", __func__); - goto out; - } - - /* a bit superfluous? */ - while (sc->sc_auth_prot) - msleep(&sc->sc_auth_prot, &sc->sc_mtx, 0, "iwmauth", 0); - sc->sc_auth_prot = 1; - - duration = min(IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, - 200 + in->in_ni.ni_intval); - min_duration = min(IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, - 100 + in->in_ni.ni_intval); - iwm_mvm_protect_session(sc, in, duration, min_duration, 500); - - IWM_DPRINTF(sc, IWM_DEBUG_RESET, - "%s: waiting for auth_prot\n", __func__); - while (sc->sc_auth_prot != 2) { - /* - * well, meh, but if the kernel is sleeping for half a - * second, we have bigger problems - */ - if (sc->sc_auth_prot == 0) { + if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0], + in->in_ni.ni_chan, 1, 1)) != 0) { device_printf(sc->sc_dev, - "%s: missed auth window!\n", __func__); + "%s: failed add phy ctxt!\n", __func__); error = ETIMEDOUT; goto out; - } else if (sc->sc_auth_prot == -1) { + } + in->in_phyctxt = &sc->sc_phyctxt[0]; + + if ((error = iwm_mvm_binding_add_vif(sc, in)) != 0) { device_printf(sc->sc_dev, - "%s: no time event, denied!\n", __func__); - sc->sc_auth_prot = 0; - error = EAUTH; + "%s: binding add cmd\n", __func__); + goto out; + } + if ((error = iwm_mvm_add_sta(sc, in)) != 0) { + device_printf(sc->sc_dev, + "%s: failed to add sta\n", __func__); goto out; } - msleep(&sc->sc_auth_prot, &sc->sc_mtx, 0, "iwmau2", 0); } - IWM_DPRINTF(sc, IWM_DEBUG_RESET, "<-%s\n", __func__); + + /* + * Prevent the FW from wandering off channel during association + * by "protecting" the session with a time event. + */ + /* XXX duration is in units of TU, not MS */ + duration = IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; + iwm_mvm_protect_session(sc, in, duration, 500 /* XXX magic number */); + DELAY(100); + error = 0; out: ieee80211_free_node(ni); diff --git a/sys/dev/iwm/if_iwm_binding.c b/sys/dev/iwm/if_iwm_binding.c index a0960529bffb..31acf2efa100 100644 --- a/sys/dev/iwm/if_iwm_binding.c +++ b/sys/dev/iwm/if_iwm_binding.c @@ -201,13 +201,13 @@ iwm_mvm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action) } int -iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in, int add) +iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in) { - return iwm_mvm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD); + return iwm_mvm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY); } int iwm_mvm_binding_add_vif(struct iwm_softc *sc, struct iwm_node *in) { - return iwm_mvm_binding_update(sc, in, IWM_FW_CTXT_ACTION_ADD); + return iwm_mvm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD); } diff --git a/sys/dev/iwm/if_iwm_binding.h b/sys/dev/iwm/if_iwm_binding.h index 6a86c927975f..933738455049 100644 --- a/sys/dev/iwm/if_iwm_binding.h +++ b/sys/dev/iwm/if_iwm_binding.h @@ -107,8 +107,7 @@ extern int iwm_mvm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action); -extern int iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in, - int add); +extern int iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in); extern int iwm_mvm_binding_add_vif(struct iwm_softc *sc, struct iwm_node *in); #endif /* __IF_IWM_BINDING_H__ */ diff --git a/sys/dev/iwm/if_iwm_time_event.c b/sys/dev/iwm/if_iwm_time_event.c index dec0b1cb565d..86cf2d1e3d11 100644 --- a/sys/dev/iwm/if_iwm_time_event.c +++ b/sys/dev/iwm/if_iwm_time_event.c @@ -244,7 +244,7 @@ iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_node *in, void iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in, - uint32_t duration, uint32_t min_duration, uint32_t max_delay) + uint32_t duration, uint32_t max_delay) { struct iwm_time_event_cmd_v2 time_cmd; diff --git a/sys/dev/iwm/if_iwm_time_event.h b/sys/dev/iwm/if_iwm_time_event.h index 9d06db641249..015652ece32b 100644 --- a/sys/dev/iwm/if_iwm_time_event.h +++ b/sys/dev/iwm/if_iwm_time_event.h @@ -108,6 +108,6 @@ #define __IF_IWM_TIME_EVENT_H__ extern void iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in, - uint32_t duration, uint32_t min_duration, uint32_t max_delay); + uint32_t duration, uint32_t max_delay); #endif /* __IF_IWM_TIME_EVENT_H__ */