mac80211: brcmfmac: backport scheduled scan cleanup and chip support
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 357-0004-brcmfmac-fix-handling-ssids-in-.sched_scan_start-cal.patch
diff --git a/package/kernel/mac80211/patches/357-0004-brcmfmac-fix-handling-ssids-in-.sched_scan_start-cal.patch b/package/kernel/mac80211/patches/357-0004-brcmfmac-fix-handling-ssids-in-.sched_scan_start-cal.patch
new file mode 100644 (file)
index 0000000..f1934af
--- /dev/null
@@ -0,0 +1,221 @@
+From 3e2e86ab19c2a43953de30089c5411c580ddb5f7 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Wed, 23 Nov 2016 10:25:23 +0000
+Subject: [PATCH] brcmfmac: fix handling ssids in .sched_scan_start() callback
+
+The ssids list in the scheduled scan request were not properly taken
+into account when configuring in firmware. The hidden bit was set for
+any ssid resulting in active scanning for all. Only set it for ssids
+that are in the ssids list.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/cfg80211.c         | 103 ++++++++++-----------
+ .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c |  18 ++++
+ .../net/wireless/broadcom/brcm80211/brcmfmac/pno.h |  12 ++-
+ 3 files changed, 76 insertions(+), 57 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -3314,19 +3314,37 @@ out_err:
+       return err;
+ }
++static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid,
++                               struct cfg80211_sched_scan_request *req)
++{
++      int i;
++
++      if (!ssid || !req->ssids || !req->n_ssids)
++              return false;
++
++      for (i = 0; i < req->n_ssids; i++) {
++              if (ssid->ssid_len == req->ssids[i].ssid_len) {
++                      if (!strncmp(ssid->ssid, req->ssids[i].ssid,
++                                   ssid->ssid_len))
++                              return true;
++              }
++      }
++      return false;
++}
++
+ static int
+ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
+                               struct net_device *ndev,
+-                              struct cfg80211_sched_scan_request *request)
++                              struct cfg80211_sched_scan_request *req)
+ {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+-      struct brcmf_pno_net_param_le pfn;
++      struct cfg80211_ssid *ssid;
+       int i;
+       int ret = 0;
+       brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
+-                request->n_match_sets, request->n_ssids);
++                req->n_match_sets, req->n_ssids);
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
+               return -EAGAIN;
+@@ -3337,71 +3355,46 @@ brcmf_cfg80211_sched_scan_start(struct w
+               return -EAGAIN;
+       }
+-      if (!request->n_ssids || !request->n_match_sets) {
+-              brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
+-                        request->n_ssids);
++      if (req->n_match_sets <= 0) {
++              brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
++                        req->n_match_sets);
+               return -EINVAL;
+       }
+-      if (request->n_ssids > 0) {
+-              for (i = 0; i < request->n_ssids; i++) {
+-                      /* Active scan req for ssids */
+-                      brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
+-                                request->ssids[i].ssid);
+-
+-                      /* match_set ssids is a supert set of n_ssid list,
+-                       * so we need not add these set separately.
+-                       */
+-              }
++      /* clean up everything */
++      ret = brcmf_pno_clean(ifp);
++      if  (ret < 0) {
++              brcmf_err("failed error=%d\n", ret);
++              return ret;
+       }
+-      if (request->n_match_sets > 0) {
+-              /* clean up everything */
+-              ret = brcmf_pno_clean(ifp);
+-              if  (ret < 0) {
+-                      brcmf_err("failed error=%d\n", ret);
+-                      return ret;
++      /* configure pno */
++      ret = brcmf_pno_config(ifp, req);
++      if (ret < 0)
++              return ret;
++
++      /* configure each match set */
++      for (i = 0; i < req->n_match_sets; i++) {
++
++              ssid = &req->match_sets[i].ssid;
++
++              if (!ssid->ssid_len) {
++                      brcmf_err("skip broadcast ssid\n");
++                      continue;
+               }
+-              /* configure pno */
+-              ret = brcmf_pno_config(ifp, request);
++              ret = brcmf_pno_add_ssid(ifp, ssid,
++                                       brcmf_is_ssid_active(ssid, req));
+               if (ret < 0)
+-                      return ret;
+-
+-              /* configure each match set */
+-              for (i = 0; i < request->n_match_sets; i++) {
+-                      struct cfg80211_ssid *ssid;
+-                      u32 ssid_len;
+-
+-                      ssid = &request->match_sets[i].ssid;
+-                      ssid_len = ssid->ssid_len;
+-
+-                      if (!ssid_len) {
+-                              brcmf_err("skip broadcast ssid\n");
+-                              continue;
+-                      }
+-                      pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
+-                      pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
+-                      pfn.wsec = cpu_to_le32(0);
+-                      pfn.infra = cpu_to_le32(1);
+-                      pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
+-                      pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
+-                      memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
+-                      ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
+-                                                     sizeof(pfn));
+                       brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
+                                 ret == 0 ? "set" : "failed", ssid->ssid);
+-              }
+-              /* Enable the PNO */
+-              if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
+-                      brcmf_err("PNO enable failed!! ret=%d\n", ret);
+-                      return -EINVAL;
+-              }
+-      } else {
+-              return -EINVAL;
+       }
++      /* Enable the PNO */
++      ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1);
++      if (ret < 0)
++              brcmf_err("PNO enable failed!! ret=%d\n", ret);
+-      return 0;
++      return ret;
+ }
+ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+@@ -28,6 +28,8 @@
+ #define BRCMF_PNO_FREQ_EXPO_MAX               3
+ #define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT        6
+ #define BRCMF_PNO_SCAN_INCOMPLETE     0
++#define BRCMF_PNO_WPA_AUTH_ANY                0xFFFFFFFF
++#define BRCMF_PNO_HIDDEN_BIT          2
+ int brcmf_pno_clean(struct brcmf_if *ifp)
+ {
+@@ -98,3 +100,19 @@ int brcmf_pno_config(struct brcmf_if *if
+       return err;
+ }
++int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
++                     bool active)
++{
++      struct brcmf_pno_net_param_le pfn;
++
++      pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
++      pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
++      pfn.wsec = cpu_to_le32(0);
++      pfn.infra = cpu_to_le32(1);
++      if (active)
++              pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
++      pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len);
++      memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len);
++      return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn));
++}
++
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+@@ -17,8 +17,6 @@
+ #define _BRCMF_PNO_H
+ #define BRCMF_PNO_SCAN_COMPLETE               1
+-#define BRCMF_PNO_WPA_AUTH_ANY                0xFFFFFFFF
+-#define BRCMF_PNO_HIDDEN_BIT          2
+ #define BRCMF_PNO_MAX_PFN_COUNT               16
+ /**
+@@ -37,4 +35,14 @@ int brcmf_pno_clean(struct brcmf_if *ifp
+ int brcmf_pno_config(struct brcmf_if *ifp,
+                    struct cfg80211_sched_scan_request *request);
++/**
++ * brcmf_pno_add_ssid - add ssid for pno in firmware.
++ *
++ * @ifp: interface object used.
++ * @ssid: ssid information.
++ * @active: indicate this ssid needs to be actively probed.
++ */
++int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
++                     bool active);
++
+ #endif /* _BRCMF_PNO_H */