This diff makes us keep track of changes in the network's HT protection
settings. These settings are advertised in beacons and change dynamically
based on the nature of clients associated to an AP at a given moment.

Tracking these changes is rather important.
If a non-11n client associates to an AP which previously had 11n clients
only, we must update our wireless device's configuration accordingly or
the new client might damage frames we send out.

Index: dev/pci/if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.75
diff -u -p -r1.75 if_iwm.c
--- dev/pci/if_iwm.c    7 Jan 2016 23:08:38 -0000       1.75
+++ dev/pci/if_iwm.c    20 Jan 2016 20:42:23 -0000
@@ -294,6 +294,8 @@ int iwm_nvm_read_section(struct iwm_soft
                                uint16_t *);
 void   iwm_init_channel_map(struct iwm_softc *, const uint16_t * const);
 void   iwm_setup_ht_rates(struct iwm_softc *);
+void   iwm_htprot_task(void *);
+void   iwm_update_htprot(struct ieee80211com *, const struct ieee80211_node *);
 int    iwm_ampdu_rx_start(struct ieee80211com *,
                    struct ieee80211_node *, uint8_t);
 void   iwm_ampdu_rx_stop(struct ieee80211com *,
@@ -2602,6 +2604,34 @@ iwm_mvm_sta_rx_agg(struct iwm_softc *sc,
 }
 
 void
+iwm_htprot_task(void *arg)
+{
+       struct iwm_softc *sc = arg;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct iwm_node *in = (void *)ic->ic_bss;
+       int error;
+
+       /* This call updates HT protection based on in->in_ni.ni_htop1. */
+       error = iwm_mvm_mac_ctxt_changed(sc, in);
+       if (error != 0)
+               printf("%s: could not change HT protection: error %d\n",
+                   DEVNAME(sc), error);
+}
+
+/*
+ * This function is called by upper layer when HT protection settings in
+ * beacons have changed.
+ */
+void
+iwm_update_htprot(struct ieee80211com *ic, const struct ieee80211_node *ni)
+{
+       struct iwm_softc *sc = ic->ic_softc;
+
+       /* assumes that ni == ic->ic_bss */
+       task_add(systq, &sc->htprot_task);
+}
+
+void
 iwm_ba_task(void *arg)
 {
        struct iwm_softc *sc = arg;
@@ -5878,6 +5908,7 @@ iwm_stop(struct ifnet *ifp, int disable)
        task_del(sc->sc_eswq, &sc->sc_eswk);
        task_del(systq, &sc->setrates_task);
        task_del(systq, &sc->ba_task);
+       task_del(systq, &sc->htprot_task);
 
        sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
 
@@ -6586,6 +6617,7 @@ iwm_preinit(struct iwm_softc *sc)
        /* Override 802.11 state transition machine. */
        sc->sc_newstate = ic->ic_newstate;
        ic->ic_newstate = iwm_newstate;
+       ic->ic_update_htprot = iwm_update_htprot;
        ic->ic_ampdu_rx_start = iwm_ampdu_rx_start;
        ic->ic_ampdu_rx_stop = iwm_ampdu_rx_stop;
 #ifdef notyet
@@ -6822,6 +6854,7 @@ iwm_attach(struct device *parent, struct
        task_set(&sc->newstate_task, iwm_newstate_task, sc);
        task_set(&sc->setrates_task, iwm_setrates_task, sc);
        task_set(&sc->ba_task, iwm_ba_task, sc);
+       task_set(&sc->htprot_task, iwm_htprot_task, sc);
 
        /*
         * We cannot read the MAC address without loading the
Index: dev/pci/if_iwmvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
retrieving revision 1.15
diff -u -p -r1.15 if_iwmvar.h
--- dev/pci/if_iwmvar.h 5 Jan 2016 18:41:15 -0000       1.15
+++ dev/pci/if_iwmvar.h 20 Jan 2016 17:37:06 -0000
@@ -376,6 +376,9 @@ struct iwm_softc {
        int                     ba_tid;
        uint16_t                ba_ssn;
 
+       /* Task for HT protection updates. */
+       struct task             htprot_task;
+
        bus_space_tag_t sc_st;
        bus_space_handle_t sc_sh;
        bus_size_t sc_sz;
Index: dev/pci/if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.157
diff -u -p -r1.157 if_iwn.c
--- dev/pci/if_iwn.c    13 Jan 2016 14:39:35 -0000      1.157
+++ dev/pci/if_iwn.c    20 Jan 2016 20:45:40 -0000
@@ -226,6 +226,8 @@ int         iwn_set_key(struct ieee80211com *, 
                    struct ieee80211_key *);
 void           iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
                    struct ieee80211_key *);
+void           iwn_update_htprot(struct ieee80211com *,
+                   const struct ieee80211_node *);
 int            iwn_ampdu_rx_start(struct ieee80211com *,
                    struct ieee80211_node *, uint8_t);
 void           iwn_ampdu_rx_stop(struct ieee80211com *,
@@ -515,6 +517,7 @@ iwn_attach(struct device *parent, struct
        ic->ic_updateedca = iwn_updateedca;
        ic->ic_set_key = iwn_set_key;
        ic->ic_delete_key = iwn_delete_key;
+       ic->ic_update_htprot = iwn_update_htprot;
        ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
        ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
 #ifdef notyet
@@ -5009,6 +5012,44 @@ iwn_delete_key(struct ieee80211com *ic, 
        node.kid = 0xff;
        DPRINTF(("delete keys for node %d\n", node.id));
        (void)ops->add_node(sc, &node, 1);
+}
+
+/*
+ * This function is called by upper layer when HT protection settings in
+ * beacons have changed.
+ */
+void
+iwn_update_htprot(struct ieee80211com *ic, const struct ieee80211_node *ni)
+{
+       struct iwn_softc *sc = ic->ic_softc;
+       struct iwn_rxon_assoc cmd;
+       enum ieee80211_htprot htprot;
+       int error;
+
+       memset(&cmd, 0, sizeof cmd);
+
+       /* Copy settings from RXON configuration. */
+       cmd.flags = sc->rxon.flags;
+       cmd.filter = sc->rxon.filter;
+       cmd.cck_mask = sc->rxon.cck_mask;
+       cmd.ofdm_mask = sc->rxon.ofdm_mask;
+       cmd.ht_single_mask = sc->rxon.ht_single_mask;
+       cmd.ht_dual_mask = sc->rxon.ht_dual_mask;
+       cmd.ht_triple_mask = sc->rxon.ht_triple_mask;
+       cmd.rxchain = sc->rxon.rxchain;
+       cmd.acquisition = sc->rxon.acquisition;
+
+       /* Update HT protection setting. */
+       htprot = ((ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >>
+           IEEE80211_HTOP1_PROT_SHIFT);
+       cmd.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3));
+       cmd.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot));
+
+       /* Use the RXON_ASSOC command since we're already associated. */
+       error = iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &cmd, sizeof cmd, 1);
+       if (error != 0)
+               printf("%s: could not change HT protection: error %d\n",
+                   sc->sc_dev.dv_xname, error);
 }
 
 /*
Index: dev/pci/if_iwnreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v
retrieving revision 1.51
diff -u -p -r1.51 if_iwnreg.h
--- dev/pci/if_iwnreg.h 7 Jan 2016 23:08:38 -0000       1.51
+++ dev/pci/if_iwnreg.h 20 Jan 2016 20:09:13 -0000
@@ -529,6 +529,22 @@ struct iwn_rxon {
 #define IWN4965_RXONSZ (sizeof (struct iwn_rxon) - 6)
 #define IWN5000_RXONSZ (sizeof (struct iwn_rxon))
 
+/* Structure for command IWN_CMD_RXON_ASSOC. */
+struct iwn_rxon_assoc {
+       uint32_t        flags;
+       uint32_t        filter;
+       uint8_t         cck_mask;
+       uint8_t         ofdm_mask;
+       uint16_t        reserved1;
+       uint8_t         ht_single_mask;
+       uint8_t         ht_dual_mask;
+       uint8_t         ht_triple_mask;
+       uint8_t         reserved2;
+       uint16_t        rxchain;
+       uint16_t        acquisition;
+       uint32_t        reserved3;
+} __packed;
+
 /* Structure for command IWN_CMD_ASSOCIATE. */
 struct iwn_assoc {
        uint32_t        flags;
Index: net80211/ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.151
diff -u -p -r1.151 ieee80211_input.c
--- net80211/ieee80211_input.c  7 Jan 2016 23:22:31 -0000       1.151
+++ net80211/ieee80211_input.c  20 Jan 2016 20:52:08 -0000
@@ -1577,10 +1577,14 @@ ieee80211_recv_probe_resp(struct ieee802
        } else
                is_new = 0;
 
+       if (htcaps)
+               ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]);
+       if (htop)
+               ieee80211_setup_htop(ni, htop + 2, htop[1]);
+
        /*
         * When operating in station mode, check for state updates
-        * while we're associated. We consider only 11g stuff right
-        * now.
+        * while we're associated.
         */
        if (ic->ic_opmode == IEEE80211_M_STA &&
            ic->ic_state == IEEE80211_S_RUN &&
@@ -1599,6 +1603,22 @@ ieee80211_recv_probe_resp(struct ieee802
                                ic->ic_flags &= ~IEEE80211_F_USEPROT;
                        ic->ic_bss->ni_erp = erp;
                }
+               if (ic->ic_bss->ni_flags & IEEE80211_NODE_HT) {
+                       enum ieee80211_htprot htprot_last, htprot;
+                       htprot_last =
+                           ((ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK)
+                           >> IEEE80211_HTOP1_PROT_SHIFT);
+                       htprot = ((ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >>
+                           IEEE80211_HTOP1_PROT_SHIFT);
+                       if (htprot_last != htprot) {
+                               DPRINTF(("[%s] htprot change: was %d, now %d\n",
+                                   ether_sprintf((u_int8_t *)wh->i_addr2),
+                                   htprot_last, htprot));
+                               ic->ic_bss->ni_htop1 = ni->ni_htop1;
+                               ic->ic_update_htprot(ic, ic->ic_bss);
+                       }
+               }
+
                /*
                 * Check if AP short slot time setting has changed
                 * since last beacon and give the driver a chance to
@@ -1679,10 +1699,6 @@ ieee80211_recv_probe_resp(struct ieee802
        ni->ni_erp = erp;
        /* NB: must be after ni_chan is setup */
        ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
-       if (htcaps)
-               ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]);
-       if (htop)
-               ieee80211_setup_htop(ni, htop + 2, htop[1]);
 #ifndef IEEE80211_STA_ONLY
        if (ic->ic_opmode == IEEE80211_M_IBSS && is_new && isprobe) {
                /*
Index: net80211/ieee80211_var.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_var.h,v
retrieving revision 1.70
diff -u -p -r1.70 ieee80211_var.h
--- net80211/ieee80211_var.h    12 Jan 2016 09:28:09 -0000      1.70
+++ net80211/ieee80211_var.h    20 Jan 2016 19:18:40 -0000
@@ -213,6 +213,8 @@ struct ieee80211com {
                                    struct ieee80211_node *, u_int8_t);
        void                    (*ic_ampdu_rx_stop)(struct ieee80211com *,
                                    struct ieee80211_node *, u_int8_t);
+       void                    (*ic_update_htprot)(struct ieee80211com *,
+                                       const struct ieee80211_node *);
        u_int8_t                ic_myaddr[IEEE80211_ADDR_LEN];
        struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
        struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];

Reply via email to