This ensures that if WPA offloading is in use iwx(4) only sets link
state UP once firmware has confirmed that crypto keys have been
installed successfully.

iwm(4) could use a similar patch, but I've not written that yet.

ok?

diff f30a2d1c29071de858b3607fbaa2227aa7c6bfd3 
57e0ba6871dcbf4d5516ac085c5c82b830b96e3d
blob - 2775f725d6347e9dbfcc2cf2ce296133ce7d6d47
blob + c0303528fdbc71291f3d5bf4d2677d351c86eb9c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -416,6 +416,7 @@ int iwx_run_stop(struct iwx_softc *);
 struct ieee80211_node *iwx_node_alloc(struct ieee80211com *);
 int    iwx_set_key(struct ieee80211com *, struct ieee80211_node *,
            struct ieee80211_key *);
+void   iwx_setkey_task(void *);
 void   iwx_delete_key(struct ieee80211com *,
            struct ieee80211_node *, struct ieee80211_key *);
 int    iwx_media_change(struct ifnet *);
@@ -6670,13 +6671,56 @@ iwx_set_key(struct ieee80211com *ic, struct ieee80211_
     struct ieee80211_key *k)
 {
        struct iwx_softc *sc = ic->ic_softc;
-       struct iwx_add_sta_key_cmd cmd;
+       struct iwx_setkey_task_arg *a;
 
        if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
                /* Fallback to software crypto for other ciphers. */
                return (ieee80211_set_key(ic, ni, k));
        }
 
+       a = &sc->setkey_arg[sc->setkey_cur];
+       if (a->ni != NULL)
+               return ENOSPC;
+       a->sta_id = IWX_STATION_ID;
+       a->ni = ni;
+       a->k = k;
+       sc->setkey_cur = (sc->setkey_cur + 1) % nitems(sc->setkey_arg);
+
+       iwx_add_task(sc, systq, &sc->setkey_task);
+       return EBUSY;
+}
+
+void
+iwx_setkey_task(void *arg)
+{
+       struct iwx_softc *sc = arg;
+       struct iwx_setkey_task_arg *a;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211_node *ni;
+       struct ieee80211_key *k;
+       int sta_id;
+       struct iwx_add_sta_key_cmd cmd;
+       uint32_t status;
+       int err, s = splnet();
+
+       if (sc->sc_flags & IWX_FLAG_SHUTDOWN)
+               goto out;
+
+       a = &sc->setkey_arg[sc->setkey_tail];
+       sta_id = a->sta_id;
+       ni = a->ni;
+       a->ni = NULL;
+       k = a->k;
+       a->k = NULL;
+       sc->setkey_tail = (sc->setkey_tail + 1) % nitems(sc->setkey_arg);
+
+       /*
+        * Keys are stored in 'ni' so 'k' is valid if 'ni' is valid.
+        * Currently we only implement station mode where 'ni' is always
+        * ic->ic_bss so there is no need to validate arguments beyond this:
+        */
+       KASSERT(ni == ic->ic_bss);
+
        memset(&cmd, 0, sizeof(cmd));
 
        cmd.common.key_flags = htole16(IWX_STA_KEY_FLG_CCM |
@@ -6690,12 +6734,29 @@ iwx_set_key(struct ieee80211com *ic, struct ieee80211_
                cmd.common.key_offset = 0;
 
        memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len));
-       cmd.common.sta_id = IWX_STATION_ID;
+       cmd.common.sta_id = sta_id;
 
        cmd.transmit_seq_cnt = htole64(k->k_tsc);
 
-       return iwx_send_cmd_pdu(sc, IWX_ADD_STA_KEY, IWX_CMD_ASYNC,
-           sizeof(cmd), &cmd);
+       status = IWX_ADD_STA_SUCCESS;
+       err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA_KEY, sizeof(cmd), &cmd,
+           &status);
+       if (sc->sc_flags & IWX_FLAG_SHUTDOWN)
+               goto out;
+       if (err || (status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS) {
+               IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+                   IEEE80211_REASON_AUTH_LEAVE);
+               ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+       } else {
+               DPRINTF(("marking port %s valid\n",
+                   ether_sprintf(ni->ni_macaddr)));
+               ni->ni_port_valid = 1;
+               ieee80211_set_link_state(ic, LINK_STATE_UP);
+       }
+out:
+       refcnt_rele_wake(&sc->task_refs);
+       splx(s);
+       return;
 }
 
 void
@@ -6868,6 +6929,9 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_s
 
        if (ic->ic_state == IEEE80211_S_RUN) {
                iwx_del_task(sc, systq, &sc->ba_task);
+               iwx_del_task(sc, systq, &sc->setkey_task);
+               memset(sc->setkey_arg, 0, sizeof(sc->setkey_arg));
+               sc->setkey_cur = sc->setkey_tail = 0;
                iwx_del_task(sc, systq, &sc->mac_ctxt_task);
                for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
                        struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i];
@@ -7440,6 +7504,9 @@ iwx_stop(struct ifnet *ifp)
        task_del(systq, &sc->init_task);
        iwx_del_task(sc, sc->sc_nswq, &sc->newstate_task);
        iwx_del_task(sc, systq, &sc->ba_task);
+       iwx_del_task(sc, systq, &sc->setkey_task);
+       memset(sc->setkey_arg, 0, sizeof(sc->setkey_arg));
+       sc->setkey_cur = sc->setkey_tail = 0;
        iwx_del_task(sc, systq, &sc->mac_ctxt_task);
        KASSERT(sc->task_refs.refs >= 1);
        refcnt_finalize(&sc->task_refs, "iwxstop");
@@ -8837,6 +8904,7 @@ iwx_attach(struct device *parent, struct device *self,
        task_set(&sc->init_task, iwx_init_task, sc);
        task_set(&sc->newstate_task, iwx_newstate_task, sc);
        task_set(&sc->ba_task, iwx_ba_task, sc);
+       task_set(&sc->setkey_task, iwx_setkey_task, sc);
        task_set(&sc->mac_ctxt_task, iwx_mac_ctxt_task, sc);
 
        ic->ic_node_alloc = iwx_node_alloc;
blob - 993528772f7face7580e9b461b4d795b14ade10a
blob + 224bc5626a20b1beaaf30b430cb901fdf800ed62
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -438,6 +438,12 @@ struct iwx_rxq_dup_data {
        uint8_t last_sub_frame[IWX_MAX_TID_COUNT + 1];
 };
 
+struct iwx_setkey_task_arg {
+       int sta_id;
+       struct ieee80211_node *ni;
+       struct ieee80211_key *k;
+};
+
 struct iwx_softc {
        struct device sc_dev;
        struct ieee80211com sc_ic;
@@ -458,6 +464,19 @@ struct iwx_softc {
        uint16_t                ba_winsize[IWX_MAX_TID_COUNT];
        int                     ba_timeout_val[IWX_MAX_TID_COUNT];
 
+       /* Task for setting encryption keys and its arguments. */
+       struct task             setkey_task;
+       /*
+        * At present we need to process at most two keys at once:
+        * Our pairwise key and a group key.
+        * When hostap mode is implemented this array needs to grow or
+        * it might become a bottleneck for associations that occur at
+        * roughly the same time.
+        */
+       struct iwx_setkey_task_arg setkey_arg[2];
+       int setkey_cur;
+       int setkey_tail;
+
        /* Task for ERP/HT prot/slot-time/EDCA updates. */
        struct task             mac_ctxt_task;
 


Reply via email to