On Sun, Aug 25, 2019 at 03:18:46PM +0200, Stefan Sperling wrote:
> This has been very stable for me on an iwm(4) client device.
> 
> Has anyone tested this in other contexts?
> Could somebody please test this in hostap mode?
> 
> Thanks,
> Stefan
> 

i ran this on iwn and athn, both in client mode. saw no issues.
jmc

> On Sat, Aug 17, 2019 at 12:01:24AM +0200, Stefan Sperling wrote:
> > When a scan begins we currently toss away everything we have
> > learned about access points in the previous scan iteration.
> > This behaviour gets in the way of some things.
> > 
> > For instance, I am working on another diff to show reasons for association
> > failures in ifconfig output ("wrong channel", "wrong WPA key", "wrong 
> > BSSID").
> > Because the scan loop keeps deleting existing nodes it gets in the way of
> > such features. Whenever ifconfig wants to read information about an AP we
> > have failed to associate to the AP's node has been freed already, and has
> > perhaps been re-allocated upon reception of a new beacon.
> > 
> > There are several ways in which nodes will still get freed with this diff:
> > 
> > 1) This diff adds a new way of timing out inactive nodes which don't
> > send a beacon within 10 scan iterations. This should get rid of stale
> > APs if we're scanning for some time in a changing environment (should
> > cover laptops walking around in buildings looking for APs to connect to).
> > 
> > 2) If we fail to associate a few times, the corresponding node is removed.
> > This mechanism already exists in -current code and is not changed here.
> > See how ni_fails is handled in ieee80211_node_choose_bss().
> > 
> > 3) If net80211 transitions back to INIT state (e.g. because of a
> > user-initiated configuration change) all nodes are removed.
> > 
> > 4) When a background scan starts all nodes will be removed.
> > This could be revisited later. I have left it as-is for now.
> > Background scan only occurs in RUN state and would be unwise to mix
> > such changes into this diff, which aims to fix SCAN state.
> > 
> > 
> > This isn't a new idea.
> > I can recall conversations about this with various people.
> > 
> > My question is whether this diff breaks anything for anyone.
> > 
> > 
> > diff refs/heads/master refs/heads/keepnodes
> > blob - 461f33f2561841520e61dd3de64a857413d1b224
> > blob + 4634efcc61bcc44bea8a44abb4590cd6df303384
> > --- sys/dev/ic/bwfm.c
> > +++ sys/dev/ic/bwfm.c
> > @@ -2610,7 +2610,7 @@ bwfm_newstate(struct ieee80211com *ic, enum ieee80211_
> >                     return 0;
> >             }
> >             ieee80211_set_link_state(ic, LINK_STATE_DOWN);
> > -           ieee80211_free_allnodes(ic, 1);
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> >             ic->ic_state = nstate;
> >             splx(s);
> >             return 0;
> > blob - 0eb9dc07a0a75583f80579cc2d4c285dd1dc36b2
> > blob + 0caa61779fed20f6e96a337a7ec0278efaaa72b5
> > --- sys/dev/ic/pgt.c
> > +++ sys/dev/ic/pgt.c
> > @@ -170,7 +170,7 @@ void     node_mark_active_ap(void *, struct 
> > ieee80211_nod
> >  void        node_mark_active_adhoc(void *, struct ieee80211_node *);
> >  void        pgt_watchdog(struct ifnet *);
> >  int         pgt_init(struct ifnet *);
> > -void        pgt_update_hw_from_sw(struct pgt_softc *, int, int);
> > +void        pgt_update_hw_from_sw(struct pgt_softc *, int);
> >  void        pgt_hostap_handle_mlme(struct pgt_softc *, uint32_t,
> >          struct pgt_obj_mlme *);
> >  void        pgt_update_sw_from_hw(struct pgt_softc *,
> > @@ -544,8 +544,7 @@ trying_again:
> >             sc->sc_flags &= ~flag;
> >             if (ic->ic_if.if_flags & IFF_RUNNING)
> >                     pgt_update_hw_from_sw(sc,
> > -                       ic->ic_state != IEEE80211_S_INIT,
> > -                       ic->ic_opmode != IEEE80211_M_MONITOR);
> > +                       ic->ic_state != IEEE80211_S_INIT);
> >     }
> >  
> >     ic->ic_if.if_flags &= ~IFF_RUNNING;
> > @@ -2015,7 +2014,7 @@ pgt_media_change(struct ifnet *ifp)
> >  
> >          error = ieee80211_media_change(ifp);
> >          if (error == ENETRESET) {
> > -                pgt_update_hw_from_sw(sc, 0, 0);
> > +                pgt_update_hw_from_sw(sc, 0);
> >                  error = 0;
> >          }
> >  
> > @@ -2367,7 +2366,7 @@ pgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t req)
> >     }
> >  
> >     if (error == ENETRESET) {
> > -           pgt_update_hw_from_sw(sc, 0, 0);
> > +           pgt_update_hw_from_sw(sc, 0);
> >             error = 0;
> >     }
> >     splx(s);
> > @@ -2501,8 +2500,7 @@ pgt_init(struct ifnet *ifp)
> >  
> >     if (!(sc->sc_flags & (SC_DYING | SC_UNINITIALIZED)))
> >             pgt_update_hw_from_sw(sc,
> > -               ic->ic_state != IEEE80211_S_INIT,
> > -               ic->ic_opmode != IEEE80211_M_MONITOR);
> > +               ic->ic_state != IEEE80211_S_INIT);
> >  
> >     ifp->if_flags |= IFF_RUNNING;
> >     ifq_clr_oactive(&ifp->if_snd);
> > @@ -2522,7 +2520,7 @@ pgt_init(struct ifnet *ifp)
> >   * back to the BSS had before.
> >   */
> >  void
> > -pgt_update_hw_from_sw(struct pgt_softc *sc, int keepassoc, int keepnodes)
> > +pgt_update_hw_from_sw(struct pgt_softc *sc, int keepassoc)
> >  {
> >     struct ieee80211com *ic = &sc->sc_ic;
> >     struct arpcom *ac = &ic->ic_ac;
> > @@ -2769,8 +2767,6 @@ badopmode:
> >     splx(s);
> >  
> >     if (success) {
> > -           if (shouldbeup && keepnodes)
> > -                   sc->sc_flags |= SC_NOFREE_ALLNODES;
> >             if (shouldbeup)
> >                     ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
> >             else
> > @@ -2942,11 +2938,7 @@ pgt_newstate(struct ieee80211com *ic, enum 
> > ieee80211_s
> >     case IEEE80211_S_SCAN:
> >             ic->ic_if.if_timer = 1;
> >             ic->ic_mgt_timer = 0;
> > -           if (sc->sc_flags & SC_NOFREE_ALLNODES)
> > -                   sc->sc_flags &= ~SC_NOFREE_ALLNODES;
> > -           else
> > -                   ieee80211_free_allnodes(ic, 1);
> > -
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> >             ieee80211_set_link_state(ic, LINK_STATE_DOWN);
> >  #ifndef IEEE80211_STA_ONLY
> >             /* Just use any old channel; we override it anyway. */
> > @@ -3262,7 +3254,7 @@ pgt_activate(struct device *self, int act)
> >     case DVACT_SUSPEND:
> >             if (ifp->if_flags & IFF_RUNNING) {
> >                     pgt_stop(sc, SC_NEEDS_RESET);
> > -                   pgt_update_hw_from_sw(sc, 0, 0);
> > +                   pgt_update_hw_from_sw(sc, 0);
> >             }
> >             if (sc->sc_power != NULL)
> >                     (*sc->sc_power)(sc, act);
> > @@ -3283,10 +3275,10 @@ pgt_wakeup(struct pgt_softc *sc)
> >             (*sc->sc_power)(sc, DVACT_RESUME);
> >  
> >     pgt_stop(sc, SC_NEEDS_RESET);
> > -   pgt_update_hw_from_sw(sc, 0, 0);
> > +   pgt_update_hw_from_sw(sc, 0);
> >  
> >     if (ifp->if_flags & IFF_UP) {
> >             pgt_init(ifp);
> > -           pgt_update_hw_from_sw(sc, 0, 0);
> > +           pgt_update_hw_from_sw(sc, 0);
> >     }
> >  }
> > blob - 038e6a63dfff113b525bb1e9a30c935996535569
> > blob + 83b42976022d4ed42a9165720139abe5c1508324
> > --- sys/dev/pci/if_iwm.c
> > +++ sys/dev/pci/if_iwm.c
> > @@ -5701,7 +5701,7 @@ iwm_scan(struct iwm_softc *sc)
> >                 ieee80211_state_name[IEEE80211_S_SCAN]);
> >     if ((sc->sc_flags & IWM_FLAG_BGSCAN) == 0) {
> >             ieee80211_set_link_state(ic, LINK_STATE_DOWN);
> > -           ieee80211_free_allnodes(ic, 1);
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> >     }
> >     ic->ic_state = IEEE80211_S_SCAN;
> >     iwm_led_blink_start(sc);
> > blob - be1f18695ea4d1c2dedcd7e1630b97f3f72a7cd6
> > blob + ef5f81699e90f2d4c4202b25880c9120907e5ec3
> > --- sys/dev/pci/if_iwn.c
> > +++ sys/dev/pci/if_iwn.c
> > @@ -1825,7 +1825,7 @@ iwn_newstate(struct ieee80211com *ic, enum ieee80211_s
> >                         ieee80211_state_name[nstate]);
> >             if ((sc->sc_flags & IWN_FLAG_BGSCAN) == 0) {
> >                     ieee80211_set_link_state(ic, LINK_STATE_DOWN);
> > -                   ieee80211_free_allnodes(ic, 1);
> > +                   ieee80211_node_cleanup(ic, ic->ic_bss);
> >             }
> >             ic->ic_state = nstate;
> >             return 0;
> > blob - b67bcfd77b19bceb5ee8b7ceffc1bfe7aab92598
> > blob + 3075074c587ff95f69675e252c4b58f3aaf63e37
> > --- sys/dev/pci/if_wpi.c
> > +++ sys/dev/pci/if_wpi.c
> > @@ -1058,7 +1058,7 @@ wpi_newstate(struct ieee80211com *ic, enum ieee80211_s
> >                         ieee80211_state_name[ic->ic_state],
> >                         ieee80211_state_name[nstate]);
> >             ieee80211_set_link_state(ic, LINK_STATE_DOWN);
> > -           ieee80211_free_allnodes(ic, 1);
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> >             ic->ic_state = nstate;
> >             return 0;
> >  
> > blob - a2476c29743019bca8b9183c32be0971f992b178
> > blob + e8064dda864afdda3814234882fd125c430799ce
> > --- sys/dev/usb/if_atu.c
> > +++ sys/dev/usb/if_atu.c
> > @@ -1210,7 +1210,7 @@ atu_newstate(struct ieee80211com *ic, enum ieee80211_s
> >     case IEEE80211_S_SCAN:
> >             memcpy(ic->ic_chan_scan, ic->ic_chan_active,
> >                 sizeof(ic->ic_chan_active));
> > -           ieee80211_free_allnodes(ic, 1);
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> >  
> >             /* tell the event thread that we want a scan */
> >             sc->sc_cmd = ATU_C_SCAN;
> > blob - ec3e0f61e963ea403c9d8b88e675fbe42d5aeaeb
> > blob + 905396f216158f9497fc28be19737e61595adce3
> > --- sys/net80211/ieee80211_node.c
> > +++ sys/net80211/ieee80211_node.c
> > @@ -74,7 +74,6 @@ void ieee80211_setup_node(struct ieee80211com *, struc
> >      const u_int8_t *);
> >  void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
> >  struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
> > -void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node 
> > *);
> >  void ieee80211_node_switch_bss(struct ieee80211com *, struct 
> > ieee80211_node *);
> >  void ieee80211_node_addba_request(struct ieee80211_node *, int);
> >  void ieee80211_node_addba_request_ac_be_to(void *);
> > @@ -92,6 +91,7 @@ void ieee80211_node_leave_11g(struct ieee80211com *, s
> >  void ieee80211_inact_timeout(void *);
> >  void ieee80211_node_cache_timeout(void *);
> >  #endif
> > +void ieee80211_clean_inactive_nodes(struct ieee80211com *, int);
> >  
> >  #ifndef IEEE80211_STA_ONLY
> >  void
> > @@ -780,6 +780,19 @@ ieee80211_reset_scan(struct ifnet *ifp)
> >  }
> >  
> >  /*
> > + * Increase a node's inactitivy counter.
> > + * This counter get reset to zero if a frame is received.
> > + * This function is intended for station mode only.
> > + * See ieee80211_node_cache_timeout() for hostap mode.
> > + */
> > +void
> > +ieee80211_node_raise_inact(void *arg, struct ieee80211_node *ni)
> > +{
> > +   if (ni->ni_refcnt == 0 && ni->ni_inact < IEEE80211_INACT_SCAN)
> > +           ni->ni_inact++;
> > +}
> > +
> > +/*
> >   * Begin an active scan.
> >   */
> >  void
> > @@ -807,14 +820,12 @@ ieee80211_begin_scan(struct ifnet *ifp)
> >                     (ic->ic_flags & IEEE80211_F_ASCAN) ?
> >                             "active" : "passive");
> >  
> > -   /*
> > -    * Flush any previously seen AP's. Note that the latter 
> > -    * assumes we don't act as both an AP and a station,
> > -    * otherwise we'll potentially flush state of stations
> > -    * associated with us.
> > -    */
> > -   ieee80211_free_allnodes(ic, 1);
> >  
> > +   if (ic->ic_opmode == IEEE80211_M_STA) {
> > +           ieee80211_node_cleanup(ic, ic->ic_bss);
> > +           ieee80211_iterate_nodes(ic, ieee80211_node_raise_inact, NULL);
> > +   }
> > +
> >     /*
> >      * Reset the current mode. Setting the current mode will also
> >      * reset scan state.
> > @@ -1297,6 +1308,9 @@ ieee80211_end_scan(struct ifnet *ifp)
> >     if (ic->ic_scan_count)
> >             ic->ic_flags &= ~IEEE80211_F_ASCAN;
> >  
> > +   if (ic->ic_opmode == IEEE80211_M_STA)
> > +           ieee80211_clean_inactive_nodes(ic, IEEE80211_INACT_SCAN);
> > +
> >     ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
> >  
> >  #ifndef IEEE80211_STA_ONLY
> > @@ -2130,6 +2144,29 @@ ieee80211_clean_nodes(struct ieee80211com *ic, int 
> > cac
> >                 "possible nodes leak\n", ifp->if_xname, nnodes,
> >                 ic->ic_nnodes);
> >  #endif
> > +   splx(s);
> > +}
> > +
> > +void
> > +ieee80211_clean_inactive_nodes(struct ieee80211com *ic, int inact_max)
> > +{
> > +   struct ieee80211_node *ni, *next_ni;
> > +   u_int gen = ic->ic_scangen++;   /* NB: ok 'cuz single-threaded*/
> > +   int s;
> > +
> > +   s = splnet();
> > +   for (ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
> > +       ni != NULL; ni = next_ni) {
> > +           next_ni = RBT_NEXT(ieee80211_tree, ni);
> > +           if (ni->ni_scangen == gen)      /* previously handled */
> > +                   continue;
> > +           ni->ni_scangen = gen;
> > +           if (ni->ni_refcnt > 0 || ni->ni_inact < inact_max)
> > +                   continue;
> > +           ieee80211_free_node(ic, ni);
> > +           ic->ic_stats.is_node_timeout++;
> > +   }
> > +
> >     splx(s);
> >  }
> >  
> > blob - af6ad346c608189e4689050262a477a7a2e75cd5
> > blob + 84c5ecabaf666eb20d0935b0d96cdd3af88084c4
> > --- sys/net80211/ieee80211_node.h
> > +++ sys/net80211/ieee80211_node.h
> > @@ -41,6 +41,7 @@
> >  #define    IEEE80211_INACT_MAX     (300/IEEE80211_INACT_WAIT)
> >  #define    IEEE80211_CACHE_SIZE    100
> >  #define    IEEE80211_CACHE_WAIT    30
> > +#define    IEEE80211_INACT_SCAN    10              /* for station mode */
> >  
> >  struct ieee80211_rateset {
> >     u_int8_t                rs_nrates;
> > @@ -491,6 +492,7 @@ struct ieee80211_node *
> >             const char *, u_int8_t);
> >  void ieee80211_release_node(struct ieee80211com *,
> >             struct ieee80211_node *);
> > +void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node 
> > *);
> >  void ieee80211_free_allnodes(struct ieee80211com *, int);
> >  void ieee80211_iterate_nodes(struct ieee80211com *,
> >             ieee80211_iter_func *, void *);
> > 
> > 
> > 
> 

Reply via email to