You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/06/18 11:42:35 UTC

[incubator-nuttx] branch master updated: wireless/bcm43xxx: sort scan result by rssi

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new e6a23e7b8a wireless/bcm43xxx: sort scan result by rssi
e6a23e7b8a is described below

commit e6a23e7b8a9255c952dc43a42a667a61d9874c54
Author: chao.an <an...@xiaomi.com>
AuthorDate: Sat Jun 18 01:26:13 2022 +0800

    wireless/bcm43xxx: sort scan result by rssi
    
    1. Replace SCAN_RESULT_SIZE to SCAN_RESULT_ENTRIES
    2. filter scan result with better rssi
    3. Sort scan result by rssi
    
    Signed-off-by: chao.an <an...@xiaomi.com>
---
 drivers/wireless/ieee80211/bcm43xxx/Kconfig       |   8 +-
 drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c | 458 +++++++++-------------
 drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h |   4 +-
 3 files changed, 192 insertions(+), 278 deletions(-)

diff --git a/drivers/wireless/ieee80211/bcm43xxx/Kconfig b/drivers/wireless/ieee80211/bcm43xxx/Kconfig
index d57b0e3c4c..a5a48d7be0 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/Kconfig
+++ b/drivers/wireless/ieee80211/bcm43xxx/Kconfig
@@ -125,11 +125,11 @@ config IEEE80211_BROADCOM_SCHED_PRIORITY
 		This parameter should be set the bcmf daemon thread
 		schedule priority
 
-config IEEE80211_BROADCOM_SCAN_RESULT_SIZE
-	int "Broadcom BCMF escan result size"
-	default 1024
+config IEEE80211_BROADCOM_SCAN_RESULT_ENTRIES
+	int "Broadcom BCMF escan result entries"
+	default 10
 	---help---
-		This parameter should be set the bcmf escan result buffer size
+		This parameter should be set the bcmf escan result buffer entries
 
 if IEEE80211_BROADCOM_FULLMAC
 
diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c
index c477cfc7a7..721336b645 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c
+++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c
@@ -53,10 +53,10 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define DOT11_BSSTYPE_ANY      2
-#define BCMF_SCAN_TIMEOUT_TICK (5*CLOCKS_PER_SEC)
-#define BCMF_AUTH_TIMEOUT_MS   20000  /* was 10000 */
-#define BCMF_SCAN_RESULT_SIZE  CONFIG_IEEE80211_BROADCOM_SCAN_RESULT_SIZE
+#define DOT11_BSSTYPE_ANY         2
+#define BCMF_SCAN_TIMEOUT_TICK    (5*CLOCKS_PER_SEC)
+#define BCMF_AUTH_TIMEOUT_MS      20000  /* was 10000 */
+#define BCMF_SCAN_RESULT_ENTRIES  CONFIG_IEEE80211_BROADCOM_SCAN_RESULT_ENTRIES
 
 /* CLM file is cut into pieces of MAX_CHUNK_LEN.
  * It is relatively small because dongles (FW) have a small maximum size
@@ -623,16 +623,19 @@ void bcmf_wl_auth_event_handler(FAR struct bcmf_dev_s *priv,
  */
 
 void bcmf_wl_scan_event_handler(FAR struct bcmf_dev_s *priv,
-                                struct bcmf_event_s *event,
+                                FAR struct bcmf_event_s *event,
                                 unsigned int len)
 {
-  uint32_t status;
-  uint32_t event_len;
-  struct wl_escan_result *result;
-  struct wl_bss_info *bss;
-  unsigned int bss_info_len;
+  FAR struct wl_escan_result *result;
   unsigned int escan_result_len;
-  unsigned int bss_count = 0;
+  FAR struct wl_bss_info *curr;
+  FAR struct wl_bss_info *bss;
+  uint32_t event_len;
+  int16_t worst_rssi;
+  int worst_entry;
+  uint32_t status;
+  int i;
+  int j;
 
   event_len = len;
 
@@ -666,7 +669,7 @@ void bcmf_wl_scan_event_handler(FAR struct bcmf_dev_s *priv,
 
   /* Process escan result payload */
 
-  result = (struct wl_escan_result *)&event[1];
+  result = (FAR struct wl_escan_result *)&event[1];
 
   if (len < result->buflen ||
       result->buflen < sizeof(struct wl_escan_result))
@@ -674,260 +677,78 @@ void bcmf_wl_scan_event_handler(FAR struct bcmf_dev_s *priv,
       goto exit_invalid_frame;
     }
 
-  /* wl_escan_result structure contains a wl_bss_info field */
-
-  len = result->buflen - sizeof(struct wl_escan_result)
-                       + sizeof(struct wl_bss_info);
-
   /* Process bss_infos */
 
   bss = result->bss_info;
 
-  while (len > 0 && bss_count < result->bss_count)
+  for (i = 0; i < result->bss_count; i++)
     {
-      struct iw_event *iwe;
-      unsigned int result_size;
-      size_t essid_len;
-      size_t essid_len_aligned;
-      uint8_t *ie_buffer;
-      unsigned int ie_offset;
-      unsigned int check_offset;
+      worst_entry = -1;
+      worst_rssi = 0;
 
-      result_size = BCMF_SCAN_RESULT_SIZE - priv->scan_result_size;
-      bss_info_len = bss->length;
+      wlinfo("Scan result: <%.32s> "
+             "%02x:%02x:%02x:%02x:%02x:%02x "
+             "signal %d %d %d\n",
+             bss->SSID,
+             bss->BSSID.ether_addr_octet[0],
+             bss->BSSID.ether_addr_octet[1],
+             bss->BSSID.ether_addr_octet[2],
+             bss->BSSID.ether_addr_octet[3],
+             bss->BSSID.ether_addr_octet[4],
+             bss->BSSID.ether_addr_octet[5],
+             bss->RSSI, bss->phy_noise, bss->SNR);
 
-      if (len < bss_info_len)
+      for (j = 0; j < priv->scan_result_entries; j++)
         {
-          wlerr("bss_len error %d %d\n", len, bss_info_len);
-          goto exit_invalid_frame;
-        }
-
-      /* Append current bss_info to priv->scan_results
-       * FIXME protect this against race conditions
-       */
+          curr = &priv->scan_result[j];
 
-      /* Check if current bss AP is not already detected */
+          /* Check if current bss AP is not already detected */
 
-      check_offset = 0;
-
-      while (priv->scan_result_size - check_offset
-                                     >= offsetof(struct iw_event, u))
-        {
-          iwe = (struct iw_event *)&priv->scan_result[check_offset];
-
-          if (iwe->cmd == SIOCGIWAP)
+          if (memcmp(&curr->BSSID, &bss[i].BSSID,
+                     sizeof(curr->BSSID)) == 0)
             {
-              if (memcmp(&iwe->u.ap_addr.sa_data,
-                         bss->BSSID.ether_addr_octet,
-                         sizeof(bss->BSSID.ether_addr_octet)) == 0)
+              /* Replace the duplicate entry if rssi is
+               * better than before
+               */
+
+              if (curr->RSSI < bss[i].RSSI)
                 {
-                  goto process_next_bss;
+                  memcpy(curr, bss, sizeof(*curr));
                 }
-            }
-
-          check_offset += iwe->len;
-        }
-
-      wlinfo("Scan result: <%.32s> %02x:%02x:%02x:%02x:%02x:%02x\n",
-               bss->SSID,
-               bss->BSSID.ether_addr_octet[0],
-               bss->BSSID.ether_addr_octet[1],
-               bss->BSSID.ether_addr_octet[2],
-               bss->BSSID.ether_addr_octet[3],
-               bss->BSSID.ether_addr_octet[4],
-               bss->BSSID.ether_addr_octet[5]);
-
-      /* Copy BSSID */
-
-      if (result_size < BCMF_IW_EVENT_SIZE(ap_addr))
-        {
-          goto scan_result_full;
-        }
-
-      iwe = (struct iw_event *)&priv->scan_result[priv->scan_result_size];
-      iwe->len = BCMF_IW_EVENT_SIZE(ap_addr);
-      iwe->cmd = SIOCGIWAP;
-      memcpy(&iwe->u.ap_addr.sa_data, bss->BSSID.ether_addr_octet,
-             sizeof(bss->BSSID.ether_addr_octet));
-      iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
-
-      priv->scan_result_size += BCMF_IW_EVENT_SIZE(ap_addr);
-      result_size -= BCMF_IW_EVENT_SIZE(ap_addr);
-
-      /* Copy ESSID */
-
-      essid_len = min(strlen((const char *)bss->SSID), 32);
-      essid_len_aligned = (essid_len + 3) & -4;
-
-      if (result_size < BCMF_IW_EVENT_SIZE(essid)+essid_len_aligned)
-        {
-          goto scan_result_full;
-        }
 
-      iwe = (struct iw_event *)&priv->scan_result[priv->scan_result_size];
-      iwe->len = BCMF_IW_EVENT_SIZE(essid)+essid_len_aligned;
-      iwe->cmd = SIOCGIWESSID;
-      iwe->u.essid.flags = 0;
-      iwe->u.essid.length = essid_len;
-
-      /* Special processing for iw_point, set offset in pointer field */
-
-      iwe->u.essid.pointer = (FAR void *)sizeof(iwe->u.essid);
-      memcpy(&iwe->u.essid + 1, bss->SSID, essid_len);
-
-      priv->scan_result_size += BCMF_IW_EVENT_SIZE(essid)+essid_len_aligned;
-      result_size -= BCMF_IW_EVENT_SIZE(essid)+essid_len_aligned;
-
-      /* Copy link quality info */
-
-      if (result_size < BCMF_IW_EVENT_SIZE(qual))
-        {
-          goto scan_result_full;
-        }
-
-      iwe = (struct iw_event *)&priv->scan_result[priv->scan_result_size];
-      iwe->len = BCMF_IW_EVENT_SIZE(qual);
-      iwe->cmd = IWEVQUAL;
-      iwe->u.qual.qual = bss->SNR;
-      wlinfo("signal %d %d %d\n", bss->RSSI, bss->phy_noise, bss->SNR);
-      iwe->u.qual.level = bss->RSSI;
-      iwe->u.qual.noise = bss->phy_noise;
-      iwe->u.qual.updated = IW_QUAL_DBM | IW_QUAL_ALL_UPDATED;
-
-      priv->scan_result_size += BCMF_IW_EVENT_SIZE(qual);
-      result_size -= BCMF_IW_EVENT_SIZE(qual);
-
-      /* Copy AP mode */
-
-      if (result_size < BCMF_IW_EVENT_SIZE(mode))
-        {
-          goto scan_result_full;
-        }
-
-      iwe = (struct iw_event *)&priv->scan_result[priv->scan_result_size];
-      iwe->len = BCMF_IW_EVENT_SIZE(mode);
-      iwe->cmd = SIOCGIWMODE;
-      if (bss->capability & DOT11_CAP_ESS)
-        {
-          iwe->u.mode = IW_MODE_INFRA;
-        }
-      else if (bss->capability & DOT11_CAP_IBSS)
-        {
-          iwe->u.mode = IW_MODE_ADHOC;
-        }
-      else
-        {
-          iwe->u.mode = IW_MODE_AUTO;
-        }
-
-      priv->scan_result_size += BCMF_IW_EVENT_SIZE(mode);
-      result_size -= BCMF_IW_EVENT_SIZE(mode);
-
-      /* Copy AP encryption mode */
-
-      if (result_size < BCMF_IW_EVENT_SIZE(data))
-        {
-          goto scan_result_full;
-        }
-
-      iwe = (struct iw_event *)&priv->scan_result[priv->scan_result_size];
-      iwe->len = BCMF_IW_EVENT_SIZE(data);
-      iwe->cmd = SIOCGIWENCODE;
-      iwe->u.data.flags = bss->capability & DOT11_CAP_PRIVACY ?
-                          IW_ENCODE_ENABLED | IW_ENCODE_NOKEY :
-                          IW_ENCODE_DISABLED;
-      iwe->u.data.length = 0;
-      iwe->u.essid.pointer = NULL;
-
-      priv->scan_result_size += BCMF_IW_EVENT_SIZE(data);
-      result_size -= BCMF_IW_EVENT_SIZE(data);
-
-      /* Copy relevant raw IE frame */
-
-      if (bss->ie_offset >= bss_info_len ||
-          bss->ie_length > bss_info_len - bss->ie_offset)
-        {
-          goto process_next_bss;
-        }
-
-      ie_offset = 0;
-      ie_buffer = (uint8_t *)bss + bss->ie_offset;
-
-      while (1)
-        {
-          size_t ie_frame_size;
-
-          if (bss->ie_length - ie_offset < 2)
-            {
-              /* Minimum Information element size is 2 bytes */
-
-              break;
+              goto process_next_bss;
             }
 
-          ie_frame_size = ie_buffer[ie_offset + 1] + 2;
+          /* Find worst rssi and mark the entry */
 
-          if (ie_frame_size > bss->ie_length - ie_offset)
+          if (curr->RSSI < worst_rssi)
             {
-              /* Entry too big */
-
-              break;
+              worst_entry = j;
+              worst_rssi = curr->RSSI;
             }
+        }
+
+      if (priv->scan_result_entries == BCMF_SCAN_RESULT_ENTRIES)
+        {
+          /* Entries full and replace the worst entry */
 
-          switch (ie_buffer[ie_offset])
+          if (worst_entry >= 0)
             {
-              case IEEE80211_ELEMID_RSN:
+              curr = &priv->scan_result[worst_entry];
+              if (curr->RSSI < bss->RSSI)
                 {
-                  size_t ie_frame_size_aligned;
-                  ie_frame_size_aligned = (ie_frame_size + 3) & -4;
-
-                  wlinfo("found RSN\n");
-
-                  if (result_size < BCMF_IW_EVENT_SIZE(data) +
-                                    ie_frame_size_aligned)
-                    {
-                      break;
-                    }
-
-                  iwe = (struct iw_event *)
-                    &priv->scan_result[priv->scan_result_size];
-
-                  iwe->len = BCMF_IW_EVENT_SIZE(data)+ie_frame_size_aligned;
-                  iwe->cmd = IWEVGENIE;
-                  iwe->u.data.flags = 0;
-                  iwe->u.data.length = ie_frame_size;
-                  iwe->u.data.pointer = (FAR void *)sizeof(iwe->u.data);
-                  memcpy(&iwe->u.data + 1, &ie_buffer[ie_offset],
-                         ie_frame_size);
-
-                  priv->scan_result_size += BCMF_IW_EVENT_SIZE(essid) +
-                                            ie_frame_size_aligned;
-                  result_size -= BCMF_IW_EVENT_SIZE(essid) +
-                                 ie_frame_size_aligned;
-                  break;
+                  memcpy(curr, bss, sizeof(*curr));
                 }
-
-              default:
-                break;
             }
 
-          ie_offset += ie_buffer[ie_offset + 1] + 2;
+process_next_bss:
+          continue;
         }
 
-      goto process_next_bss;
-
-    scan_result_full:
-
-      /* Continue instead of break to log dropped AP results */
-
-      wlerr("No more space in scan_result buffer\n");
-
-    process_next_bss:
-
-      /* Process next bss_info */
+      curr = &priv->scan_result[priv->scan_result_entries];
+      memcpy(curr, bss, sizeof(*curr));
 
-      len -= bss_info_len;
-      bss = (struct wl_bss_info *)((uint8_t *)bss + bss_info_len);
-      bss_count += 1;
+      priv->scan_result_entries++;
     }
 
 wl_escan_result_processed:
@@ -959,7 +780,124 @@ wl_escan_result_processed:
 
 exit_invalid_frame:
   wlerr("Invalid scan result event\n");
-  bcmf_hexdump((uint8_t *)event, event_len, (unsigned long)event);
+  bcmf_hexdump((FAR uint8_t *)event, event_len, (unsigned long)event);
+}
+
+static int bcmf_wl_scan_format_results(FAR struct bcmf_dev_s *priv,
+                                       FAR struct iwreq *iwr)
+{
+  FAR wl_bss_info_t *scan_result[BCMF_SCAN_RESULT_ENTRIES];
+  FAR wl_bss_info_t *info;
+  FAR struct iw_event *iwe;
+  FAR char *pointer;
+  int len;
+  int i;
+  int j;
+
+  if (priv->scan_result_entries == 0)
+    {
+      iwr->u.data.length = 0;
+      return OK;
+    }
+
+  len = IW_EV_LEN(ap_addr) + IW_EV_LEN(qual) +
+        IW_EV_LEN(freq)    + IW_EV_LEN(data) +
+        IW_EV_LEN(essid);
+
+  len *= priv->scan_result_entries;
+
+  for (i = 0; i < priv->scan_result_entries; i++)
+    {
+      scan_result[i] = &priv->scan_result[i];
+      len += (min(strlen((FAR const char *)scan_result[i]->SSID),
+                         32) + 3) & ~3;
+    }
+
+  if (iwr->u.data.pointer == NULL || iwr->u.data.length < len)
+    {
+      iwr->u.data.length = len;
+      return -E2BIG;
+    }
+
+  /* Sort list by RSSI */
+
+  for (i = 0; i < priv->scan_result_entries; i++)
+    {
+      for (j = 0; j + 1 < priv->scan_result_entries - i; j++)
+        {
+          if (scan_result[j]->RSSI < scan_result[j + 1]->RSSI)
+            {
+              info = scan_result[j];
+              scan_result[j] = scan_result[j + 1];
+              scan_result[j + 1] = info;
+            }
+        }
+    }
+
+  pointer = iwr->u.data.pointer;
+
+  /* Copy scan result */
+
+  for (i = 0; i < priv->scan_result_entries; i++)
+    {
+      info = scan_result[i];
+
+      /* Copy BSSID */
+
+      iwe = (FAR struct iw_event *)pointer;
+      iwe->cmd = SIOCGIWAP;
+      iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
+      memcpy(&iwe->u.ap_addr.sa_data,
+             info->BSSID.ether_addr_octet, IFHWADDRLEN);
+      iwe->len = IW_EV_LEN(ap_addr);
+      pointer += iwe->len;
+
+      /* Copy ESSID */
+
+      iwe = (FAR struct iw_event *)pointer;
+      iwe->cmd = SIOCGIWESSID;
+      iwe->u.essid.flags = 0;
+      iwe->u.essid.length = min(strlen((FAR const char *)info->SSID), 32);
+      iwe->u.essid.pointer = (FAR void *)sizeof(iwe->u.essid);
+      memcpy(&iwe->u.essid + 1, info->SSID, iwe->u.essid.length);
+      iwe->len = IW_EV_LEN(essid) + ((iwe->u.essid.length + 3) & ~3);
+      pointer += iwe->len;
+
+      /* Copy link quality info */
+
+      iwe = (FAR struct iw_event *)pointer;
+      iwe->cmd = IWEVQUAL;
+      iwe->u.qual.qual = info->SNR;
+      iwe->u.qual.level = info->RSSI;
+      iwe->u.qual.noise = info->phy_noise;
+      iwe->u.qual.updated = IW_QUAL_DBM | IW_QUAL_ALL_UPDATED;
+      iwe->len = IW_EV_LEN(qual);
+      pointer += iwe->len;
+
+      /* Copy AP control channel */
+
+      iwe = (FAR struct iw_event *)pointer;
+      iwe->cmd = SIOCGIWFREQ;
+      iwe->u.freq.e = 0;
+      iwe->u.freq.m = info->ctl_ch;
+      iwe->len = IW_EV_LEN(freq);
+      pointer += iwe->len;
+
+      /* Copy AP encryption mode */
+
+      iwe = (FAR struct iw_event *)pointer;
+      iwe->cmd = SIOCGIWENCODE;
+      iwe->u.data.flags = info->capability & DOT11_CAP_PRIVACY ?
+                          IW_ENCODE_ENABLED | IW_ENCODE_NOKEY :
+                          IW_ENCODE_DISABLED;
+      iwe->u.data.length = 0;
+      iwe->u.essid.pointer = NULL;
+      iwe->len = IW_EV_LEN(data);
+      pointer += iwe->len;
+    }
+
+  iwr->u.data.length = pointer - (FAR char *)iwr->u.data.pointer;
+  return OK;
 }
 
 void bcmf_wl_scan_timeout(wdparm_t arg)
@@ -1130,7 +1068,8 @@ int bcmf_wl_start_scan(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
 
   if (priv->scan_result == NULL)
     {
-      priv->scan_result = kmm_malloc(BCMF_SCAN_RESULT_SIZE);
+      priv->scan_result = kmm_malloc(sizeof(wl_bss_info_t) *
+                                     BCMF_SCAN_RESULT_ENTRIES);
       if (priv->scan_result == NULL)
         {
           wlerr("Cannot allocate result buffer\n");
@@ -1141,7 +1080,7 @@ int bcmf_wl_start_scan(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
 
   wlinfo("start scan\n");
 
-  priv->scan_result_size = 0;
+  priv->scan_result_entries = 0;
   priv->scan_status = BCMF_SCAN_RUN;
 
   out_len = sizeof(scan_params);
@@ -1202,41 +1141,16 @@ int bcmf_wl_get_scan_results(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
       goto exit_sem_post;
     }
 
-  if (iwr->u.data.pointer == NULL ||
-      iwr->u.data.length < priv->scan_result_size)
-    {
-      /* Stat request, return scan_result_size */
-
-      ret = -E2BIG;
-      iwr->u.data.pointer = NULL;
-      iwr->u.data.length = priv->scan_result_size;
-      goto exit_sem_post;
-    }
-
-  if (priv->scan_result_size <= 0)
+  ret = bcmf_wl_scan_format_results(priv, iwr);
+  if (ret == OK)
     {
-      ret = OK;
-      iwr->u.data.length = 0;
-      goto exit_free_buffer;
-    }
-
-  /* Copy result to user buffer */
+      /* Free scan result buffer */
 
-  if (iwr->u.data.length > priv->scan_result_size)
-    {
-      iwr->u.data.length = priv->scan_result_size;
+      kmm_free(priv->scan_result);
+      priv->scan_result = NULL;
+      priv->scan_result_entries = 0;
     }
 
-  memcpy(iwr->u.data.pointer, priv->scan_result, iwr->u.data.length);
-
-exit_free_buffer:
-
-  /* Free scan result buffer */
-
-  kmm_free(priv->scan_result);
-  priv->scan_result = NULL;
-  priv->scan_result_size = 0;
-
 exit_sem_post:
   nxsem_post(&priv->control_mutex);
 
diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h
index 3a5c96d63e..1361912e1a 100644
--- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h
+++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h
@@ -89,8 +89,8 @@ struct bcmf_dev_s
 
   int scan_status;                     /* Current scan status */
   struct wdog_s scan_timeout;          /* Scan timeout timer */
-  FAR uint8_t *scan_result;            /* Temp buffer that holds results */
-  unsigned int scan_result_size;       /* Current size of temp buffer */
+  FAR wl_bss_info_t *scan_result;      /* Temp buffer that holds results */
+  unsigned int scan_result_entries;    /* Current entries of temp buffer */
 
   sem_t auth_signal; /* Authentication notification signal */
   int   auth_status; /* Authentication status */