prima: Fix Set/Clear MCBC ioctl transition in early suspend

Host uses set MCBC ioctl to change the MCBC value
dynamically. But current host ioctl handling is not
correct because firmware expects host must first disable
offloads and later apply new filter value. Instead
Host is applying new MCBC filter value without disabling
offloads in early suspend mode.

Another issue is host is updating suspend MCBC filter
even when wlan is not in early suspend mode during
IPv4 and Ipv6 change handling.

As part of this fix, ensure host first disable and then
enable offload. Host modify the suspend MCBC filter only
when wlan is in early suspended mode.

Change-Id: Ib759dd2210eb7e1acf028456c4ca98239f425604
CRs-Fixed: 1096069
diff --git a/CORE/HDD/src/wlan_hdd_early_suspend.c b/CORE/HDD/src/wlan_hdd_early_suspend.c
index 05abfef..01b8a9d 100644
--- a/CORE/HDD/src/wlan_hdd_early_suspend.c
+++ b/CORE/HDD/src/wlan_hdd_early_suspend.c
@@ -106,6 +106,23 @@
 static struct timer_list ssr_timer;
 static bool ssr_timer_started;
 
+void inline check_and_set_suspend_resume_mcbc_filter(hdd_context_t *pHddCtx)
+{
+    hddLog(VOS_TRACE_LEVEL_INFO,
+       FL("offload: sus_res_mcbc_filter_valid: %d sus_res_mcbc_filter: %d configuredMcBcFilter: %d"),
+       pHddCtx->sus_res_mcastbcast_filter_valid,
+       pHddCtx->sus_res_mcastbcast_filter,
+       pHddCtx->configuredMcastBcastFilter);
+    if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid)
+    {
+       pHddCtx->sus_res_mcastbcast_filter =
+           pHddCtx->configuredMcastBcastFilter;
+       pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE;
+       hddLog(VOS_TRACE_LEVEL_INFO,
+           FL("offload: saving sus_res_mcastbcast_filter = %d"),
+           pHddCtx->sus_res_mcastbcast_filter);
+    }
+}
 
 #ifdef FEATURE_WLAN_DIAG_SUPPORT
 /**
@@ -504,19 +521,11 @@
         return;
     }
 
-    if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid)
-    {
-        pHddCtx->sus_res_mcastbcast_filter =
-            pHddCtx->configuredMcastBcastFilter;
-        hddLog(LOG1, FL("saving configuredMcastBcastFilter = %d"),
-                        pHddCtx->sus_res_mcastbcast_filter);
-        pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE;
-    }
-
     if ((eConnectionState_Associated ==
                 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)
         && (pHddCtx->hdd_wlan_suspended))
     {
+        check_and_set_suspend_resume_mcbc_filter(pHddCtx);
         // This invocation being part of the IPv6 registration callback,
         // set the newly generated ip address to f/w in suspend mode.
 #ifdef WLAN_NS_OFFLOAD
@@ -713,6 +722,11 @@
             {
                 hdd_conf_ns_offload(pAdapter, fenable);
             }
+            else
+            {
+                hddLog(VOS_TRACE_LEVEL_INFO,
+                    FL("ns offload ini is disabled"));
+            }
 #endif
         }
     }
@@ -919,13 +933,13 @@
                     {
                         offLoadRequest.enableOrDisable =
                             SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE;
-                        hddLog (VOS_TRACE_LEVEL_INFO,
-                                FL("Set offLoadRequest with %d"),
-                                   offLoadRequest.enableOrDisable);
                     }
                     hdd_wlan_offload_event(
                                   SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE,
                                   SIR_OFFLOAD_ENABLE);
+                    hddLog(VOS_TRACE_LEVEL_INFO,
+                        FL("offload: NS filter programmed %d"),
+                        offLoadRequest.enableOrDisable);
                     vos_mem_copy(&offLoadRequest.params.hostIpv6Addr,
                                 &offLoadRequest.nsOffloadInfo.targetIPv6Addr[0],
                                 sizeof(tANI_U8)*SIR_MAC_IPV6_ADDR_LEN);
@@ -1016,15 +1030,6 @@
         return;
     }
 
-    if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid)
-    {
-        pHddCtx->sus_res_mcastbcast_filter =
-            pHddCtx->configuredMcastBcastFilter;
-        hddLog(LOG1, FL("saving configuredMcastBcastFilter = %d"),
-                        pHddCtx->sus_res_mcastbcast_filter);
-        pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE;
-    }
-
     if ((eConnectionState_Associated ==
                 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)
         && (pHddCtx->hdd_wlan_suspended))
@@ -1032,7 +1037,16 @@
         // This invocation being part of the IPv4 registration callback,
         // we are passing second parameter as 2 to avoid registration
         // of IPv4 notifier again.
-        hdd_conf_arp_offload(pAdapter, 2);
+        check_and_set_suspend_resume_mcbc_filter(pHddCtx);
+        if (pHddCtx->cfg_ini->fhostArpOffload)
+        {
+            hdd_conf_arp_offload(pAdapter, 2);
+        }
+        else
+        {
+            hddLog(VOS_TRACE_LEVEL_INFO,
+                    FL("offload: arp offload ini is disabled in host"));
+        }
     }
     EXIT();
 }
@@ -1341,7 +1355,8 @@
         value, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE)
     {
        ret_val = eHAL_STATUS_FAILURE;
-       hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CCM");
+       hddLog(LOGE,
+           FL("offload: can't pass WNI_CFG_ENABLE_MC_ADDR_LIST to CCM"));
        return ret_val;
     }
 
@@ -1356,12 +1371,17 @@
     }
     /* cache the value configured in fwr */
     pHddCtx->mc_list_cfg_in_fwr = value;
-
     return eHAL_STATUS_SUCCESS;
 }
 
 bool is_mc_list_cfg_disable_required(hdd_context_t* pHddCtx)
 {
+    hddLog(VOS_TRACE_LEVEL_INFO,
+        FL("offload: fEnableMCList %d sus_res_mcbc_filter %d mc_list_in_fwr %d"),
+        pHddCtx->cfg_ini->fEnableMCAddrList,
+        pHddCtx->sus_res_mcastbcast_filter,
+        pHddCtx->mc_list_cfg_in_fwr);
+
     /*
      * If MCAddrList is enabled in ini and MCBC filter is set to
      * Either Filter None or Filter all BC then, Fwr need to push
@@ -1378,10 +1398,14 @@
                  pHddCtx->sus_res_mcastbcast_filter)))
        )
     {
+        hddLog(VOS_TRACE_LEVEL_INFO,
+            FL("offload: cfg ini need to disable in fwr"));
         return true;
     }
     else
     {
+        hddLog(VOS_TRACE_LEVEL_INFO,
+            FL("offload: cfg ini disable not needed "));
         return false;
     }
 }
@@ -1414,6 +1438,9 @@
             {
                 hdd_set_mc_list_cfg_item(pHddCtx,
                     !pHddCtx->cfg_ini->fEnableMCAddrList);
+                hddLog(VOS_TRACE_LEVEL_INFO,
+                    FL("offload: setting mc_list_cfg_in_fwr: %d"),
+                    !pHddCtx->cfg_ini->fEnableMCAddrList);
             }
         }
         else
@@ -1424,6 +1451,9 @@
            {
                hdd_set_mc_list_cfg_item(pHddCtx,
                    pHddCtx->cfg_ini->fEnableMCAddrList);
+               hddLog(VOS_TRACE_LEVEL_INFO,
+                   FL("offload: setting mc_list_cfg_in_fwr: %d"),
+                   pHddCtx->cfg_ini->fEnableMCAddrList);
            }
         }
     }
@@ -1435,6 +1465,9 @@
        {
            hdd_set_mc_list_cfg_item(pHddCtx,
                pHddCtx->cfg_ini->fEnableMCAddrList);
+           hddLog(VOS_TRACE_LEVEL_INFO,
+               FL("offload: setting mc_list_cfg_in_fwr: %d"),
+               pHddCtx->cfg_ini->fEnableMCAddrList);
        }
     }
 }
@@ -1446,17 +1479,7 @@
     tpSirWlanSuspendParam wlanSuspendParam =
       vos_mem_malloc(sizeof(tSirWlanSuspendParam));
 
-    if (VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) {
-        pHddCtx->sus_res_mcastbcast_filter =
-            pHddCtx->configuredMcastBcastFilter;
-        pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE;
-        hddLog(VOS_TRACE_LEVEL_INFO, "offload: hdd_conf_suspend_ind");
-        hddLog(VOS_TRACE_LEVEL_INFO, "configuredMCastBcastFilter saved = %d",
-               pHddCtx->configuredMcastBcastFilter);
-
-    }
-
-
+    check_and_set_suspend_resume_mcbc_filter(pHddCtx);
     if(NULL == wlanSuspendParam)
     {
         hddLog(VOS_TRACE_LEVEL_FATAL,
@@ -1671,6 +1694,69 @@
    return;
 }
 
+/**
+ * @brief hdd_ReConfigSuspendDataClearedDuringRoaming() - Reconfigure the
+ * suspend related data which was cleared during roaming in FWR.
+ */
+void hdd_ReConfigSuspendDataClearedDuringRoaming(hdd_context_t *pHddCtx)
+
+{
+    VOS_STATUS vstatus = VOS_STATUS_E_FAILURE;
+    hdd_adapter_t *pAdapter;
+    hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+
+    ENTER();
+
+    spin_lock(&pHddCtx->filter_lock);
+    check_and_set_suspend_resume_mcbc_filter(pHddCtx);
+    spin_unlock(&pHddCtx->filter_lock);
+
+    hdd_conf_mcastbcast_filter(pHddCtx, TRUE);
+    if(pHddCtx->hdd_mcastbcast_filter_set != TRUE)
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("Not able to set mcast/bcast filter "));
+
+    vstatus = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+    //No need to configure GTK Offload from here because it might possible
+    //cfg80211_set_rekey_data might not yet came, anyway GTK offload will
+    //be handled as part of cfg80211_set_rekey_data processing.
+    while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == vstatus )
+    {
+        pAdapter = pAdapterNode->pAdapter;
+        if( pAdapter &&
+        (( pAdapter->device_mode == WLAN_HDD_INFRA_STATION)  ||
+          (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)))
+        {
+            if (pHddCtx->cfg_ini->fhostArpOffload)
+            {
+                //Configure ARPOFFLOAD
+                vstatus = hdd_conf_arp_offload(pAdapter, TRUE);
+                if (!VOS_IS_STATUS_SUCCESS(vstatus))
+                {
+                    hddLog(VOS_TRACE_LEVEL_INFO,
+                        FL("Failed to disable ARPOffload Feature %d"), vstatus);
+                }
+            }
+#ifdef WLAN_NS_OFFLOAD
+            //Configure NSOFFLOAD
+            if (pHddCtx->cfg_ini->fhostNSOffload)
+            {
+                hdd_conf_ns_offload(pAdapter, TRUE);
+            }
+#endif
+#ifdef WLAN_FEATURE_PACKET_FILTERING
+            /* During suspend, configure MC Addr list filter to the firmware
+             * function takes care of checking necessary conditions before
+             * configuring.
+             */
+            wlan_hdd_set_mc_addr_list(pAdapter, TRUE);
+#endif
+        }
+        vstatus = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+        pAdapterNode = pNext;
+    }
+    EXIT();
+}
+
 static void hdd_PowerStateChangedCB
 (
    v_PVOID_t callbackContext,
@@ -1691,21 +1777,8 @@
    spin_lock(&pHddCtx->filter_lock);
    if ((newState == BMPS) &&  pHddCtx->hdd_wlan_suspended)
    {
+      check_and_set_suspend_resume_mcbc_filter(pHddCtx);
       spin_unlock(&pHddCtx->filter_lock);
-      if (VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid)
-      {
-          pHddCtx->sus_res_mcastbcast_filter =
-              pHddCtx->configuredMcastBcastFilter;
-          pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE;
-
-          hddLog(VOS_TRACE_LEVEL_INFO, "offload: callback to associated");
-          hddLog(VOS_TRACE_LEVEL_INFO, "saving configuredMcastBcastFilter = %d",
-                 pHddCtx->configuredMcastBcastFilter);
-          hddLog(VOS_TRACE_LEVEL_INFO,
-                 "offload: calling hdd_conf_mcastbcast_filter");
-
-      }
-
       hdd_conf_mcastbcast_filter(pHddCtx, TRUE);
       if(pHddCtx->hdd_mcastbcast_filter_set != TRUE)
          hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Not able to set mcast/bcast filter ", __func__);