net: wireless: bcmdhd: Re-set country code on disconnection
Srinivas Ramachandran [Sat, 15 Apr 2017 01:19:58 +0000 (18:19 -0700)]
Issue: Sometime on disconnection from AP on
DFS channel, firmware channel flags are still in stale active
state. This leads to active scanning on DFS channel without AP
connection, which is not permitted.

Fix: Re-set the current firmware country code to update the channel
flags on disconnection. This will restore the channel flags.

Bug 1883430

Change-Id: I773ce9bcdd2c1943668380f106601be1acb4259c
Signed-off-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-on: http://git-master/r/1465084
Reviewed-by: Mohan Thadikamalla <mohant@nvidia.com>
Reviewed-by: Mahesh Patil <maheshp@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>

drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wldev_common.c

index 7978526..26652f9 100644 (file)
@@ -9104,6 +9104,11 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                        "event : %d, reason=%d from " MACDBG "\n",
                                        ndev->name, event, ntoh32(e->reason),
                                        MAC2STRDBG((u8*)(&e->addr))));
+                               /* Re-set existing country code to restore channel
+                                * flags on DFS channels
+                                */
+                               if ((cfg->channel >= 50) && (cfg->channel <= 144))
+                                       wldev_set_country(ndev, NULL, true, false);
 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
                                if (ntoh32(e->reason) == 15) {
                                        TEGRA_SYSFS_HISTOGRAM_STAT_INC(connect_fail_reason_15);
index 7755713..ef3536c 100644 (file)
@@ -416,9 +416,6 @@ int wldev_set_country(
        scb_val_t scbval;
        char smbuf[WLC_IOCTL_SMLEN];
 
-       if (!country_code)
-               return error;
-
        bzero(&scbval, sizeof(scb_val_t));
        error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL);
        if (error < 0) {
@@ -426,34 +423,43 @@ int wldev_set_country(
                return error;
        }
 
-       if ((error < 0) ||
-           (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) {
+       /* Skip setting same country code provided again */
+       if (country_code &&
+           (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) == 0))
+               return 0;
 
-               if (user_enforced) {
-                       bzero(&scbval, sizeof(scb_val_t));
-                       error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
-                       if (error < 0) {
-                               WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
-                                       __FUNCTION__, error));
-                               return error;
-                       }
-               }
+       /* Reset existing country code if none provided */
+       if (!country_code)
+               goto set_cur_ccode;
 
-               cspec.rev = -1;
-               memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
-               memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
-               dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
-               error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
-                       smbuf, sizeof(smbuf), NULL);
+       if (user_enforced) {
+               bzero(&scbval, sizeof(scb_val_t));
+               error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
                if (error < 0) {
-                       WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
-                               __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+                       WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
+                               __FUNCTION__, error));
                        return error;
                }
-               dhd_bus_country_set(dev, &cspec, notify);
-               WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
+       }
+
+       cspec.rev = -1;
+       memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
+       memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
+       dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
+
+set_cur_ccode:
+
+       error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
+               smbuf, sizeof(smbuf), NULL);
+       if (error < 0) {
+               WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
                        __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+               return error;
        }
+       dhd_bus_country_set(dev, &cspec, notify);
+       WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
+               __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+
        return 0;
 }