wlan: Add support to get wlan version info from cfg layer

Add support to send wlan driver related information
to user space for debugging.

Change-Id: Id8d1583eac9e8259b5a5cd86e755c1064f879382
CRs-Fixed: 818318
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 9243f56..de675e1 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -95,6 +95,8 @@
 #include "wlan_qct_wda.h"
 #include "wlan_nv.h"
 #include "wlan_hdd_dev_pwr.h"
+#include "qwlan_version.h"
+
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -6198,6 +6200,12 @@
         .subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN
     },
 
+    {
+        .vendor_id = QCA_NL80211_VENDOR_ID,
+        .subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO,
+    }
+
+
 };
 
 /*
@@ -14327,6 +14335,88 @@
 
     return ret;
 }
+static const struct
+nla_policy
+qca_wlan_vendor_get_wifi_info_policy[
+         QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX +1] = {
+    [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 },
+    [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 },
+};
+
+/**
+ * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info
+ * @wiphy:   pointer to wireless wiphy structure.
+ * @wdev:    pointer to wireless_dev structure.
+ * @data:    Pointer to the data to be passed via vendor interface
+ * @data_len:Length of the data to be passed
+ *
+ * This is called when wlan driver needs to send wifi driver related info
+ * (driver/fw version) to the user space application upon request.
+ *
+ * Return:   Return the Success or Failure code.
+ */
+static int
+wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy,
+                                  struct wireless_dev *wdev,
+                              const void *data, int data_len)
+{
+    hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+    struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1];
+    tSirVersionString version;
+    uint32 version_len;
+    uint8 attr;
+    int status;
+    struct sk_buff *reply_skb = NULL;
+
+    if (VOS_FTM_MODE == hdd_get_conparam()) {
+        hddLog(LOGE, FL("Command not allowed in FTM mode"));
+        return -EINVAL;
+    }
+
+    status = wlan_hdd_validate_context(hdd_ctx);
+    if (0 != status) {
+        hddLog(LOGE, FL("HDD context is not valid"));
+        return -EINVAL;
+    }
+
+    if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, data,
+        data_len, qca_wlan_vendor_get_wifi_info_policy)) {
+        hddLog(LOGE, FL("WIFI_INFO_GET NL CMD parsing failed"));
+        return -EINVAL;
+    }
+
+    if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) {
+        hddLog(LOG1, FL("Rcvd req for Driver version "
+                        "Driver version is %s"),QWLAN_VERSIONSTR);
+        strlcpy(version, QWLAN_VERSIONSTR, sizeof(version));
+        attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION;
+    } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) {
+        hddLog(LOG1, FL("Rcvd req for FW version "
+                        "FW version is %s"), hdd_ctx->fw_Version);
+        strlcpy(version, hdd_ctx->fw_Version, sizeof(version));
+        attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION;
+    } else {
+        hddLog(LOGE, FL("Invalid attribute in get wifi info request"));
+        return -EINVAL;
+    }
+
+    version_len = strlen(version);
+    reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+    version_len + NLA_HDRLEN + NLMSG_HDRLEN);
+    if (!reply_skb) {
+        hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
+        return -ENOMEM;
+    }
+
+    if (nla_put(reply_skb, attr, version_len, version)) {
+        hddLog(LOGE, FL("nla put fail"));
+        kfree_skb(reply_skb);
+        return -EINVAL;
+    }
+
+    return cfg80211_vendor_cmd_reply(reply_skb);
+}
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
 static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy,
                                            struct net_device *netdev,