Author: avos
Date: Sun Oct  2 19:39:23 2016
New Revision: 306590
URL: https://svnweb.freebsd.org/changeset/base/306590

Log:
  net80211: add one-vap version of ieee80211_iterate_nodes()
  
  - Add a counter into 'struct ieee80211_node_table' to save current number
  of allocated nodes.
  (allows to remove array overflow checking in ieee80211_iterate_nodes()).
  - Add ieee80211_iterate_nodes_vap() function; unlike non-vap version,
  it iterates on nodes for specified vap only.
  
  In addition to the above:
  - Remove ieee80211_iterate_nt(); it is not used by drivers / net80211
  outside ieee80211_iterate_nodes() function + cannot be separated due
  to structural changes in code.
  
  Since size of 'struct ieee80211_node_table' (part of ieee80211com,
  which is a part of driver's softc) is changed all wireless drivers /
  kernel need to be recompiled.
  
  Tested with wpi(4), STA mode.
  
  Reviewed by:  adrian
  Differential Revision:        https://reviews.freebsd.org/D7996

Modified:
  head/sys/net80211/ieee80211_node.c
  head/sys/net80211/ieee80211_node.h

Modified: head/sys/net80211/ieee80211_node.c
==============================================================================
--- head/sys/net80211/ieee80211_node.c  Sun Oct  2 17:36:55 2016        
(r306589)
+++ head/sys/net80211/ieee80211_node.c  Sun Oct  2 19:39:23 2016        
(r306590)
@@ -1214,13 +1214,44 @@ node_getmimoinfo(const struct ieee80211_
        /* XXX EVM? */
 }
 
+static void
+ieee80211_add_node_nt(struct ieee80211_node_table *nt,
+    struct ieee80211_node *ni)
+{
+       struct ieee80211com *ic = nt->nt_ic;
+       int hash;
+
+       IEEE80211_NODE_LOCK_ASSERT(nt);
+
+       hash = IEEE80211_NODE_HASH(ic, ni->ni_macaddr);
+       (void) ic;      /* XXX IEEE80211_NODE_HASH */
+       TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
+       LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
+       nt->nt_count++;
+       ni->ni_table = nt;
+}
+
+static void
+ieee80211_del_node_nt(struct ieee80211_node_table *nt,
+    struct ieee80211_node *ni)
+{
+
+       IEEE80211_NODE_LOCK_ASSERT(nt);
+
+       TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
+       LIST_REMOVE(ni, ni_hash);
+       nt->nt_count--;
+       KASSERT(nt->nt_count >= 0,
+           ("nt_count is negative (%d)!\n", nt->nt_count));
+       ni->ni_table = NULL;
+}
+
 struct ieee80211_node *
 ieee80211_alloc_node(struct ieee80211_node_table *nt,
        struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
 {
        struct ieee80211com *ic = nt->nt_ic;
        struct ieee80211_node *ni;
-       int hash;
 
        ni = ic->ic_node_alloc(vap, macaddr);
        if (ni == NULL) {
@@ -1233,7 +1264,6 @@ ieee80211_alloc_node(struct ieee80211_no
                ether_sprintf(macaddr), nt->nt_name);
 
        IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
-       hash = IEEE80211_NODE_HASH(ic, macaddr);
        ieee80211_node_initref(ni);             /* mark referenced */
        ni->ni_chan = IEEE80211_CHAN_ANYC;
        ni->ni_authmode = IEEE80211_AUTH_OPEN;
@@ -1250,9 +1280,7 @@ ieee80211_alloc_node(struct ieee80211_no
                ieee80211_mesh_node_init(vap, ni);
 #endif
        IEEE80211_NODE_LOCK(nt);
-       TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
-       LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
-       ni->ni_table = nt;
+       ieee80211_add_node_nt(nt, ni);
        ni->ni_vap = vap;
        ni->ni_ic = ic;
        IEEE80211_NODE_UNLOCK(nt);
@@ -1815,10 +1843,8 @@ _ieee80211_free_node(struct ieee80211_no
                if (vap->iv_aid_bitmap != NULL)
                        IEEE80211_AID_CLR(vap, ni->ni_associd);
        }
-       if (nt != NULL) {
-               TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
-               LIST_REMOVE(ni, ni_hash);
-       }
+       if (nt != NULL)
+               ieee80211_del_node_nt(nt, ni);
        ni->ni_ic->ic_node_free(ni);
 }
 
@@ -1957,9 +1983,7 @@ node_reclaim(struct ieee80211_node_table
                 * the references are dropped storage will be
                 * reclaimed.
                 */
-               TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
-               LIST_REMOVE(ni, ni_hash);
-               ni->ni_table = NULL;            /* clear reference */
+               ieee80211_del_node_nt(nt, ni);
        } else
                _ieee80211_free_node(ni);
 }
@@ -1977,6 +2001,7 @@ ieee80211_node_table_init(struct ieee802
        nt->nt_ic = ic;
        IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
        TAILQ_INIT(&nt->nt_node);
+       nt->nt_count = 0;
        nt->nt_name = name;
        nt->nt_inact_init = inact;
        nt->nt_keyixmax = keyixmax;
@@ -2261,117 +2286,68 @@ ieee80211_node_timeout(void *arg)
 }
 
 /*
- * Iterate over the node table and return an array of ref'ed nodes.
- *
- * This is separated out from calling the actual node function so that
- * no LORs will occur.
- *
- * If there are too many nodes (ie, the number of nodes doesn't fit
- * within 'max_aid' entries) then the node references will be freed
- * and an error will be returned.
- *
- * The responsibility of allocating and freeing "ni_arr" is up to
- * the caller.
+ * The same as ieee80211_iterate_nodes(), but for one vap only.
  */
 int
-ieee80211_iterate_nt(struct ieee80211_node_table *nt,
-    struct ieee80211_node **ni_arr, uint16_t max_aid)
+ieee80211_iterate_nodes_vap(struct ieee80211_node_table *nt,
+    struct ieee80211vap *vap, ieee80211_iter_func *f, void *arg)
 {
-       int i, j, ret;
+       struct ieee80211_node **ni_arr;
        struct ieee80211_node *ni;
+       size_t size;
+       int count, i;
 
+       /*
+        * Iterate over the node table and save an array of ref'ed nodes.
+        *
+        * This is separated out from calling the actual node function so that
+        * no LORs will occur.
+        */
        IEEE80211_NODE_LOCK(nt);
+       count = nt->nt_count;
+       size = count * sizeof(struct ieee80211_node *);
+       ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
+           IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
+       if (ni_arr == NULL) {
+               IEEE80211_NODE_UNLOCK(nt);
+               return (ENOMEM);
+       }
 
-       i = ret = 0;
+       i = 0;
        TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
-               if (i >= max_aid) {
-                       ret = E2BIG;
-                       ic_printf(nt->nt_ic, "Node array overflow: max=%u",
-                           max_aid);
-                       break;
-               }
+               if (vap != NULL && ni->ni_vap != vap)
+                       continue;
+               KASSERT(i < count,
+                   ("node array overflow (vap %p, i %d, count %d)\n",
+                   vap, i, count));
                ni_arr[i] = ieee80211_ref_node(ni);
                i++;
        }
-
-       /*
-        * It's safe to unlock here.
-        *
-        * If we're successful, the list is returned.
-        * If we're unsuccessful, the list is ignored
-        * and we remove our references.
-        *
-        * This avoids any potential LOR with
-        * ieee80211_free_node().
-        */
        IEEE80211_NODE_UNLOCK(nt);
 
-       /*
-        * If ret is non-zero, we hit some kind of error.
-        * Rather than walking some nodes, we'll walk none
-        * of them.
-        */
-       if (ret) {
-               for (j = 0; j < i; j++) {
-                       /* ieee80211_free_node() locks by itself */
-                       ieee80211_free_node(ni_arr[j]);
-               }
+       for (i = 0; i < count; i++) {
+               if (ni_arr[i] == NULL)  /* end of the list */
+                       break;
+               (*f)(arg, ni_arr[i]);
+               /* ieee80211_free_node() locks by itself */
+               ieee80211_free_node(ni_arr[i]);
        }
 
-       return (ret);
+       IEEE80211_FREE(ni_arr, M_80211_NODE);
+
+       return (0);
 }
 
 /*
  * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
  * reference in the source.
- *
- * Note that this fetches 'max_aid' from the first VAP, rather than finding
- * the largest max_aid from all VAPs.
  */
 void
 ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
        ieee80211_iter_func *f, void *arg)
 {
-       struct ieee80211_node **ni_arr;
-       size_t size;
-       int i;
-       uint16_t max_aid;
-       struct ieee80211vap *vap;
-
-       /* Overdoing it default */
-       max_aid = IEEE80211_AID_MAX;
-
-       /* Handle the case of there being no vaps just yet */
-       vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps);
-       if (vap != NULL)
-               max_aid = vap->iv_max_aid;
-
-       size = max_aid * sizeof(struct ieee80211_node *);
-       ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
-           IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
-       if (ni_arr == NULL)
-               return;
-
-       /*
-        * If this fails, the node table won't have any
-        * valid entries - ieee80211_iterate_nt() frees
-        * the references to them.  So don't try walking
-        * the table; just skip to the end and free the
-        * temporary memory.
-        */
-       if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0)
-               goto done;
-
-       for (i = 0; i < max_aid; i++) {
-               if (ni_arr[i] == NULL)  /* end of the list */
-                       break;
-               (*f)(arg, ni_arr[i]);
-               /* ieee80211_free_node() locks by itself */
-               ieee80211_free_node(ni_arr[i]);
-       }
-
-done:
-       IEEE80211_FREE(ni_arr, M_80211_NODE);
+       /* XXX no way to pass error to the caller. */
+       (void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg);
 }
 
 void

Modified: head/sys/net80211/ieee80211_node.h
==============================================================================
--- head/sys/net80211/ieee80211_node.h  Sun Oct  2 17:36:55 2016        
(r306589)
+++ head/sys/net80211/ieee80211_node.h  Sun Oct  2 19:39:23 2016        
(r306590)
@@ -359,6 +359,7 @@ struct ieee80211_node_table {
        ieee80211_node_lock_t   nt_nodelock;    /* on node table */
        TAILQ_HEAD(, ieee80211_node) nt_node;   /* information of all nodes */
        LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
+       int                     nt_count;       /* number of nodes */
        struct ieee80211_node   **nt_keyixmap;  /* key ix -> node map */
        int                     nt_keyixmax;    /* keyixmap size */
        const char              *nt_name;       /* table name for debug msgs */
@@ -444,8 +445,8 @@ int ieee80211_node_delucastkey(struct ie
 void   ieee80211_node_timeout(void *arg);
 
 typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
-int    ieee80211_iterate_nt(struct ieee80211_node_table *,
-               struct ieee80211_node **, uint16_t);
+int    ieee80211_iterate_nodes_vap(struct ieee80211_node_table *,
+               struct ieee80211vap *, ieee80211_iter_func *, void *);
 void   ieee80211_iterate_nodes(struct ieee80211_node_table *,
                ieee80211_iter_func *, void *);
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to