wlan: Logging Infrastructure

Enhance driver to send the driver log messages to the userspace
app. This helps in enabling more log levels in driver without
any issue of device going into download mode due to excessive
logging.

Change-Id: I18d5e593823e394464c0a4824351c4417dca5476
CRs-Fixed: 628075
(cherry picked from commit 55fd6c173286517e34ad865784618d3c46b225ce)
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index 80b68f7..99316ca 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -2121,6 +2121,26 @@
 #define CFG_ROAMING_DFS_CHANNEL_MAX                 (1)
 #define CFG_ROAMING_DFS_CHANNEL_DEFAULT             (0)
 
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+//Enable WLAN Logging to app space
+#define CFG_WLAN_LOGGING_SUPPORT_NAME            "wlanLoggingEnable"
+#define CFG_WLAN_LOGGING_SUPPORT_ENABLE          ( 1 )
+#define CFG_WLAN_LOGGING_SUPPORT_DISABLE         ( 0 )
+#define CFG_WLAN_LOGGING_SUPPORT_DEFAULT         ( 1 )
+
+//Enable FATAL and ERROR logs for kmsg console
+#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME     "wlanLoggingFEToConsole"
+#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE   ( 1 )
+#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE  ( 0 )
+#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT  ( 0 )
+
+//Number of buffers to be used for WLAN logging
+#define CFG_WLAN_LOGGING_NUM_BUF_NAME     "wlanLoggingNumBuf"
+#define CFG_WLAN_LOGGING_NUM_BUF_MIN      ( 8  )
+#define CFG_WLAN_LOGGING_NUM_BUF_MAX      ( 64 )
+#define CFG_WLAN_LOGGING_NUM_BUF_DEFAULT  ( 32 )
+#endif //WLAN_LOGGING_SOCK_SVC_ENABLE
+
 /*--------------------------------------------------------------------------- 
   Type declarations
   -------------------------------------------------------------------------*/ 
@@ -2556,6 +2576,14 @@
    v_BOOL_t                    cfgRAFilterEnable;
    v_U16_t                     cfgRARateLimitInterval;
    v_U8_t                      allowDFSChannelRoam;
+
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+   //WLAN Logging
+   v_U32_t                     wlanLoggingEnable;
+   v_U32_t                     wlanLoggingFEToConsole;
+   v_U32_t                     wlanLoggingNumBuf;
+#endif
+
 } hdd_config_t;
 /*--------------------------------------------------------------------------- 
   Function declarations and documenation
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index ef4879b..ea70f45 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -2950,6 +2950,30 @@
                  CFG_ROAMING_DFS_CHANNEL_DEFAULT,
                  CFG_ROAMING_DFS_CHANNEL_MIN,
                  CFG_ROAMING_DFS_CHANNEL_MAX ),
+
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+   REG_VARIABLE( CFG_WLAN_LOGGING_SUPPORT_NAME, WLAN_PARAM_Integer,
+                 hdd_config_t, wlanLoggingEnable,
+                 VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                 CFG_WLAN_LOGGING_SUPPORT_DEFAULT,
+                 CFG_WLAN_LOGGING_SUPPORT_DISABLE,
+                 CFG_WLAN_LOGGING_SUPPORT_ENABLE ),
+
+   REG_VARIABLE( CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME, WLAN_PARAM_Integer,
+                 hdd_config_t, wlanLoggingFEToConsole,
+                 VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                 CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT,
+                 CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE,
+                 CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE ),
+
+   REG_VARIABLE( CFG_WLAN_LOGGING_NUM_BUF_NAME, WLAN_PARAM_Integer,
+                 hdd_config_t, wlanLoggingNumBuf,
+                 VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                 CFG_WLAN_LOGGING_NUM_BUF_DEFAULT,
+                 CFG_WLAN_LOGGING_NUM_BUF_MIN,
+                 CFG_WLAN_LOGGING_NUM_BUF_MAX ),
+#endif //WLAN_LOGGING_SOCK_SVC_ENABLE
+
 };
 
 /*
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 80e3039..2e0442a 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -81,6 +81,7 @@
 #include <wlan_btc_svc.h>
 #include <wlan_hdd_cfg.h>
 #include <wlan_ptt_sock_svc.h>
+#include <wlan_logging_sock_svc.h>
 #include <wlan_hdd_wowl.h>
 #include <wlan_hdd_misc.h>
 #include <wlan_hdd_wext.h>
@@ -7494,6 +7495,13 @@
    nl_srv_exit();
 #endif /* WLAN_KD_READY_NOTIFIER */
 
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+   if(pHddCtx->cfg_ini->wlanLoggingEnable)
+   {
+       wlan_logging_sock_deactivate_svc();
+   }
+#endif
+
    /* Cancel the vote for XO Core ON. 
     * This is done here to ensure there is no race condition since MC, TX and WD threads have
     * exited at this point
@@ -8608,6 +8616,20 @@
    }
 #endif
 
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+   if(pHddCtx->cfg_ini && pHddCtx->cfg_ini->wlanLoggingEnable)
+   {
+      if(wlan_logging_sock_activate_svc(
+               pHddCtx->cfg_ini->wlanLoggingFEToConsole,
+               pHddCtx->cfg_ini->wlanLoggingNumBuf))
+      {
+         hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wlan_logging_sock_activate_svc"
+                                      " failed", __func__);
+         goto err_nl_srv;
+      }
+   }
+#endif
+
    hdd_register_mcast_bcast_filter(pHddCtx);
    if (VOS_STA_SAP_MODE != hdd_get_conparam())
    {
diff --git a/CORE/SVC/external/wlan_nlink_common.h b/CORE/SVC/external/wlan_nlink_common.h
index 8d773e0..ba1b3af 100644
--- a/CORE/SVC/external/wlan_nlink_common.h
+++ b/CORE/SVC/external/wlan_nlink_common.h
@@ -102,6 +102,7 @@
    ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01,// PTT Socket App
    ANI_NL_MSG_PTT   = ANI_NL_MSG_BASE + 0x07,// Quarky GUI
    WLAN_NL_MSG_BTC,
+   ANI_NL_MSG_LOG,
    ANI_NL_MSG_MAX  
 } tAniNlModTypes, tWlanNlModTypes;
 
diff --git a/CORE/SVC/inc/wlan_logging_sock_svc.h b/CORE/SVC/inc/wlan_logging_sock_svc.h
new file mode 100644
index 0000000..de70f28
--- /dev/null
+++ b/CORE/SVC/inc/wlan_logging_sock_svc.h
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+*
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+* This file was originally distributed by Qualcomm Atheros, Inc.
+* under proprietary terms before Copyright ownership was assigned
+* to the Linux Foundation.
+*/
+
+/******************************************************************************
+ * wlan_logging_sock_svc.h
+ *
+ ******************************************************************************/
+
+#ifndef WLAN_LOGGING_SOCK_SVC_H
+#define WLAN_LOGGING_SOCK_SVC_H
+
+#include <wlan_nlink_srv.h>
+#include <vos_status.h>
+#include <wlan_hdd_includes.h>
+#include <vos_trace.h>
+#include <wlan_nlink_common.h>
+
+int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf);
+int wlan_logging_sock_deactivate_svc(void);
+int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length);
+
+#endif /* WLAN_LOGGING_SOCK_SVC_H */
diff --git a/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
new file mode 100644
index 0000000..9ac2201
--- /dev/null
+++ b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
@@ -0,0 +1,555 @@
+/*
+* Copyright (c) 2014 The Linux Foundation. All rights reserved.
+*
+* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+*
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+* This file was originally distributed by Qualcomm Atheros, Inc.
+* under proprietary terms before Copyright ownership was assigned
+* to the Linux Foundation.
+*/
+
+/******************************************************************************
+ * wlan_logging_sock_svc.c
+ *
+ ******************************************************************************/
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+#include <wlan_nlink_srv.h>
+#include <vos_status.h>
+#include <vos_trace.h>
+#include <wlan_nlink_common.h>
+#include <wlan_logging_sock_svc.h>
+#include <vos_types.h>
+#include <vos_trace.h>
+#include <kthread.h>
+
+#define LOGGING_TRACE(level, args...) \
+		VOS_TRACE(VOS_MODULE_ID_HDD, level, ## args)
+
+/* Global variables */
+
+#define ANI_NL_MSG_LOG_TYPE 89
+#define INVALID_PID -1
+
+#define MAX_LOGMSG_LENGTH 4096
+#define SECONDS_IN_A_DAY (86400)
+
+struct log_msg {
+	struct list_head node;
+	unsigned int radio;
+	unsigned int index;
+	/* indicates the current filled log length in logbuf */
+	unsigned int filled_length;
+	/*
+	 * Buf to hold the log msg
+	 * tAniHdr + log
+	 */
+	char logbuf[MAX_LOGMSG_LENGTH];
+};
+
+struct wlan_logging {
+	/* Log Fatal and ERROR to console */
+	bool log_fe_to_console;
+	/* Number of buffers to be used for logging */
+	int num_buf;
+	/* Lock to synchronize access to shared logging resource */
+	spinlock_t spin_lock;
+	/* Holds the free node which can be used for filling logs */
+	struct list_head free_list;
+	/* Holds the filled nodes which needs to be indicated to APP */
+	struct list_head filled_list;
+	/* Wait queue for Logger thread */
+	wait_queue_head_t wait_queue;
+	/* Logger thread */
+	struct task_struct *thread;
+	/* Logging thread sets this variable on exit */
+	struct completion   shutdown_comp;
+	/* Indicates to logger thread to exit */
+	bool exit;
+	/* Holds number of dropped logs*/
+	unsigned int drop_count;
+	/* current logbuf to which the log will be filled to */
+	struct log_msg *pcur_node;
+};
+
+static struct wlan_logging gwlan_logging;
+static struct log_msg *gplog_msg;
+
+/* PID of the APP to log the message */
+static int gapp_pid = INVALID_PID;
+
+/* Utility function to send a netlink message to an application
+ * in user space
+ */
+static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio,
+				int src_mod, int pid)
+{
+	int err = -1;
+	int payload_len;
+	int tot_msg_len;
+	tAniNlHdr *wnl = NULL;
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	int wmsg_length = be16_to_cpu(wmsg->length);
+	static int nlmsg_seq;
+
+	if (radio < 0 || radio > ANI_MAX_RADIOS) {
+		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
+				"%s: invalid radio id [%d]",
+				__func__, radio);
+		return -EINVAL;
+	}
+
+	payload_len = wmsg_length + sizeof(wnl->radio);
+	tot_msg_len = NLMSG_SPACE(payload_len);
+	skb = dev_alloc_skb(tot_msg_len);
+	if (skb == NULL) {
+		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
+				"%s: dev_alloc_skb() failed for msg size[%d]",
+				__func__, tot_msg_len);
+		return -ENOMEM;
+	}
+	nlh = nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len,
+		NLM_F_REQUEST);
+	if (NULL == nlh) {
+		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
+				"%s: nlmsg_put() failed for msg size[%d]",
+				__func__, tot_msg_len);
+		kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	wnl = (tAniNlHdr *) nlh;
+	wnl->radio = radio;
+	memcpy(&wnl->wmsg, wmsg, wmsg_length);
+	LOGGING_TRACE(VOS_TRACE_LEVEL_INFO,
+			"%s: Sending Msg Type [0x%X] to pid[%d]\n",
+			__func__, be16_to_cpu(wmsg->type), pid);
+
+	err = nl_srv_ucast(skb, pid, MSG_DONTWAIT);
+	return err;
+}
+
+static void set_default_logtoapp_log_level(void)
+{
+	vos_trace_setValue(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_PE,  VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ALL,
+			VOS_TRUE);
+	vos_trace_setValue(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ALL, VOS_TRUE);
+}
+
+static void clear_default_logtoapp_log_level(void)
+{
+	int module;
+
+	for (module = 0; module < VOS_MODULE_ID_MAX; module++) {
+		vos_trace_setValue(module, VOS_TRACE_LEVEL_NONE,
+				VOS_FALSE);
+		vos_trace_setValue(module, VOS_TRACE_LEVEL_FATAL,
+				VOS_TRUE);
+		vos_trace_setValue(module, VOS_TRACE_LEVEL_ERROR,
+				VOS_TRUE);
+	}
+
+	vos_trace_setValue(VOS_MODULE_ID_RSV3, VOS_TRACE_LEVEL_NONE,
+			VOS_FALSE);
+	vos_trace_setValue(VOS_MODULE_ID_RSV4, VOS_TRACE_LEVEL_NONE,
+			VOS_FALSE);
+}
+
+/* Need to call this with spin_lock acquired */
+static int wlan_queue_logmsg_for_app(void)
+{
+	char *ptr;
+	int ret = 0;
+
+	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
+	ptr[gwlan_logging.pcur_node->filled_length] = '\0';
+
+	*(unsigned short *)(gwlan_logging.pcur_node->logbuf) =
+			ANI_NL_MSG_LOG_TYPE;
+	*(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) =
+			gwlan_logging.pcur_node->filled_length;
+	list_add_tail(&gwlan_logging.pcur_node->node,
+			&gwlan_logging.filled_list);
+
+	if (!list_empty(&gwlan_logging.free_list)) {
+		/* Get buffer from free list */
+		gwlan_logging.pcur_node =
+			(struct log_msg *)(gwlan_logging.free_list.next);
+		list_del_init(gwlan_logging.free_list.next);
+	} else if (!list_empty(&gwlan_logging.filled_list)) {
+		/* Get buffer from filled list */
+		/* This condition will drop the packet from being
+		 * indicated to app
+		 */
+		gwlan_logging.pcur_node =
+			(struct log_msg *)(gwlan_logging.filled_list.next);
+		pr_err("%s: drop_count = %u index = %d filled_length = %d\n",
+			__func__, ++gwlan_logging.drop_count,
+			gwlan_logging.pcur_node->index,
+			gwlan_logging.pcur_node->filled_length);
+		list_del_init(gwlan_logging.filled_list.next);
+		ret = 1;
+	}
+
+	/* Reset the current node values */
+	gwlan_logging.pcur_node->filled_length = 0;
+	return ret;
+}
+
+
+int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length)
+{
+	/* Add the current time stamp */
+	char *ptr;
+	char tbuf[50];
+	int tlen;
+	int total_log_len;
+	unsigned int *pfilled_length;
+	bool wake_up_thread = false;
+
+	struct timeval tv;
+
+	if (gapp_pid == INVALID_PID) {
+		/*
+		 * This is to make sure that we print the logs to kmsg console
+		 * when no logger app is running. This is also needed to
+		 * log the initial messages during loading of driver where even
+		 * if app is running it will not be able to
+		 * register with driver immediately and start logging all the
+		 * messages.
+		 */
+		pr_info("%s\n", to_be_sent);
+		return -EIO;
+	}
+
+	/* Format the Log time [Secondselapsedinaday.microseconds] */
+	do_gettimeofday(&tv);
+	tlen = snprintf(tbuf, sizeof(tbuf), "[%s][%5lu.%06lu] ", current->comm,
+			(unsigned long) (tv.tv_sec%SECONDS_IN_A_DAY),
+			tv.tv_usec);
+
+	/* 1+1 indicate '\n'+'\0' */
+	total_log_len = length + tlen + 1 + 1;
+
+	spin_lock_bh(&gwlan_logging.spin_lock);
+	pfilled_length = &gwlan_logging.pcur_node->filled_length;
+
+	 /* Check if we can accomodate more log into current node/buffer */
+	if ((MAX_LOGMSG_LENGTH - (*pfilled_length + sizeof(tAniNlHdr))) <
+			total_log_len) {
+		wake_up_thread = true;
+		wlan_queue_logmsg_for_app();
+		pfilled_length = &gwlan_logging.pcur_node->filled_length;
+	}
+
+	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
+
+	/* Assumption here is that we receive logs which is always less than
+	 * MAX_LOGMSG_LENGTH, where we can accomodate the
+	 *   tAniNlHdr + [context][timestamp] + log
+	 * VOS_ASSERT if we cannot accomodate the the complete log into
+	 * the available buffer.
+	 *
+	 * Continue and copy logs to the available length and discard the rest.
+	 */
+	if (MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len)) {
+		VOS_ASSERT(0);
+		total_log_len = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - 2;
+	}
+
+	memcpy(&ptr[*pfilled_length], tbuf, tlen);
+	memcpy(&ptr[*pfilled_length + tlen], to_be_sent,
+			min(length, (total_log_len - tlen)));
+	*pfilled_length += tlen + min(length, total_log_len - tlen);
+	ptr[*pfilled_length] = '\n';
+	*pfilled_length += 1;
+
+	spin_unlock_bh(&gwlan_logging.spin_lock);
+
+	/* Wakeup logger thread */
+	if (true == wake_up_thread)
+		wake_up_interruptible(&gwlan_logging.wait_queue);
+
+	if (gwlan_logging.log_fe_to_console
+		&& ((VOS_TRACE_LEVEL_FATAL == log_level)
+		|| (VOS_TRACE_LEVEL_ERROR == log_level))) {
+		pr_info("%s\n", to_be_sent);
+	}
+
+	return 0;
+}
+
+static int send_filled_buffers_to_user(void)
+{
+	int ret = -1;
+	struct log_msg *plog_msg;
+	int payload_len;
+	int tot_msg_len;
+	tAniNlHdr *wnl;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	static int nlmsg_seq;
+
+	while (!list_empty(&gwlan_logging.filled_list)
+		&& !gwlan_logging.exit) {
+
+		skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
+		if (skb == NULL) {
+			pr_err("%s: dev_alloc_skb() failed for msg size[%d]\n",
+				__func__, MAX_LOGMSG_LENGTH);
+			ret = -ENOMEM;
+			break;
+		}
+
+		spin_lock(&gwlan_logging.spin_lock);
+
+		plog_msg = (struct log_msg *)
+			(gwlan_logging.filled_list.next);
+		list_del_init(gwlan_logging.filled_list.next);
+		/* 4 extra bytes for the radio idx */
+		payload_len = plog_msg->filled_length +
+			sizeof(wnl->radio) + sizeof(tAniHdr);
+
+		tot_msg_len = NLMSG_SPACE(payload_len);
+		nlh = nlmsg_put(skb, gapp_pid, nlmsg_seq++,
+				ANI_NL_MSG_LOG, payload_len,
+				NLM_F_REQUEST);
+		if (NULL == nlh) {
+			list_add_tail(&plog_msg->node,
+				&gwlan_logging.free_list);
+			spin_unlock(&gwlan_logging.spin_lock);
+			pr_err("%s: drop_count = %u\n", __func__,
+				++gwlan_logging.drop_count);
+			pr_err("%s: nlmsg_put() failed for msg size[%d]\n",
+				__func__, tot_msg_len);
+			dev_kfree_skb(skb);
+			skb = NULL;
+			ret = -EINVAL;
+			continue;
+		}
+		spin_unlock(&gwlan_logging.spin_lock);
+
+		wnl = (tAniNlHdr *) nlh;
+		wnl->radio = plog_msg->radio;
+		memcpy(&wnl->wmsg, plog_msg->logbuf,
+				plog_msg->filled_length +
+				sizeof(tAniHdr));
+
+		spin_lock(&gwlan_logging.spin_lock);
+		list_add_tail(&plog_msg->node,
+				&gwlan_logging.free_list);
+		spin_unlock(&gwlan_logging.spin_lock);
+
+		ret = nl_srv_ucast(skb, gapp_pid, 0);
+		if (ret < 0) {
+			pr_err("%s: Send Failed %d drop_count = %u\n",
+				__func__, ret, ++gwlan_logging.drop_count);
+			skb = NULL;
+			gapp_pid = INVALID_PID;
+			clear_default_logtoapp_log_level();
+		} else {
+			skb = NULL;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * wlan_logging_thread() - The WLAN Logger thread
+ * @Arg - pointer to the HDD context
+ *
+ * This thread logs log message to App registered for the logs.
+ */
+static int wlan_logging_thread(void *Arg)
+{
+	int ret_wait_status = 0;
+
+	set_user_nice(current, -2);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+	daemonize("wlan_logging_thread");
+#endif
+
+	while (!gwlan_logging.exit) {
+		ret_wait_status = wait_event_interruptible(
+		    gwlan_logging.wait_queue,
+		    (!list_empty(&gwlan_logging.filled_list)
+		  || gwlan_logging.exit));
+
+		if (ret_wait_status == -ERESTARTSYS) {
+			pr_err("%s: wait_event_interruptible returned -ERESTARTSYS",
+				__func__);
+			break;
+		}
+
+		if (gwlan_logging.exit) {
+			pr_err("%s: Exiting the thread\n", __func__);
+			break;
+		}
+
+		if (INVALID_PID == gapp_pid) {
+			pr_err("%s: Invalid PID\n", __func__);
+			continue;
+		}
+
+		send_filled_buffers_to_user();
+	}
+
+	complete_and_exit(&gwlan_logging.shutdown_comp, 0);
+
+	pr_info("%s: Terminating\n", __func__);
+
+	return 0;
+}
+
+/*
+ * Process all the Netlink messages from Logger Socket app in user space
+ */
+static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb)
+{
+	tAniNlHdr *wnl;
+	int radio;
+	int type;
+	int ret;
+
+	wnl = (tAniNlHdr *) skb->data;
+	radio = wnl->radio;
+	type = wnl->nlh.nlmsg_type;
+
+	if (radio < 0 || radio > ANI_MAX_RADIOS) {
+		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
+				"%s: invalid radio id [%d]\n",
+				__func__, radio);
+		return -EINVAL;
+	}
+
+	if (gapp_pid != INVALID_PID) {
+		if (wnl->nlh.nlmsg_pid > gapp_pid) {
+			gapp_pid = wnl->nlh.nlmsg_pid;
+		}
+
+		spin_lock_bh(&gwlan_logging.spin_lock);
+		if (gwlan_logging.pcur_node->filled_length) {
+			wlan_queue_logmsg_for_app();
+		}
+		spin_unlock_bh(&gwlan_logging.spin_lock);
+		wake_up_interruptible(&gwlan_logging.wait_queue);
+	} else {
+		/* This is to set the default levels (WLAN logging
+		 * default values not the VOS trace default) when
+		 * logger app is registered for the first time.
+		 */
+		gapp_pid = wnl->nlh.nlmsg_pid;
+		set_default_logtoapp_log_level();
+	}
+
+	ret = wlan_send_sock_msg_to_app(&wnl->wmsg, 0,
+			ANI_NL_MSG_LOG, wnl->nlh.nlmsg_pid);
+	if (ret < 0) {
+		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
+				"wlan_send_sock_msg_to_app: failed");
+	}
+
+	return ret;
+}
+
+int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf)
+{
+	int i = 0;
+	unsigned long irq_flag;
+
+	pr_info("%s: Initalizing FEConsoleLog = %d NumBuff = %d\n",
+			__func__, log_fe_to_console, num_buf);
+
+	gapp_pid = INVALID_PID;
+
+	gplog_msg = (struct log_msg *) vos_mem_malloc(
+			num_buf * sizeof(struct log_msg));
+	if (!gplog_msg) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	vos_mem_zero(gplog_msg, (num_buf * sizeof(struct log_msg)));
+
+	gwlan_logging.log_fe_to_console = !!log_fe_to_console;
+	gwlan_logging.num_buf = num_buf;
+
+	spin_lock_init(&gwlan_logging.spin_lock);
+
+	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
+	INIT_LIST_HEAD(&gwlan_logging.free_list);
+	INIT_LIST_HEAD(&gwlan_logging.filled_list);
+
+	for (i = 0; i < num_buf; i++) {
+		list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
+		gplog_msg[i].index = i;
+	}
+	gwlan_logging.pcur_node = (struct log_msg *)
+		(gwlan_logging.free_list.next);
+	list_del_init(gwlan_logging.free_list.next);
+	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
+
+	init_waitqueue_head(&gwlan_logging.wait_queue);
+	gwlan_logging.exit = false;
+	init_completion(&gwlan_logging.shutdown_comp);
+	gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
+					"wlan_logging_thread");
+	if (IS_ERR(gwlan_logging.thread)) {
+		pr_err("%s: Could not Create LogMsg Thread Controller",
+		       __func__);
+		vos_mem_free(gplog_msg);
+		return -ENOMEM;
+	}
+	wake_up_process(gwlan_logging.thread);
+
+	nl_srv_register(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg);
+
+	pr_info("%s: Activated wlan_logging svc\n", __func__);
+	return 0;
+}
+
+int wlan_logging_sock_deactivate_svc(void)
+{
+
+	nl_srv_unregister(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg);
+	clear_default_logtoapp_log_level();
+	gapp_pid = INVALID_PID;
+
+	gwlan_logging.exit = true;
+	INIT_COMPLETION(gwlan_logging.shutdown_comp);
+	wake_up_interruptible(&gwlan_logging.wait_queue);
+	wait_for_completion_interruptible(&gwlan_logging.shutdown_comp);
+
+	vos_mem_free(gplog_msg);
+
+	pr_info("%s: Deactivate wlan_logging svc\n", __func__);
+
+	return 0;
+}
+
+#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
diff --git a/CORE/VOSS/inc/vos_types.h b/CORE/VOSS/inc/vos_types.h
index 25acdcb..861377d 100644
--- a/CORE/VOSS/inc/vos_types.h
+++ b/CORE/VOSS/inc/vos_types.h
@@ -106,6 +106,8 @@
    VOS_MODULE_ID_TL         = 1,
    VOS_MODULE_ID_WDI        = 2,
    // 3 & 4 are unused for historical purposes
+   VOS_MODULE_ID_RSV3       = 3,
+   VOS_MODULE_ID_RSV4       = 4,
    VOS_MODULE_ID_HDD        = 5,
    VOS_MODULE_ID_SME        = 6,
    VOS_MODULE_ID_PE         = 7,
diff --git a/CORE/VOSS/src/vos_trace.c b/CORE/VOSS/src/vos_trace.c
index cd51a75..7f927f9 100644
--- a/CORE/VOSS/src/vos_trace.c
+++ b/CORE/VOSS/src/vos_trace.c
@@ -64,6 +64,7 @@
   ------------------------------------------------------------------------*/
 #include <vos_trace.h>
 #include <aniGlobal.h>
+#include <wlan_logging_sock_svc.h>
 /*--------------------------------------------------------------------------
   Preprocessor definitions and constants
   ------------------------------------------------------------------------*/
@@ -100,7 +101,7 @@
 {
    [VOS_MODULE_ID_BAP]        = { VOS_DEFAULT_TRACE_LEVEL, "BAP" },
    [VOS_MODULE_ID_TL]         = { VOS_DEFAULT_TRACE_LEVEL, "TL " },
-   [VOS_MODULE_ID_WDI]        = { VOS_DEFAULT_TRACE_LEVEL, "WDI"},
+   [VOS_MODULE_ID_WDI]        = { VOS_DEFAULT_TRACE_LEVEL, "WDI" },
    [VOS_MODULE_ID_HDD]        = { VOS_DEFAULT_TRACE_LEVEL, "HDD" },
    [VOS_MODULE_ID_SME]        = { VOS_DEFAULT_TRACE_LEVEL, "SME" },
    [VOS_MODULE_ID_PE]         = { VOS_DEFAULT_TRACE_LEVEL, "PE " },
@@ -348,7 +349,12 @@
          kmsgwconnBuffWrite(strBuffer);
          spin_unlock_irqrestore (&gVosSpinLock, irq_flag);
 #endif
+
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+         wlan_log_to_user(level, (char *)strBuffer, strlen(strBuffer));
+#else
          pr_err("%s\n", strBuffer);
+#endif
       }
      va_end(val);
    }
diff --git a/Kbuild b/Kbuild
index 72129ce..ff5e229 100644
--- a/Kbuild
+++ b/Kbuild
@@ -328,9 +328,13 @@
 PTT_SRC_DIR :=	$(SVC_SRC_DIR)/ptt
 PTT_OBJS :=	$(PTT_SRC_DIR)/wlan_ptt_sock_svc.o
 
+WLAN_LOGGING_SRC_DIR := $(SVC_SRC_DIR)/logging
+WLAN_LOGGING_OBJS := $(WLAN_LOGGING_SRC_DIR)/wlan_logging_sock_svc.o
+
 SVC_OBJS :=	$(BTC_OBJS) \
 		$(NLINK_OBJS) \
-		$(PTT_OBJS)
+		$(PTT_OBJS) \
+                $(WLAN_LOGGING_OBJS)
 
 ############ SYS ############
 SYS_DIR :=	CORE/SYS
@@ -547,7 +551,8 @@
                 -DFEATURE_WLAN_PAL_MEM_DISABLE \
                 -DFEATURE_WLAN_CH144 \
                 -DWLAN_BUG_ON_SKB_ERROR \
-                -DWLAN_DXE_LOW_RESOURCE_TIMER
+                -DWLAN_DXE_LOW_RESOURCE_TIMER \
+                -DWLAN_LOGGING_SOCK_SVC_ENABLE
 
 ifneq ($(CONFIG_PRONTO_WLAN),)
 CDEFINES += -DWCN_PRONTO