wlan: Add one more variable sent through debugfs for WoW

Add "mask" variable support for WoW feature through debugfs interface.
Also add explicitly enable/disable WoW support through debugfs.

Change-Id: I1c7a2253de55541fe2dbc0cba7ee2961f83313ca
CRs-Fixed: 576468
diff --git a/CORE/HDD/inc/wlan_hdd_wowl.h b/CORE/HDD/inc/wlan_hdd_wowl.h
index 82e3ff8..5ab7861 100644
--- a/CORE/HDD/inc/wlan_hdd_wowl.h
+++ b/CORE/HDD/inc/wlan_hdd_wowl.h
@@ -153,21 +153,24 @@
 
 /**============================================================================
   @brief hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern
-  to be used when PBM filtering is enabled and MP filtering is disabled
+  sent from debugfs interface
 
   @param pAdapter       : [in] pointer to the adapter
          pattern_idx    : [in] index of the pattern to be added
          pattern_offset : [in] offset of the pattern in the frame payload
          pattern_buf    : [in] pointer to the pattern hex string to be added
+         pattern_mask   : [in] pointer to the pattern mask hex string
 
   @return               : FALSE if any errors encountered
                         : TRUE otherwise
   ===========================================================================*/
 v_BOOL_t hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, v_U8_t pattern_idx,
-                                   v_U8_t pattern_offset, char *pattern_buf);
+                                   v_U8_t pattern_offset, char *pattern_buf,
+                                   char *pattern_mask);
 
 /**============================================================================
   @brief hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern
+  sent from debugfs interface
 
   @param pAdapter    : [in] pointer to the adapter
          pattern_idx : [in] index of the pattern to be removed
diff --git a/CORE/HDD/src/wlan_hdd_debugfs.c b/CORE/HDD/src/wlan_hdd_debugfs.c
index c15d222..ab90322 100644
--- a/CORE/HDD/src/wlan_hdd_debugfs.c
+++ b/CORE/HDD/src/wlan_hdd_debugfs.c
@@ -31,9 +31,103 @@
 #include <wlan_hdd_includes.h>
 #include <wlan_hdd_wowl.h>
 
+#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
 #define MAX_USER_COMMAND_SIZE_FRAME 4096
 
+static ssize_t wcnss_wowenable_write(struct file *file,
+               const char __user *buf, size_t count, loff_t *ppos)
+{
+    hdd_adapter_t *pAdapter = (hdd_adapter_t *)file->private_data;
+
+    char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
+    char *sptr, *token;
+    v_U8_t wow_enable = 0;
+    v_U8_t wow_mp = 0;
+    v_U8_t wow_pbm = 0;
+
+    if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+                  "%s: Invalid adapter or adapter has invalid magic.",
+                  __func__);
+
+        return -EINVAL;
+    }
+
+    if (!sme_IsFeatureSupportedByFW(WOW))
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s: Wake-on-Wireless feature is not supported "
+                  "in firmware!", __func__);
+
+        return -EINVAL;
+    }
+
+    if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s: Command length is larger than %d bytes.",
+                  __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
+
+        return -EINVAL;
+    }
+
+    /* Get command from user */
+    if (copy_from_user(cmd, buf, count))
+        return -EFAULT;
+    cmd[count] = '\0';
+    sptr = cmd;
+
+    /* Get enable or disable wow */
+    token = strsep(&sptr, " ");
+    if (!token)
+        return -EINVAL;
+    if (kstrtou8(token, 0, &wow_enable))
+        return -EINVAL;
+
+    /* Disable wow */
+    if (!wow_enable) {
+        if (!hdd_exit_wowl(pAdapter))
+        {
+          VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                    "%s: hdd_exit_wowl failed!", __func__);
+
+          return -EFAULT;
+        }
+
+        return count;
+    }
+
+    /* Get enable or disable magic packet mode */
+    token = strsep(&sptr, " ");
+    if (!token)
+        return -EINVAL;
+    if (kstrtou8(token, 0, &wow_mp))
+        return -EINVAL;
+    if (wow_mp > 1)
+        wow_mp = 1;
+
+    /* Get enable or disable pattern byte matching mode */
+    token = strsep(&sptr, " ");
+    if (!token)
+        return -EINVAL;
+    if (kstrtou8(token, 0, &wow_pbm))
+        return -EINVAL;
+    if (wow_pbm > 1)
+        wow_pbm = 1;
+
+    if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm))
+    {
+      VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                "%s: hdd_enter_wowl failed!", __func__);
+
+      return -EFAULT;
+    }
+
+    return count;
+}
+
 static ssize_t wcnss_wowpattern_write(struct file *file,
                const char __user *buf, size_t count, loff_t *ppos)
 {
@@ -44,6 +138,7 @@
     v_U8_t pattern_idx = 0;
     v_U8_t pattern_offset = 0;
     char *pattern_buf;
+    char *pattern_mask;
 
     if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic))
     {
@@ -105,10 +200,17 @@
         return -EINVAL;
 
     pattern_buf = token;
-    pattern_buf[strlen(pattern_buf) - 1] = '\0';
+
+    /* Get pattern mask */
+    token = strsep(&sptr, " ");
+    if (!token)
+        return -EINVAL;
+
+    pattern_mask = token;
+    pattern_mask[strlen(pattern_mask) - 1] = '\0';
 
     hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
-                              pattern_buf);
+                              pattern_buf, pattern_mask);
 
     return count;
 }
@@ -149,7 +251,7 @@
     }
 
     /* Get command from user */
-    if (count < MAX_USER_COMMAND_SIZE_FRAME)
+    if (count <= MAX_USER_COMMAND_SIZE_FRAME)
         cmd = vos_mem_malloc(count + 1);
     else
     {
@@ -328,6 +430,13 @@
     return 0;
 }
 
+static const struct file_operations fops_wowenable = {
+    .write = wcnss_wowenable_write,
+    .open = wcnss_debugfs_open,
+    .owner = THIS_MODULE,
+    .llseek = default_llseek,
+};
+
 static const struct file_operations fops_wowpattern = {
     .write = wcnss_wowpattern_write,
     .open = wcnss_debugfs_open,
@@ -350,6 +459,10 @@
     if (NULL == pHddCtx->debugfs_phy)
         return VOS_STATUS_E_FAILURE;
 
+    if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR,
+        pHddCtx->debugfs_phy, pAdapter, &fops_wowenable))
+        return VOS_STATUS_E_FAILURE;
+
     if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR,
         pHddCtx->debugfs_phy, pAdapter, &fops_wowpattern))
         return VOS_STATUS_E_FAILURE;
diff --git a/CORE/HDD/src/wlan_hdd_wowl.c b/CORE/HDD/src/wlan_hdd_wowl.c
index f7e5c68..dfb22af 100644
--- a/CORE/HDD/src/wlan_hdd_wowl.c
+++ b/CORE/HDD/src/wlan_hdd_wowl.c
@@ -349,24 +349,26 @@
 
 /**============================================================================
   @brief hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern
-  to be used when PBM filtering is enabled and MP filtering is disabled
+  sent from debugfs interface
 
   @param pAdapter       : [in] pointer to the adapter
          pattern_idx    : [in] index of the pattern to be added
          pattern_offset : [in] offset of the pattern in the frame payload
          pattern_buf    : [in] pointer to the pattern hex string to be added
+         pattern_mask   : [in] pointer to the pattern mask hex string
 
   @return               : FALSE if any errors encountered
                         : TRUE otherwise
   ===========================================================================*/
 v_BOOL_t hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, v_U8_t pattern_idx,
-                                   v_U8_t pattern_offset, char *pattern_buf)
+                                   v_U8_t pattern_offset, char *pattern_buf,
+                                   char *pattern_mask)
 {
   tSirWowlAddBcastPtrn localPattern;
   eHalStatus halStatus;
   tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
   v_U8_t sessionId = pAdapter->sessionId;
-  v_U16_t pattern_len, i;
+  v_U16_t pattern_len, mask_len, i;
 
   if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1))
   {
@@ -413,16 +415,28 @@
     pattern_buf += 2;
   }
 
-  /* Generate bytemask by pattern length */
-  for (i = 0; i < (pattern_len >> 3); i++)
-    localPattern.ucPatternMask[i] = 0xFF;
-
-  localPattern.ucPatternMaskSize = i;
-
+  /* Get pattern mask size by pattern length */
+  localPattern.ucPatternMaskSize = pattern_len >> 3;
   if (pattern_len % 8)
-  {
-    localPattern.ucPatternMask[i] = (1 << (pattern_len % 8)) - 1;
     localPattern.ucPatternMaskSize += 1;
+
+  mask_len = strlen(pattern_mask);
+  if ((mask_len % 2) || (localPattern.ucPatternMaskSize != (mask_len >> 1)))
+  {
+    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+               "%s: Malformed WoW pattern mask!", __func__);
+
+    return VOS_FALSE;
+  }
+
+  /* Extract the pattern mask */
+  for (i = 0; i < localPattern.ucPatternMaskSize; i++)
+  {
+    localPattern.ucPatternMask[i] =
+      (hdd_parse_hex(pattern_mask[0]) << 4) + hdd_parse_hex(pattern_mask[1]);
+
+    /* Skip to next byte */
+    pattern_mask += 2;
   }
 
   /* Register the pattern downstream */
@@ -437,16 +451,6 @@
     return VOS_FALSE;
   }
 
-  /* Enable WoW immediately after add a pattern. By default,
-   * disable magic packet mode and enable pattern byte matching mode. */
-  if (!hdd_enter_wowl(pAdapter, 0, 1))
-  {
-    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-               "%s: hdd_enter_wowl failed!", __func__);
-
-    return VOS_FALSE;
-  }
-
   /* All is good. */
   if (!g_hdd_wowl_ptrns_debugfs[pattern_idx])
   {
@@ -461,6 +465,7 @@
 
 /**============================================================================
   @brief hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern
+  sent from debugfs interface
 
   @param pAdapter    : [in] pointer to the adapter
          pattern_idx : [in] index of the pattern to be removed
@@ -508,17 +513,6 @@
   g_hdd_wowl_ptrns_debugfs[pattern_idx] = 0;
   g_hdd_wowl_ptrns_count--;
 
-  if (g_hdd_wowl_ptrns_count == 0)
-  {
-    if (!hdd_exit_wowl(pAdapter))
-    {
-      VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: hdd_exit_wowl failed!", __func__);
-
-      return VOS_FALSE;
-    }
-  }
-
   return VOS_TRUE;
 }