wigig: Adding debug tools

Adding the debug tools package for 11ad

Change-Id: I171d7534614ec8941e0b48bb01d757ccd3be8960
Signed-off-by: Vadim Iosevich <vadimi@codeaurora.org>
diff --git a/debug-tools/remoteserver/Android.mk b/debug-tools/remoteserver/Android.mk
new file mode 100644
index 0000000..9a215a8
--- /dev/null
+++ b/debug-tools/remoteserver/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := wigig_remoteserver
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPPFLAGS := -Wall -lpthread -fexceptions
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/../lib/WlctPciAcss \
+	$(LOCAL_PATH)/../lib/inc \
+	$(LOCAL_PATH)/../lib/utils
+
+LOCAL_SHARED_LIBRARIES := \
+	libwigig_utils \
+	libwigig_pciaccess
+
+LOCAL_SRC_FILES := $(shell find $(LOCAL_PATH) -name '*.cpp' | sed s:^$(LOCAL_PATH)::g )
+LOCAL_SRC_FILES += parser.l
+
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/debug-tools/remoteserver/Makefile b/debug-tools/remoteserver/Makefile
new file mode 100644
index 0000000..e9bef43
--- /dev/null
+++ b/debug-tools/remoteserver/Makefile
@@ -0,0 +1,62 @@
+-include $(TOPDIR)/rules.mk
+
+CFLAGS := -fPIE -Wall -g -MMD -Wno-unused-function
+LDFLAGS := -pie -fPIE -pthread -lwigig_pciaccess -lwigig_utils
+
+ifneq ($(CONFIG_TARGET_ipq)$(CONFIG_TARGET_ipq806x),)
+is_ipq806x = 1
+endif
+
+ifeq ($(is_ipq806x), 1)
+ifneq ($(strip $(TOOLPREFIX)),)
+CROSS:=$(TOOLPREFIX)
+endif
+endif
+
+CC := $(CROSS)gcc
+CXX := $(CROSS)g++
+
+.DEFAULT_GOAL = all
+PROG = wigig_remoteserver
+
+INCLUDES = -I ../lib/WlctPciAcss \
+           -I ../lib/inc \
+           -I ../lib/utils \
+
+LIBS = -L../lib/WlctPciAcss \
+       -L../lib/utils \
+
+all: $(PROG)
+
+CPP_FILES = $(shell find . -type f -name '*.cpp')
+C_FILES = $(shell find . -type f -name '*.c')
+LEX_FILES = $(shell find . -type f -name '*.l')
+
+
+GENERATED_C_FILES=$(LEX_FILES:.l=.c)
+OBJ_FILES=  $(CPP_FILES:.cpp=.o)
+OBJ_FILES += $(C_FILES:.c=.o)
+OBJ_FILES += $(GENERATED_C_FILES:.c=.o)
+
+.PRECIOUS: $(GENERATED_C_FILES)
+
+$(PROG): $(OBJ_FILES)
+	$(CXX) -o $@ $^ $(LIBS) $(LDFLAGS)
+
+%.o : %.c
+	$(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $<
+
+%.o : %.cpp
+	$(CXX) $(CFLAGS) $(INCLUDES) -o $@ -c $<
+
+%.c : %.l
+	flex -o $@ $<
+
+
+
+clean:
+	rm -rf $(PROG) $(GENERATED_C_FILES)
+	find . -type f \( -name "*.d" -o -name "*.o" \) -delete
+
+
+-include $(OBJ_FILES:%.o=%.d)
diff --git a/debug-tools/remoteserver/cmdiface.cpp b/debug-tools/remoteserver/cmdiface.cpp
new file mode 100644
index 0000000..9c03471
--- /dev/null
+++ b/debug-tools/remoteserver/cmdiface.cpp
@@ -0,0 +1,645 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+
+#include "cmdiface.h"
+#include "parser.h"
+#include "debug.h"
+#include "WlctPciAcss.h"
+#include "pmc_file.h"
+#include "udp_server.h"
+
+
+struct open_interface_s *CmdIface::open_interfaces = NULL;
+pthread_mutex_t CmdIface::open_interfaces_mutex = PTHREAD_MUTEX_INITIALIZER;
+int CmdIface::interface_id = 0;
+
+/*
+*/
+void *CmdIface::get_interface(const char *name)
+{
+    struct open_interface_s *s = open_interfaces;
+    LOG_DEBUG << "Looking for interface: " << name << std::endl;
+
+    while(s != NULL)
+    {
+        LOG_VERBOSE << "Checking interface for match: " << s->interface << std::endl;
+        if(0 == strncasecmp(name, s->interface, MAX_INTERFACE_NAME))
+        {
+            LOG_VERBOSE << "Match found" << std::endl;
+            return s->handler;
+        }
+        s = s->next;
+    }
+
+    return NULL;
+}
+
+/*
+*/
+void *CmdIface::add_interface(const char *name, void *handler)
+{
+    LOG_DEBUG << "Adding interface: " << name << std::endl;
+
+    void *h = get_interface(name);
+    if(h != NULL)
+    {
+        LOG_DEBUG << "The interface is already open" << std::endl;
+        return h;			// Interface already opened
+    }
+
+    // Add interface to the list
+    struct open_interface_s *s = new struct open_interface_s;
+    if(s == NULL)
+    {
+        return NULL;
+    }
+
+    snprintf(s->interface, MAX_INTERFACE_NAME, "%s", name);
+    s->handler = handler;
+    pthread_mutex_lock(&open_interfaces_mutex);
+    s->next = open_interfaces;
+    open_interfaces = s;
+    pthread_mutex_unlock(&open_interfaces_mutex);
+
+    return handler;
+}
+
+/*
+*/
+void CmdIface::del_interface(void *handler)
+{
+    LOG_DEBUG << "Deleting interfaces by handler" << std::endl;
+
+    struct open_interface_s *s = open_interfaces;
+    struct open_interface_s *prev = NULL;
+
+    while(s != NULL) {
+        if(handler == s->handler)  {
+            // Remove the interface from the list
+            pthread_mutex_lock(&open_interfaces_mutex);
+            if(prev != NULL)
+                prev->next = s->next;
+            else
+                open_interfaces = s->next;
+            pthread_mutex_unlock(&open_interfaces_mutex);
+            delete s;
+        }
+        prev = s;
+        s = s->next;
+    }
+}
+
+/*
+*/
+int CmdIface::cmd_get_interfaces()
+{
+    INTERFACE_LIST interfaces;
+    int num_interfaces;
+    int rc;
+
+    LOG_DEBUG << "Getting active WIGIG card interfaces" << std::endl;
+
+    rc = GetInterfaces(&interfaces, &num_interfaces);
+    LOG_DEBUG << "Found " << num_interfaces << " interfaces" << std::endl;
+
+    std::ostringstream replyBuilder;
+
+    if(rc == 0)
+    {
+        for(int i=0; i < num_interfaces; i++)
+        {
+            replyBuilder << interfaces.list[i].ifName << ' ';
+        }
+    }
+
+    replyBuilder << "\r\n";
+    m_Reply = replyBuilder.str();
+
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_open_interface(char *interface)
+{
+    void *handler = NULL;
+    int rc=0;
+
+    LOG_DEBUG << "Opening an interface: " << interface << std::endl;
+
+    if( strstr(interface, "SPARROW")|| strstr(interface, "sparrow")){
+	rc = CreateDeviceAccessHandler(interface, MST_SPARROW, &handler);
+    }
+    else if(strstr(interface, "MARLON") || strstr(interface, "marlon")){
+	rc = CreateDeviceAccessHandler(interface, MST_MARLON, &handler);
+    }
+    else{
+        m_Reply = "0xDEAD\r\n";
+    }
+    if(rc != 0)
+        m_Reply = "0xDEADDEAD\r\n";
+    else {
+
+        std::ostringstream replyBuilder;
+
+        replyBuilder << interface << '_' << interface_id;
+        add_interface(replyBuilder.str().c_str(), handler);
+        replyBuilder << "\r\n";
+        m_Reply = replyBuilder.str();
+        interface_id++;                     // TODO: Should be protected by a mutex? I didn't see it's being used in the application
+    }
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_close_interface(char *interface)
+{
+    LOG_DEBUG << "Closing interface: " << interface << std::endl;
+
+    void *handler = get_interface(interface);
+
+    if(handler != NULL)
+    {
+        del_interface(handler);
+        interface_id--;
+    }
+    else
+    {
+        LOG_WARNING << "Interface " << interface << " wasn't opened" << std::endl;
+    }
+
+    m_Reply = "0\r\n";
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_r(char *interface, unsigned int address)
+{
+    unsigned int val = 0xDEADDEAD;
+    void *handler = get_interface(interface);
+
+    std::ostringstream replyBuilder;
+    if(handler == NULL)
+    {
+        m_Reply = "0xDEADDEAD";
+    }
+    else
+    {
+        int rc = WlctAccssRead(handler, address, val);
+        (void)rc;
+        replyBuilder << val;
+    }
+
+    replyBuilder << "\r\n";
+    m_Reply = replyBuilder.str();
+
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_w(char *interface, unsigned int address, unsigned int data)
+{
+    int rc;
+    void *handler = get_interface(interface);
+
+    std::ostringstream replyBuilder;
+
+    if(handler == NULL)
+    {
+        replyBuilder << "0xDEADDEAD";
+    }
+    else
+    {
+        rc = WlctAccssWrite(handler, address, data);
+        if(rc == 0)
+            replyBuilder << "0";
+        else
+            replyBuilder << "ERROR";
+    }
+
+    replyBuilder << "\r\n";
+    m_Reply = replyBuilder.str();
+
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_alloc_pmc(char *interface, unsigned int desc_size, unsigned int desc_num)
+{
+    int rc;
+    LOG_DEBUG << "Allocating PMC descriptors:"
+              << " interface = " << interface
+              << " size = " << desc_size
+              << " number = " << desc_num
+              << std::endl;
+
+    std::ostringstream replyBuilder;
+
+    void *handler = get_interface(interface);
+    if(handler == NULL)
+    {
+        LOG_DEBUG << "Cannot get handler for interface " << interface << std::endl;
+        replyBuilder << "0xDEADDEAD";
+    }
+    else
+    {
+	rc = WlctAccssAllocPmc(handler, desc_size, desc_num);
+
+	if(rc == 0)
+        {
+            LOG_DEBUG << "Successfully allocated PMC descriptors" << std::endl;
+            replyBuilder << "0";
+        }
+        else
+        {
+            LOG_ERROR << "Error allocating PMC descriptors" << std::endl;
+            replyBuilder << "ERROR";
+        }
+    }
+
+    replyBuilder << "\r\n";
+    m_Reply = replyBuilder.str();
+
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_read_pmc(char *interface, unsigned int ref_number)
+{
+    LOG_DEBUG << "Reading PMC data:"
+              << " interface = " << interface
+              << " reference number = " << ref_number
+              << std::endl;
+
+    void *handler = get_interface(interface);
+
+    if(handler == NULL)
+    {
+        LOG_ERROR << "No interface found: " << interface << std::endl;
+        m_Reply = "0xDEADDEAD\r\n";
+        return 0;
+    }
+
+    PmcFile pmcFile(ref_number);
+    PmcFileWriter pmcFileWriter(pmcFile);
+    bool status = pmcFileWriter.WriteFile();
+    if (false == status)
+    {
+        LOG_ERROR << "Error creating PMC data file" << std::endl;
+        m_Reply = "0xDEADDEAD\r\n";
+        return 0;
+    }
+
+    // Reply with file size
+    size_t pmcFileSize = pmcFileWriter.GetFileSize();
+
+    std::ostringstream replyBuilder;
+    replyBuilder << pmcFileSize << "\r\n";
+    m_Reply = replyBuilder.str();
+
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_read_pmc_file(unsigned int ref_number)
+{
+    LOG_DEBUG << "Reading PMC File #" << ref_number << std::endl;
+
+    PmcFile pmcFile(ref_number);
+
+    if (NULL == pmcFile.GetFileName())
+    {
+        LOG_ERROR << "Error getting PMC data file #" << ref_number << std::endl;
+        m_Reply = "0xDEADDEAD\r\n";
+        return 0;
+    }
+
+    // Note: No \r\n is needed here, the file name won't be sent to a clientls
+    m_Reply = pmcFile.GetFileName();
+	replyType = REPLY_TYPE_FILE;
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_rb(char *interface, unsigned int address, unsigned int num_regs)
+{
+    void *handler = get_interface(interface);
+
+    if((handler == NULL) || (num_regs > MAX_REGS_LEN))
+    {
+        m_Reply = "0xDEADDEAD\r\n";
+        return 0;
+    }
+
+    unsigned int *val = new unsigned int[num_regs];
+    int rc = readBlock(handler, address, num_regs*sizeof(unsigned int), (char*)val);
+
+    if (rc == 0)
+    {
+        std::ostringstream replyBuilder;
+        replyBuilder << std::hex;
+
+        for(unsigned int i=0; i < num_regs; i++)
+        {
+            replyBuilder << "0x" << val[i];
+            if(i < num_regs -1 )
+            {
+                replyBuilder << ' ';
+            }
+        }
+
+        replyBuilder << "\r\n";
+        m_Reply = replyBuilder.str();
+    }
+    else
+    {
+        m_Reply = "0xDEADDEAD\r\n";
+    }
+
+    delete[] val;
+    return 0;
+}
+
+/*
+*/
+int CmdIface::cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block)
+{
+    void *handler = get_interface(interface);
+
+    if((handler == NULL) || (len > MAX_REGS_LEN))
+    {
+        m_Reply = "0xDEADDEAD\r\n";
+        return 0;
+    }
+
+    LOG_VERBOSE << "current WB is " << block << " length is " << len << std::endl;
+    int rc = writeBlock(handler, address, len, block);
+    if(rc == 0)
+    {
+        m_Reply = "0\r\n";
+    }
+    else
+    {
+        m_Reply = "ERROR\r\n";
+    }
+
+    return 0;
+}
+
+
+int CmdIface::cmd_interface_reset(char *interface)
+{
+    void *handler = get_interface(interface);
+    if(handler == NULL)
+    {
+        m_Reply = "0xDEADDEAD\r\n";
+	}
+    else
+	{
+        int rc = InterfaceReset(handler);
+        if(rc == 0)
+		{
+            m_Reply = "OK\r\n";
+		}
+        else
+		{
+            m_Reply = "0xDEADDEAD\r\n";
+		}
+    }
+
+    return 0;
+}
+
+
+int CmdIface::cmd_sw_reset(char *interface)
+{
+	void *handler = get_interface(interface);
+	if (handler == NULL)
+	{
+		m_Reply = "0xDEADDEAD\r\n";
+	}
+	else
+	{
+		int rc = SwReset(handler);
+		if (rc == 0)
+		{
+			m_Reply = "OK\r\n";
+		}
+		else
+		{
+			m_Reply = "0xDEADDEAD\r\n";
+		}
+	}
+
+	return 0;
+}
+
+int CmdIface::cmd_set_host_alias(char* alias)
+{
+	std::ofstream fd(UdpServer::host_details_file_name.c_str());
+	if (!fd.is_open())
+	{
+		m_Reply = "FAIL : Coudn't set the new alias: failed to open the configuration file";
+		LOG_VERBOSE << m_Reply << std::endl;
+		return -1;
+	}
+	fd << alias;
+	if (fd.bad())
+	{
+		m_Reply = "FAIL : Coudn't set the new alias: failed to write the new alias to the configuration file";
+		LOG_VERBOSE << m_Reply << std::endl;
+		fd.close();
+		return -2;
+	}
+	fd.close();
+
+	UdpServer::SetHostAlias(alias);
+	UdpServer::SendAll(UdpServer::GetHostDetails());
+	return 0;
+}
+
+
+/*
+ Execute command received from a remote client
+ The command of length 'len' is in 'buf'. 'outlen' has
+ the max output buffer size.
+ On return, 'outbuf' may have a reply to be sent to the client,
+ 'outlen' should have the reply length or 0 if no reply required.
+ Returns KEEPALIVE_OK if ok, KEEPALIVE_CLOSE to close the connection, KEEPALIVE_SHUTDOWN to shutdown the server (debug mode)
+*/
+int CmdIface::do_command(const char *buf, int len)
+{
+    servercmd_t s;
+    int result = KEEPALIVE_OK;
+    replyType = REPLY_TYPE_BUFFER;
+
+    ((char*)buf)[len] = '\0';	// Make a zero-terminated string
+
+    // Parse the command
+    parse_line(buf, &s);
+    dump_parser(&s);
+
+    // Check for the parser error. Note, not all the commands in the original protocol report about errors. so we check the error
+    // for selected commands only TODO: verify the commands list reporting the error
+    if(s.cmd == CMD_OPEN_INTERFACE || s.cmd == CMD_R || s.cmd == CMD_RB || s.cmd == CMD_W || s.cmd == CMD_WB)
+    {
+        if(s.error != 0)
+        {
+            LOG_ERROR << "Command line parsing error" << std::endl;
+            m_Reply = "0xDEADDEAD\r\n";    // TODO: or should it be "dmtools_error"??
+            return result;
+        }
+    }
+
+    switch(s.cmd)
+    {
+    case CMD_GET_INTERFACES:
+        cmd_get_interfaces();
+        break;
+    case CMD_OPEN_INTERFACE:
+        cmd_open_interface(s.interface);
+        break;
+    case CMD_CLOSE_INTERFACE:
+        cmd_close_interface(s.interface);
+        break;
+    case CMD_R:
+        cmd_r(s.interface, s.address);
+        break;
+    case CMD_RB:
+        cmd_rb(s.interface, s.address, s.value);
+        break;
+    case CMD_W:
+        cmd_w(s.interface, s.address, s.value);
+        break;
+    case CMD_WB:
+        // hexdata_len is in dwords, cmd_wb works in bytes. (hence * 4)
+        cmd_wb(s.interface, s.address, s.hexdata_len * 4, (const char*)s.hexdata);
+        break;
+    case CMD_INTERFACE_RESET:
+        cmd_interface_reset(s.interface);
+        break;
+    case CMD_SW_RESET:
+	cmd_sw_reset(s.interface);
+	break;
+    case CMD_EXIT:
+        result = KEEPALIVE_CLOSE;   // Terminate the connection
+        break;
+    case CMD_ALLOC_PMC:
+        cmd_alloc_pmc(s.interface, s.address, s.value);
+        break;
+    case CMD_READ_PMC:
+        cmd_read_pmc(s.interface, s.address);
+        break;
+    case CMD_READ_PMC_FILE:
+        cmd_read_pmc_file(s.address);
+        break;
+	case CMD_SET_HOST_ALIAS:
+		cmd_set_host_alias(s.interface);
+		break;
+    case CMD_COMMAND_UNKNOWN:
+    default:
+        m_Reply = "dmtools_error\r\n";
+
+    }
+    return result;
+}
+
+/*
+ Dump the parser structure, for debugging only
+*/
+void CmdIface::dump_parser(servercmd_t *s)
+{
+    if(s->error)
+    {
+        LOG_ERROR << "Parser error in comand parsing."
+            << " Error: " << s->error
+            << " Message: " << parser_error_to_string(s->error)
+            << std::endl;
+
+        return;
+    }
+
+    LOG_VERBOSE << "Parsed Command: " << command_to_string(s->cmd)
+                << " Interface: " <<  s->interface  << std::endl;
+
+    if(s->address != (unsigned int)-1)
+    {
+        LOG_VERBOSE << "Address: " << s->address << std::endl;
+    }
+    if(s->value != (unsigned int)-1)
+    {
+        LOG_VERBOSE << "Value: " << s->value << std::endl;
+    }
+    if(s->hexdata_len)
+    {
+        for(int i=0; i < s->hexdata_len && i < MAX_REGS_LEN; i++)
+            LOG_VERBOSE << std::hex << "0x" << s->hexdata[i] << std::dec << std::endl;
+    }
+}
+
+/*
+*/
+int CmdIface::get_reply_len()
+{
+    return m_Reply.size();
+}
+
+/*
+*/
+void CmdIface::to_lower(char* string)
+{
+    for (int i = 0; string[i]; i++)
+    {
+	string[i] = tolower(string[i]);
+    }
+
+    return;
+}
+
+/*
+*/
+CmdIface::CmdIface()
+    : replyType(REPLY_TYPE_BUFFER)
+{
+}
diff --git a/debug-tools/remoteserver/cmdiface.h b/debug-tools/remoteserver/cmdiface.h
new file mode 100644
index 0000000..a58864e
--- /dev/null
+++ b/debug-tools/remoteserver/cmdiface.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __interface_h
+#define __interface_h
+
+#include <pthread.h>
+#include <string>
+
+extern "C"
+{
+#include "parser.h"
+}
+
+struct open_interface_s {
+    char interface[MAX_INTERFACE_NAME];
+    void *handler;
+    struct open_interface_s *next;
+};
+
+#define KEEPALIVE_OK    0    // keep the connection
+#define KEEPALIVE_CLOSE 1    // close the connection
+#define KEEPALIVE_SHUTDOWN 2 // close the connection and shutdown the server. For debugging only, remove from the production
+
+
+// Max buffer size for a command and a reply. We should consider the longest command/data sequence to fit in a buffer.
+// rb reading 1024 (MAX_REGS_LEN) registers: rb HHHHHHHH HHHH 1024*(0xHHHHHHHH) = 17 + 1024*10 = 10257 bytes
+// wb writing 1024 (MAX_REGS_LEN) hex values: wb HHHHHHHH "1024*HH" = 14+1024*2 = 2062 bytes
+#define MAX_INPUT_BUF (11*MAX_REGS_LEN)
+
+// The reply data may be generated in several ways, the data is expected to be obtained according to this type
+enum REPLY_TYPE
+{
+    REPLY_TYPE_NONE,
+    REPLY_TYPE_BUFFER,
+    REPLY_TYPE_FILE
+};
+
+
+class CmdIface
+{
+public:
+    CmdIface();
+
+    int do_command(const char *buf, int len);
+    const char *get_reply() const { return m_Reply.c_str(); };
+    int   get_reply_len();
+    REPLY_TYPE get_reply_type() const { return replyType; }
+
+private:
+
+    static struct open_interface_s *open_interfaces;
+    static pthread_mutex_t open_interfaces_mutex;
+    static int interface_id;                        // Interface id counter returned in open_interface
+
+    void *get_interface(const char *name);
+    void *add_interface(const char *name, void *handler);
+    void del_interface(void *handler);
+
+    int cmd_get_interfaces();
+    int cmd_open_interface(char *interface);
+    int cmd_close_interface(char *interface);
+    int cmd_r(char *interface, unsigned int address);
+    int cmd_rb(char *interface, unsigned int address, unsigned int num_regs);
+    int cmd_w(char *interface, unsigned int address, unsigned int data);
+    int cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block);
+    int cmd_interface_reset(char *interface);
+    int cmd_sw_reset(char *interface);
+    int cmd_alloc_pmc(char *interface, unsigned int desc_size, unsigned int desc_num);
+    int cmd_read_pmc(char *interface, unsigned int ref_number);
+    int cmd_read_pmc_file(unsigned int ref_number);
+    void dump_parser(servercmd_t *s);
+    int cmd_set_host_alias(char *alias);
+
+    void to_lower(char* string);
+
+    REPLY_TYPE replyType;
+    std::string m_Reply;
+
+};
+
+#endif // interface_h
+
diff --git a/debug-tools/remoteserver/debug.cpp b/debug-tools/remoteserver/debug.cpp
new file mode 100644
index 0000000..7a3502d
--- /dev/null
+++ b/debug-tools/remoteserver/debug.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "debug.h"
+#include <stdio.h>
+
+// *************************************************************************************************
+
+LogConfig g_LogConfig(LOG_SEV_INFO, false);
+
+// *************************************************************************************************
+
+LogConfig::LogConfig(LogSeverity maxSeverity, bool bPrintLocation)
+    : m_MaxSeverity(maxSeverity), m_PrintLocation(bPrintLocation)
+{
+}
+
+void LogConfig::SetMaxSeverity(int traceLevel)
+{
+    if (traceLevel > LOG_SEV_VERBOSE)
+    {
+        fprintf(stderr, "Invalid trace level, setting %d\n", LOG_SEV_VERBOSE);
+        m_MaxSeverity = LOG_SEV_VERBOSE;
+    }
+    else
+    {
+        m_MaxSeverity = static_cast<LogSeverity>(traceLevel);
+        fprintf(stdout, "Setting trace level to %d\n", m_MaxSeverity);
+    }
+}
+
+// *************************************************************************************************
+
+const char* LogMsgPrefix::SeverityToString(LogSeverity sev)
+{
+    static const char* const pSeverityToString[] = { "ERR", "WRN", "INF", "DBG", "VRB" };
+
+    size_t index = static_cast<size_t>(sev);
+    if (index >= sizeof(pSeverityToString)/sizeof(pSeverityToString[0]))
+    {
+        return "---";
+    }
+
+    return pSeverityToString[index];
+}
+
+std::ostream& operator<<(std::ostream& os, const LogMsgPrefix& prefix)
+{
+    os << '[' << LogMsgPrefix::SeverityToString(prefix.Severity) << "] ";
+    if (!g_LogConfig.ShouldPrintLocation()) return os;
+    return os << "(" << prefix.File << ':' << prefix.Line << ") ";
+}
diff --git a/debug-tools/remoteserver/debug.h b/debug-tools/remoteserver/debug.h
new file mode 100644
index 0000000..d3c99bf
--- /dev/null
+++ b/debug-tools/remoteserver/debug.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __debug_h
+#define __debug_h
+
+#include <iostream>
+
+// Severity values are expected to raise from zero
+enum LogSeverity
+{
+    LOG_SEV_ERROR   = 0,   // Unexpected input/events that may cause server misbehavior
+    LOG_SEV_WARNING = 1,   // Suspicious events
+    LOG_SEV_INFO    = 2,   // Events like command/response
+    LOG_SEV_DEBUG   = 3,   // Detailed functionality
+    LOG_SEV_VERBOSE = 4    // Excessive debug
+};
+
+#define TRACE_WITH_PREFIX(SEV)    \
+    g_LogConfig.ShouldPrint(SEV) && std::cout << LogMsgPrefix(SEV, __FILE__, __LINE__)
+
+#define LOG_ERROR   TRACE_WITH_PREFIX(LOG_SEV_ERROR)
+#define LOG_WARNING TRACE_WITH_PREFIX(LOG_SEV_WARNING)
+#define LOG_INFO    TRACE_WITH_PREFIX(LOG_SEV_INFO)
+#define LOG_DEBUG   TRACE_WITH_PREFIX(LOG_SEV_DEBUG)
+#define LOG_VERBOSE TRACE_WITH_PREFIX(LOG_SEV_VERBOSE)
+
+// *************************************************************************************************
+
+struct LogConfig
+{
+public:
+    LogConfig(LogSeverity maxSeverity, bool bPrintLocation);
+    void SetMaxSeverity(int traceLevel);
+
+    bool ShouldPrint(LogSeverity sev) const { return sev <= m_MaxSeverity; }
+    bool ShouldPrintLocation() const { return m_PrintLocation; }
+
+private:
+
+    LogSeverity m_MaxSeverity;
+    const bool m_PrintLocation;
+
+};
+
+// *************************************************************************************************
+
+extern LogConfig g_LogConfig;
+
+// *************************************************************************************************
+
+class LogMsgPrefix
+{
+    friend std::ostream& operator<<(std::ostream& os, const LogMsgPrefix& prefix);
+
+public:
+
+    LogMsgPrefix(LogSeverity severity, const char* pFile, int line)
+        : Severity(severity), File(pFile), Line(line) {}
+
+private:
+
+    static const char* SeverityToString(LogSeverity sev);
+
+    const LogSeverity Severity;
+    const char* const File;
+    const int Line;
+};
+
+
+// *************************************************************************************************
+// Stream Formatters
+// *************************************************************************************************
+
+// Print a boolean value as a string
+struct BoolStr
+{
+    explicit BoolStr(bool value): Value(value) {}
+    const bool Value;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const BoolStr& boolStr)
+{
+    return os << std::boolalpha << boolStr.Value << std::noboolalpha;
+}
+
+// *************************************************************************************************
+
+// Print a string while displaying newline characters
+struct PlainStr
+{
+    explicit PlainStr(const std::string& value): Value(value) {}
+    const std::string& Value;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const PlainStr& plainStr)
+{
+    for (std::string::const_iterator it = plainStr.Value.begin(); it != plainStr.Value.end(); ++it)
+    {
+        switch (*it)
+        {
+        case '\r': os << "\\r"; break;
+        case '\n': os << "\\n"; break;
+        case '\t': os << "\\t"; break;
+        default:   os << *it; break;
+        }
+    }
+
+    return os;
+}
+
+
+#endif
diff --git a/debug-tools/remoteserver/file_reader.cpp b/debug-tools/remoteserver/file_reader.cpp
new file mode 100644
index 0000000..3e08e73
--- /dev/null
+++ b/debug-tools/remoteserver/file_reader.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file_reader.h"
+#include "debug.h"
+
+#include <cstring>
+#include <cerrno>
+#include <stdio.h>
+
+// *************************************************************************************************
+
+FileReader::FileReader(const char* pFileName)
+    : m_FileName(pFileName)
+    , m_pFile(NULL)
+    , m_FileSize(0)
+    , m_ReadTillNow(0)
+    , m_IsCompleted(false)
+    , m_IsError(false)
+{
+    if (NULL == pFileName)
+    {
+        LOG_ERROR << "No file name provided" << std::endl;
+        return;
+    }
+
+    LOG_DEBUG << "Opening file reader for: " << m_FileName << std::endl;
+    m_pFile = fopen(pFileName, "rb");
+
+    if (NULL == m_pFile)
+    {
+        int lastErrno = errno;
+        LOG_ERROR << "Error opening file."
+                  << " Name: " << pFileName
+                  << " Error: " << lastErrno
+                  << " Message: " << strerror(lastErrno)
+                  << std::endl;
+        return;
+    }
+
+    fseek (m_pFile, 0, SEEK_END);
+    m_FileSize = ftell(m_pFile);
+    rewind(m_pFile);
+
+    LOG_DEBUG <<"Get file size for " << pFileName << ": " << m_FileSize << "B" << std::endl;
+}
+
+// *************************************************************************************************
+
+FileReader::~FileReader()
+{
+    if (m_pFile)
+    {
+        LOG_DEBUG << "Closing the file: " << m_FileName << std::endl;
+        fclose (m_pFile);
+        m_pFile = NULL;
+    }
+}
+
+// *************************************************************************************************
+
+bool FileReader::CanReadFromFile(char* pBuf, size_t availableSpace)
+{
+    if (!pBuf)
+    {
+        LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+                  << "No buffer is provided" << std::endl;
+        return false;
+    }
+
+    if (0 == availableSpace)
+    {
+        LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+                  << "No buffer space is provided" << std::endl;
+        return false;
+    }
+
+    if (NULL == m_pFile)
+    {
+        LOG_ERROR << "Cannot read from file " << m_FileName << ": "
+                  << "No file handle is available" << std::endl;
+        return false;
+    }
+
+    if (m_IsCompleted)
+    {
+        LOG_ERROR << "Unexpected read from file " << m_FileName << ": "
+                  << "EoF is reached" << std::endl;
+        return false;
+    }
+
+    if (m_IsError)
+    {
+        LOG_ERROR << "Unexpected read from file " << m_FileName << ": "
+                  << "Error occured" << std::endl;
+        return false;
+    }
+
+    return true;
+
+}
+
+// *************************************************************************************************
+
+size_t FileReader::ReadChunk(char* pBuf, size_t availableSpace)
+{
+    LOG_DEBUG << "Reading a chunk."
+              << " File Name: "     << m_FileName
+              << " File Size: "     << m_FileSize << "B"
+              << " Read till now: " << m_ReadTillNow << "B"
+              << " Buffer: "        << availableSpace << "B"
+              << " Completed: "     << BoolStr(m_IsCompleted)
+              << " Error: "         << BoolStr(m_IsError)
+              << std::endl;
+
+    if (false == CanReadFromFile(pBuf, availableSpace))
+    {
+        LOG_ERROR << "Cannot read from file: " << m_FileName
+                  << " Check previous errors/status" << std::endl;
+        m_IsError = true;
+        return 0;
+    }
+
+    // Read up to availableSpace. Reading less means either EoF is reached or read error occured
+    size_t readBytes = fread(pBuf, 1, availableSpace, m_pFile);
+    m_ReadTillNow += readBytes;
+
+    if (feof(m_pFile))
+    {
+        LOG_DEBUG << "EOF reached" << std::endl;
+        m_IsCompleted = true;
+    }
+
+    if (ferror(m_pFile))
+    {
+        int lastErrno = errno;
+        m_IsError = true;
+        LOG_ERROR << "Cannot read file"
+                  << " Name: "   << m_FileName
+                  << " Error: "  << lastErrno
+                  << " Message:" << strerror(lastErrno)
+                  << std::endl;
+    }
+
+    LOG_VERBOSE << "Got a chunk."
+                << " File Name: "     << m_FileName
+                << " File Size: "     << m_FileSize << "B"
+                << " Read till now: " << m_ReadTillNow << "B"
+                << " Buffer: "        << availableSpace << "B"
+                << " Completed: "     << BoolStr(m_IsCompleted)
+                << " Error: "         << BoolStr(m_IsError)
+                << std::endl;
+
+    return readBytes;
+
+}
diff --git a/debug-tools/remoteserver/file_reader.h b/debug-tools/remoteserver/file_reader.h
new file mode 100644
index 0000000..2b7b12f
--- /dev/null
+++ b/debug-tools/remoteserver/file_reader.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FILE_READER_H_
+#define _FILE_READER_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+// *************************************************************************************************
+
+// Reads a file from the file system and exports its content to a buffer provided by the caller.
+// If the file is larger than a provide bugffer, it is delivered by chunks of the buffer size.
+// The last chunk may occupy less than the whole buffer. It's a caller's responsibility to allocate
+// the buffer and call the FileReader API untill the file is fully exported.
+
+class FileReader
+{
+public:
+
+    explicit FileReader(const char* pFileName);
+    ~FileReader();
+
+    size_t ReadChunk(char* pBuf, size_t availableSpace);
+
+    bool IsCompleted() const { return m_ReadTillNow == m_FileSize; }
+    bool IsError() const { return m_IsError; }
+
+    size_t ReadTillNow() const { return m_ReadTillNow; }
+    size_t GetFileSize() const { return m_FileSize; }
+
+private:
+
+    bool CanReadFromFile(char* pBuf, size_t availableSpace);
+
+    const std::string m_FileName;        // File name - cached for tracing
+    FILE* m_pFile;                       // File Handler - open for read
+    size_t m_FileSize;                   // File Size
+    size_t m_ReadTillNow;                // Bytes read till now
+    bool m_IsCompleted;                  // Set to true when OEF is reached
+    bool m_IsError;                      // Error flag
+
+};
+
+
+#endif    // _FILE_READER_H_
diff --git a/debug-tools/remoteserver/main.cpp b/debug-tools/remoteserver/main.cpp
new file mode 100644
index 0000000..dae1030
--- /dev/null
+++ b/debug-tools/remoteserver/main.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>     // getopt
+#include <stdlib.h>     // atoi
+#include <signal.h>	// SIGQUIT handling
+#include "parser.h"
+#include "server.h"
+#include "udp_server.h"
+#include "debug.h"
+
+#define WILSERVER_VERSION 0x0100
+#define DEFAULT_SERVER_PORT 12348
+#define DEFAULT_UDP_LOCAL_SERVER_PORT_IN 12349
+#define DEFAULT_UDP_REMOTE_SERVER_PORT_IN 12350
+
+UdpServer us;
+Server s;
+
+void sig_quit_handler(int signum)
+{
+    if (signum == SIGQUIT)
+    {
+        printf("Exiting Wilserver as per user request\n");
+        us.stop();
+        s.stop();
+        exit(signum);
+    }
+}
+
+int main(int argc, char* argv[])
+{
+    // Register for SIGQUIT signal
+    signal(SIGQUIT, sig_quit_handler);
+
+    int opt;
+    int port=DEFAULT_SERVER_PORT;
+    int localUdpPortIn = DEFAULT_UDP_LOCAL_SERVER_PORT_IN;
+    int remoteUdpPortIn = DEFAULT_UDP_REMOTE_SERVER_PORT_IN;
+    int traceLevel = LOG_SEV_WARNING;
+
+    while ((opt = getopt(argc, argv, "d:vp:")) != -1) {
+        switch (opt) {
+        case 'd':
+            traceLevel = atoi(optarg);
+            g_LogConfig.SetMaxSeverity(traceLevel);
+            break;
+        case 'p':
+            port = atoi(optarg);
+            if(port == 0)  {
+                LOG_ERROR << "Invalid port specified" << optarg << std::endl;
+                exit(EXIT_FAILURE);
+            }
+            break;
+        default:
+            fprintf(stderr, "Usage: %s [-d debug_level] | [-p port]\n", argv[0]);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    LOG_INFO << "Starting WIGIG Remote Server" << std::endl;
+    us.start(localUdpPortIn, remoteUdpPortIn);
+    s.start(port);
+    return 0;
+}
+
+
diff --git a/debug-tools/remoteserver/parser.h b/debug-tools/remoteserver/parser.h
new file mode 100644
index 0000000..112f90f
--- /dev/null
+++ b/debug-tools/remoteserver/parser.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __parser_h
+#define __parser_h
+
+#include "servercmd.h"
+
+
+int parse_line(const char *line, servercmd_t *s);
+
+#endif /* __parser_h */
diff --git a/debug-tools/remoteserver/parser.l b/debug-tools/remoteserver/parser.l
new file mode 100644
index 0000000..e4d0507
--- /dev/null
+++ b/debug-tools/remoteserver/parser.l
@@ -0,0 +1,211 @@
+%{
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "servercmd.h"
+
+static int acc_byte = 0;
+static int acc_len =  0;
+
+%}
+%option noyywrap
+%option nounput
+/* We need reentratnt scanner for multiple connections */
+%option reentrant
+/* %option c++ */
+%x str
+DIGIT		[0-9]
+HEXDIGIT	[0-9A-Fa-f]
+
+ID		[A-Za-z_!][A-Za-z_!0-9]*
+
+%%
+"get_interfaces"  {
+		if(cb_cmd(yyextra, CMD_GET_INTERFACES))
+			yyterminate();
+		}
+"open_interface"	{
+		if(cb_cmd(yyextra, CMD_OPEN_INTERFACE))
+			yyterminate();
+		}
+"close_interface" {
+		if(cb_cmd(yyextra, CMD_CLOSE_INTERFACE))
+			yyterminate();
+		}
+"r"		{
+		if(cb_cmd(yyextra, CMD_R))
+			yyterminate();
+		}
+"rb"		{
+		if(cb_cmd(yyextra, CMD_RB))
+			yyterminate();
+		}
+"w"		{
+		if(cb_cmd(yyextra, CMD_W))
+			yyterminate();
+		}
+"wb"		{
+		if(cb_cmd(yyextra, CMD_WB))
+			yyterminate();
+		}
+"alloc_pmc"	{
+		if(cb_cmd(yyextra, CMD_ALLOC_PMC))
+			yyterminate();
+		}
+"read_pmc"	{
+		if(cb_cmd(yyextra, CMD_READ_PMC))
+			yyterminate();
+		}
+"read_pmc_file" {
+		if(cb_cmd(yyextra, CMD_READ_PMC_FILE))
+			yyterminate();
+		}
+"interface_reset" {
+		if(cb_cmd(yyextra, CMD_INTERFACE_RESET))
+			yyterminate();
+		}
+
+"sw_reset"      {
+		if(cb_cmd(yyextra, CMD_SW_RESET))
+			yyterminate();
+		}
+"exit"  {
+        if(cb_cmd(yyextra, CMD_EXIT))
+            yyterminate();
+        }
+"set_host_alias"  {
+        if(cb_cmd(yyextra, CMD_SET_HOST_ALIAS))
+            yyterminate();
+        }
+{DIGIT}+	{
+		/* A decimal number represents the address/value */
+		if(cb_number(yyextra, yytext))
+			yyterminate();
+		}
+
+{ID}		{
+		/* The protocol doesn't separate between interface id and command */
+		if(cb_id(yyextra, yytext))
+			yyterminate();
+		}
+\"		{
+		/* Start of string */
+		BEGIN(str);
+		acc_byte = 0;
+		acc_len = 0;
+		}
+<str>\"		{
+		/* End of string */
+		if(acc_len > 0) {
+			if(cb_hexbyte(yyextra, acc_byte))
+				yyterminate();
+		}
+		/* Callback for end of hex string */
+		if(cb_endhex(yyextra))
+			yyterminate();
+		BEGIN(INITIAL);
+		}
+<str>{HEXDIGIT}	{
+		/* We get hex bytes in the string */
+		if(acc_len == 10)  {
+			cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+			yyterminate();
+		}else if(acc_len <= 1){
+			acc_len++;
+		// do nothing on the 0x
+		}
+		else  {
+			acc_len++;
+			acc_byte = acc_byte * 16 +  hexdigit(yytext[0]);
+			}
+		}
+<str>[ \t]	{
+		/* Hex bytes separated by spaces */
+			if(acc_len > 0) {
+				if(cb_hexbyte(yyextra, acc_byte))
+					yyterminate();
+				acc_len = 0;
+				acc_byte = 0;
+			}
+		}
+<str><<EOF>>	{
+		/* Check the end of string with unterminated quote */
+		cb_error(yyextra, ERR_UNTERMINATED_STRING, "");
+		yyterminate();
+		}
+<str>x		{
+		/* if we ancounter 0x, remove the x and continue */
+			if(acc_len != 1){
+				cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+			}
+			acc_len++;
+		}
+<str>.		{
+		/* Anything except the hex bytes is not allowed in the string parameter */
+		cb_error(yyextra, ERR_BAD_HEX_VALUE, "");
+		yyterminate();
+		}
+
+[ \t\r\n]+	{
+		/* Whitespace */
+		if(cb_separator(yyextra))
+			yyterminate();
+		}
+.		{
+		cb_error(yyextra, ERR_BAD_TOKEN, yytext);
+		yyterminate();
+		}
+%%
+
+/*
+ Parses the input line
+*/
+int parse_line(const char *line, servercmd_t *s)
+{
+	yyscan_t scanner;
+	YY_BUFFER_STATE bs;
+	cb_parser_start(s);
+        yylex_init(&scanner);
+
+        if (!scanner)
+        {
+            return 1;
+        }
+
+	yyset_extra(s, scanner);
+	bs = yy_scan_string(line, scanner);
+	yylex(scanner);
+	yy_delete_buffer(bs, scanner);
+	yylex_destroy(scanner);
+	cb_parser_end(s);
+	return s->error;
+}
+
+
+
diff --git a/debug-tools/remoteserver/pmc_file.cpp b/debug-tools/remoteserver/pmc_file.cpp
new file mode 100644
index 0000000..e449739
--- /dev/null
+++ b/debug-tools/remoteserver/pmc_file.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pmc_file.h"
+#include "debug.h"
+
+#include <cstring>
+#include <cerrno>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// *************************************************************************************************
+#ifdef __ANDROID__
+#define PMC_DATA_DIRECTORY "/data/pmc"
+#else
+#define PMC_DATA_DIRECTORY "/var/pmc"
+#endif
+
+// PMC directory and file name pattern should be managed separately as directory is required as a
+// separate variable.
+
+const char* const PmcFile::s_pDirectory = PMC_DATA_DIRECTORY;
+const char* const PmcFile::s_pFileNamePrefix = "pmc_data_";
+
+// *************************************************************************************************
+
+PmcFile::PmcFile(int fileId)
+    : m_FileId(fileId)
+{
+    std::stringstream ss;
+    ss << s_pDirectory << '/' << s_pFileNamePrefix << fileId;
+    m_FileName = ss.str();
+
+    LOG_DEBUG << "PMC file name #" << fileId << " generated: " << m_FileName << std::endl;
+}
+
+std::ostream& operator<<(std::ostream& os, const PmcFile& pmcFile)
+{
+    return os << "PMC file #" << pmcFile.GetFileId() << " (" << pmcFile.GetFileName() << ')';
+}
+
+// *************************************************************************************************
+
+PmcFileWriter::PmcFileWriter(const PmcFile& pmcFile)
+    : m_PmcFile(pmcFile)
+{
+}
+
+// *************************************************************************************************
+
+bool PmcFileWriter::CreateDirectoryIfNeeded() const
+{
+    // Create a PMC directory if does not exist
+    struct stat st = {};
+    if (stat(m_PmcFile.GetDirectory(), &st) != -1)
+    {
+        LOG_DEBUG << "PMC directory " << m_PmcFile.GetDirectory()
+                  << " exists for " << m_PmcFile.GetFileName() << std::endl;
+        return true;
+    }
+
+    LOG_DEBUG << "Creating a PMC directory: " << m_PmcFile.GetDirectory() << std::endl;
+
+    int status = mkdir(m_PmcFile.GetDirectory(), 0700);
+    if (0 != status)
+    {
+        int lastErrno = errno;
+        LOG_ERROR << "Cannot create PMC directory."
+                  << " Path: "    << m_PmcFile.GetDirectory()
+                  << " Error:"    <<  lastErrno
+                  << " Message: " << strerror(lastErrno)
+                  << std::endl;
+
+        return false;
+    }
+
+    return true;
+}
+
+// *************************************************************************************************
+
+bool PmcFileWriter::WriteFile() const
+{
+    if (false == CreateDirectoryIfNeeded())
+    {
+        LOG_ERROR << "Cannot create a PMC directory for " << m_PmcFile << std::endl;
+        return false;
+    }
+
+    // Create a PMC file
+    const char* pCmdPrefix =
+        "D=$(find /sys/kernel/debug/ieee80211/ -name wil6210); cat $D/pmcdata >> ";
+    std::stringstream ss;
+    ss << pCmdPrefix << m_PmcFile.GetFileName();
+
+    system(ss.str().c_str());
+    return true;
+
+}
+
+// *************************************************************************************************
+
+size_t PmcFileWriter::GetFileSize() const
+{
+    FILE *pFile = fopen(m_PmcFile.GetFileName(), "r");
+
+    if (NULL == pFile)
+    {
+        int lastErrno = errno;
+        LOG_ERROR << "Cannot open " << m_PmcFile << " for writing."
+                  << " Error: "   << lastErrno
+                  << " Message: " << strerror(lastErrno)
+                  << std::endl;
+        return 0;
+    }
+
+    fseek (pFile, 0, SEEK_END);
+    size_t fileSize = ftell(pFile);
+    fclose(pFile);
+
+    LOG_DEBUG << "Get PMC file size for " << m_PmcFile
+              << ": " << fileSize << "B" << std::endl;
+
+    return fileSize;
+}
diff --git a/debug-tools/remoteserver/pmc_file.h b/debug-tools/remoteserver/pmc_file.h
new file mode 100644
index 0000000..b7af0b7
--- /dev/null
+++ b/debug-tools/remoteserver/pmc_file.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PMC_FILE_H_
+#define _PMC_FILE_H_
+
+#include <stdio.h>
+#include <string>
+
+// *************************************************************************************************
+
+// Generates a PMC file name from its ID.
+class PmcFile
+{
+public:
+
+    explicit PmcFile(int fileId);
+
+    int GetFileId() const { return m_FileId; }
+    const char* GetFileName() const { return m_FileName.c_str(); }
+
+    static const char* GetDirectory() { return s_pDirectory; }
+
+private:
+
+    static const char* const s_pDirectory;
+    static const char* const s_pFileNamePrefix;
+
+    const int m_FileId;        // File ID (expected to be unique)
+    std::string m_FileName;    // File Name Buffer
+
+};
+
+std::ostream& operator<<(std::ostream& os, const PmcFile& pmcFile);
+
+// *************************************************************************************************
+
+// Creates a PMC data file according to a provided ID.
+class PmcFileWriter
+{
+public:
+
+    explicit PmcFileWriter(const PmcFile& pmcFile);
+
+    bool WriteFile() const;
+    size_t GetFileSize() const;
+
+private:
+
+    bool CreateDirectoryIfNeeded() const;
+
+    const PmcFile& m_PmcFile;
+
+};
+
+
+#endif    // PMC_FILE_H_
diff --git a/debug-tools/remoteserver/server.cpp b/debug-tools/remoteserver/server.cpp
new file mode 100644
index 0000000..5ee1b48
--- /dev/null
+++ b/debug-tools/remoteserver/server.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cerrno>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fstream>
+#include "server.h"
+#include "cmdiface.h"
+#include "debug.h"
+#include "pmc_file.h"
+#include "file_reader.h"
+
+// Thread parameters structure
+typedef struct {
+    int sock;
+    struct sockaddr address;
+    int addr_len;
+} connection_par_t;
+
+volatile int Server::shutdown_flag = 0;
+volatile int Server::running_threads = 0;
+pthread_mutex_t Server::threads_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void *Server::server_process(void *ptr)
+{
+    char *buf;
+    CmdIface *iface;
+    int rw;
+
+    if(ptr == NULL)
+    {
+        pthread_exit(0);
+    }
+
+    connection_par_t *par = (connection_par_t*)ptr;
+    iface = new CmdIface();
+    buf = new char[MAX_INPUT_BUF+1];
+    memset(buf, 0, MAX_INPUT_BUF+1);
+    rw = read(par->sock, buf, MAX_INPUT_BUF);
+
+    while(rw > 0)
+    {
+        // Got some data
+        if(rw)
+        {
+            buf[rw] = '\0';
+            LOG_INFO << "Client Command: " << PlainStr(buf) << std::endl;
+            int cmdKeepalive = iface->do_command((const char*)buf, rw);
+            LOG_DEBUG << "Command handling keepalive: " << cmdKeepalive << std::endl;
+
+            // Check for keepalive return value
+            int replyKeepalive = reply(par->sock, iface);
+
+            if(cmdKeepalive == KEEPALIVE_CLOSE || replyKeepalive == KEEPALIVE_CLOSE)
+            {
+                // Handler asked to close the connection
+                rw = 0;
+                break;
+            }
+        }
+        rw = read(par->sock, buf, MAX_INPUT_BUF);
+    }
+
+    // if 0 - connection is closed, <0 - error
+    LOG_DEBUG << "Closing connection. Read result: " << rw << std::endl;
+    close(par->sock);
+    delete[] buf;
+    delete iface;
+    delete par;
+    pthread_mutex_lock(&threads_counter_mutex);
+    running_threads--;
+    pthread_mutex_unlock(&threads_counter_mutex);
+    pthread_exit(0);
+}
+
+int Server::reply(int sock, CmdIface* iface)
+{
+    LOG_INFO << "Reply: " << PlainStr(iface->get_reply()) << std::endl;
+
+    switch (iface->get_reply_type())
+    {
+    case REPLY_TYPE_BUFFER:
+        return reply_buffer(sock, iface->get_reply(), iface->get_reply_len());
+
+    case REPLY_TYPE_FILE:
+        return reply_file(sock, iface->get_reply());
+
+    default:
+        LOG_ERROR << "Unexpected reply type: " << iface->get_reply_type() << std::endl;
+        return KEEPALIVE_CLOSE;
+    }
+}
+
+int Server::reply_buffer(int sock, const char* pBuf, size_t len)
+{
+    LOG_DEBUG << "Replying from a buffer (" << len << "B) Content: " << PlainStr(pBuf) << std::endl;
+
+    if (0 == len)
+    {
+        LOG_ERROR << "No reply generated by a command handler - connection will be closed" << std::endl;
+        return KEEPALIVE_CLOSE;
+    }
+
+    if (false == send_buffer(sock, pBuf, len))
+    {
+        return KEEPALIVE_CLOSE;
+    }
+
+    return KEEPALIVE_OK;
+}
+
+int Server::reply_file(int sock, const char* pFileName)
+{
+    LOG_DEBUG << "Replying from a file: " << pFileName << std::endl;
+
+    FileReader fileReader(pFileName);
+    size_t fileSize = fileReader.GetFileSize();
+
+    if (0 == fileSize)
+    {
+        LOG_ERROR << "No file content is available for reply" << std::endl;
+        return KEEPALIVE_CLOSE;
+    }
+
+    static const size_t BUF_LEN = 64 * 1024;
+
+    char* pBuf = new char[BUF_LEN];
+    size_t chunkSize = 0;
+    bool isError = false;
+
+    do
+    {
+        LOG_VERBOSE << "Requesting for a file chunk" << std::endl;
+
+        chunkSize = fileReader.ReadChunk(pBuf, BUF_LEN);
+        if (chunkSize > 0)
+        {
+            if (false == send_buffer(sock, pBuf, chunkSize))
+            {
+                LOG_ERROR << "Send error detected" << std::endl;
+                isError = true;
+                break;
+            }
+        }
+
+        // Error/Completion may occur with non-zero chunk as well
+        if (fileReader.IsError())
+        {
+            LOG_ERROR << "File read error detected" << std::endl;
+            isError = true;
+            break;
+        }
+
+        if (fileReader.IsCompleted())
+        {
+            LOG_DEBUG << "File completion detected" << std::endl;
+            break;
+        }
+
+        LOG_DEBUG << "File Chunk Delivered: " << chunkSize << "B" << std::endl;
+    }
+    while (chunkSize > 0);
+
+    delete[] pBuf;
+
+    if (isError)
+    {
+        LOG_ERROR << "Error occured while replying file content" << std::endl;
+        return KEEPALIVE_CLOSE;
+    }
+    else
+    {
+        LOG_DEBUG << "File Content successfully delivered" << std::endl;
+        return KEEPALIVE_OK;
+    }
+}
+
+bool Server::send_buffer(int sock, const char* pBuf, size_t len)
+{
+    if (!pBuf)
+    {
+        LOG_ERROR << "Cannot reply to a command - No buffer is provided" << std::endl;
+        return false;
+    }
+
+    size_t sentTillNow = 0;
+
+    while(sentTillNow < len)
+    {
+        ssize_t sentBytes = write(sock, pBuf, len);
+        if (sentBytes < 0)
+        {
+            int lastErrno = errno;
+            LOG_ERROR << "Cannot send response buffer."
+                      << " Error:" << lastErrno
+                      << " Message: " << strerror(lastErrno)
+                      << std::endl;
+            return false;
+        }
+
+        sentTillNow += sentBytes;
+        LOG_DEBUG << "Sent response chunk."
+                  << " Chunk Size: "      << sentBytes
+                  << " Sent till now: "   << sentTillNow
+                  << " Response Length: " <<  len
+                  << std::endl;
+    }
+
+    LOG_DEBUG << "Response buffer fully sent" << std::endl;
+    return true;
+}
+
+/*
+  Close the server to allow un-bind te socket - allowing future connections without delay
+*/
+int Server::stop()
+{
+    LOG_INFO << "Stopping the server" << std::endl;
+    shutdown(sock, SHUT_RDWR);
+    return 0;
+}
+
+/*
+  Initialize server on the given port. The function returns in case of error,
+  otherwise it doesn't return
+*/
+int Server::start(int port)
+{
+    LOG_INFO << "Starting the server on port " << port << std::endl;
+
+    struct sockaddr_in address;
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+    if(sock < 0)
+    {
+        LOG_ERROR << "Cannot create a socket on port " << port << std::endl;
+        return -1;
+    }
+
+    address.sin_family = AF_INET;
+    address.sin_addr.s_addr = INADDR_ANY;
+    address.sin_port = htons(port);
+
+    // Set the "Re-Use" socket option - allows reconnections after wilserver exit
+    int reuse = 1;
+    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
+
+    if(bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
+    {
+        LOG_ERROR << "Cannot bind socket to port " << port << std::endl;
+        return -2;
+    }
+
+    if (listen(sock, 5) < 0)
+    {
+        LOG_ERROR << "Cannot listen on port " << port << std::endl;
+        return -3;
+    }
+
+    shutdown_flag = 0;
+    while (shutdown_flag == 0)  {
+        pthread_t thread;
+        connection_par_t *par = new connection_par_t;
+        par->sock = accept(sock, &par->address, (socklen_t*)&par->addr_len);
+        if(par->sock < 0)
+            delete par;
+        else {
+            pthread_mutex_lock(&threads_counter_mutex);
+            running_threads++;
+            pthread_mutex_unlock(&threads_counter_mutex);
+            pthread_create(&thread, 0, &Server::server_process, (void *)par);
+            pthread_detach(thread);
+        }
+
+    }
+    // Wait till all the threads are done in case we ever exit the loop above
+    while(running_threads > 0)
+        sleep(1);
+
+    LOG_INFO << "Server shutdown" << std::endl;
+
+    return 0; // Wont get here, just to avoid the warning
+}
diff --git a/debug-tools/remoteserver/server.h b/debug-tools/remoteserver/server.h
new file mode 100644
index 0000000..01cd080
--- /dev/null
+++ b/debug-tools/remoteserver/server.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __server_h
+#define __server_h
+#include <pthread.h>
+#include <string>
+
+class CmdIface;
+
+class Server
+{
+public:
+
+    int start(int port);
+    int stop();
+
+    static int get_shutdown_flag() { return shutdown_flag; }
+
+
+private:
+
+    static volatile int shutdown_flag;
+    static volatile int running_threads;
+    static pthread_mutex_t threads_counter_mutex;
+    int sock;
+
+    static void *server_process(void *ptr);
+    static bool send_buffer(int sock, const char* pBuf, size_t len);
+    static int reply(int sock, CmdIface* iface);
+    static int reply_buffer(int sock, const char* pBuf, size_t len);
+    static int reply_file(int sock, const char* pFileName);
+};
+
+#endif // server_h
+
diff --git a/debug-tools/remoteserver/servercmd.cpp b/debug-tools/remoteserver/servercmd.cpp
new file mode 100644
index 0000000..bfc180b
--- /dev/null
+++ b/debug-tools/remoteserver/servercmd.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+#include "servercmd.h"
+#include "debug.h"
+
+#define EXP_NON		0
+#define EXP_CMD		(-1)
+#define EXP_IFC		1
+#define EXP_NUM		2
+#define EXP_HEX		3
+#define EXP_SEP		4
+#define EXP_END		5
+
+const char* parser_state_to_string(int parserState)
+{
+    switch (parserState)
+    {
+    case EXP_NON: return "EXP_NON";
+    case EXP_CMD: return "EXP_CMD";
+    case EXP_IFC: return "EXP_IFC";
+    case EXP_NUM: return "EXP_NUM";
+    case EXP_HEX: return "EXP_HEX";
+    case EXP_SEP: return "EXP_SEP";
+    case EXP_END: return "EXP_END";
+    default:      return "<unknown>";
+    }
+}
+
+
+static int states_table[][5] =
+{
+    { EXP_END, 0,       0,       0,       0 },      // 0 - get_interfaces
+    { EXP_IFC, EXP_END, 0,       0,       0 },      // 1 - open_interface name
+    { EXP_IFC, EXP_END, 0,       0,       0 },      // 2 - close_interface name
+    { EXP_IFC, EXP_NUM, EXP_END, 0,       0 },      // 3 - r name address
+    { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 },      // 4 - rb name address count
+    { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 },      // 5 - w name address value
+    { EXP_IFC, EXP_NUM, EXP_HEX, EXP_END, 0 },      // 6 - wb name address hexstring
+    { EXP_IFC, EXP_END, 0,       0,       0 },      // 7 - interface_reset name
+    { EXP_IFC, EXP_END, 0,       0,       0 },      // 8 - sw_reset name
+    { EXP_END, 0,       0,       0,       0 },      // 9 - exit
+    { EXP_IFC, EXP_NUM, EXP_NUM, EXP_END, 0 },      // 10 - Alloc_PMC name number_of_descriptors size_of_descriptors
+    { EXP_IFC, EXP_NUM, EXP_END, 0,       0 },      // 11 - read_pmc interface requestReferenceNumber
+    { EXP_NUM, EXP_END, 0,       0,       0 },      // 12 - read_pmc_file requestReferenceNumber
+    { EXP_IFC, EXP_END, 0, 		 0, 	  0 }, 		// 13 - set_host_alias
+};
+
+
+// The return value is copied because std::stringstream::str() returns a temporary object
+std::string parser_state_machine_to_string(int* pStateMachine)
+{
+    if (!pStateMachine)
+    {
+        return std::string("{}");
+    }
+
+    std::stringstream ss;
+
+    ss << "{ ";
+
+    size_t numStates = sizeof(states_table[0])/sizeof(int);
+    for (size_t i = 0; i < numStates; ++i)
+    {
+        ss << parser_state_to_string(pStateMachine[i]) << " ";
+    }
+    ss << "}";
+
+    return ss.str();
+}
+
+
+const char* command_to_string(int cmdCode)
+{
+    switch (cmdCode)
+    {
+    case CMD_COMMAND_UNKNOWN: return "CMD_COMMAND_UNKNOWN";
+    case CMD_GET_INTERFACES:  return "CMD_GET_INTERFACES";
+    case CMD_OPEN_INTERFACE:  return "CMD_OPEN_INTERFACE";
+    case CMD_CLOSE_INTERFACE: return "CMD_CLOSE_INTERFACE";
+    case CMD_R:               return "CMD_R";
+    case CMD_RB:              return "CMD_RB";
+    case CMD_W:               return "CMD_W";
+    case CMD_WB:              return "CMD_WB";
+    case CMD_INTERFACE_RESET: return "CMD_INTERFACE_RESET";
+    case CMD_SW_RESET:        return "CMD_SW_RESET";
+    case CMD_EXIT:            return "CMD_EXIT";
+    case CMD_ALLOC_PMC:       return "CMD_ALLOC_PMC";
+    case CMD_READ_PMC:        return "CMD_READ_PMC";
+    case CMD_READ_PMC_FILE:   return "CMD_READ_PMC_FILE";
+    case CMD_SET_HOST_ALIAS:  return "CMD_SET_HOST_ALIAS";
+    default:                  return "<unknown>";
+    }
+}
+
+
+const char* parser_error_to_string(int parserError)
+{
+    switch (parserError)
+    {
+    case ERR_BAD_TOKEN:           return "ERR_BAD_TOKEN";
+    case ERR_BAD_VALUE:           return "VALUE";
+    case ERR_UNTERMINATED_STRING: return "ERR_UNTERMINATED_STRING";
+    case ERR_BAD_HEX_VALUE:       return "ERR_BAD_HEX_VALUE";
+    case ERR_CMD_NOT_EXPECTED:    return "ERR_CMD_NOT_EXPECTED";
+    case ERR_IFACE_NOT_EXPECTED:  return "ERR_IFACE_NOT_EXPECTED";
+    case ERR_VALUE_NOT_EXPECTED:  return "ERR_VALUE_NOT_EXPECTED";
+    case ERR_HEX_NOT_EXPECTED:    return "ERR_HEX_NOT_EXPECTED";
+    case ERR_END_NOT_EXPECTED:    return "ERR_END_NOT_EXPECTED";
+    default:                      return "<unknown>";
+    }
+}
+
+
+
+/*
+  Callback on parser start.
+  Returns the handler to be used in all subsequent callbacks
+  or NULL in case of error, the parsing will be aborted then
+*/
+void cb_parser_start(servercmd_t *s)
+{
+    s->states = NULL;
+    s->state = EXP_CMD;	// We start with expecting a command
+    s->cmd = CMD_COMMAND_UNKNOWN;
+    s->error = 0;
+    s->address = (unsigned int)-1;
+    s->value = (unsigned int)-1;
+    s->hexdata_len = 0;
+    s->hexdata = (unsigned int*)malloc (sizeof(int)*MAX_REGS_LEN);
+}
+
+/*
+  Callback on a command. Gets the command code.
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int  cb_cmd(servercmd_t *s, int cmd)
+{
+    LOG_VERBOSE <<"cb_cmd(" << cmd << ") state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if(s->state != EXP_CMD)  {
+        s->error = ERR_CMD_NOT_EXPECTED;
+        LOG_ERROR << "Command not expected, expecting " << s->state << std::endl;
+        return -1;
+    }
+    LOG_VERBOSE << "Parsed Command: " << cmd << "(" << command_to_string(cmd) << ")" << std::endl;
+    s->cmd = cmd;
+    s->states = states_table[cmd];
+    s->state++;
+
+    return 0;
+}
+
+
+/*
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int  cb_id(servercmd_t *s, const char *id)
+{
+    LOG_VERBOSE << "cb_id(" << id << ") state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if((s->states == NULL) || (s->states[s->state] != EXP_IFC)) {
+        s->error = ERR_IFACE_NOT_EXPECTED;
+        LOG_ERROR << "Interface not expected, expecting: "
+                  << (s->states?s->states[s->state]:-1) << std::endl;
+        return -1;
+    }
+
+    LOG_VERBOSE << "Interface id: " << id << std::endl;
+    snprintf(s->interface, MAX_INTERFACE_NAME, "%s", id);
+    s->state++;
+    return 0;
+}
+
+/*
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int  cb_number(servercmd_t *s, const char *id)
+{
+    LOG_VERBOSE << "cb_number(" << id << ") state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if((s->states == NULL) || (s->states[s->state] != EXP_NUM))  {
+        s->error = ERR_VALUE_NOT_EXPECTED;
+        LOG_ERROR << "Number not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+        return -1;
+    }
+
+    // A hack now. if address already set, the number is for data
+    LOG_VERBOSE << "string number " << id << std::endl;
+
+    if(s->address != (unsigned int)-1){
+        sscanf(id, "%u", &(s->value));
+        //s->value = strtoul(id, tmp, 10); //10 is the base for conversion
+	//	dprint("str to uint Parsed val %u\n",  strtoul(id, tmp, 10));
+	//	dprint("str to int Parsed val %u\n", atol(id));//s->value = atol(id);
+        LOG_VERBOSE << "scanf Parsed value: " << s->value << std::endl;
+    }
+    else{
+	//	s->address = atol(id);
+        sscanf(id, "%u", &(s->address));
+        LOG_VERBOSE << "Parsed addr " << s->address << std::endl;
+    }
+    s->state++;
+    return 0;
+}
+
+/*
+  Callback on hex data
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int  cb_hexbyte(servercmd_t *s, int b)
+{
+    LOG_VERBOSE << "cb_hexbyte(0x" << std::hex << b << std::dec << ") state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
+        s->error = ERR_HEX_NOT_EXPECTED;
+        LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+        return -1;
+    }
+    if(s->hexdata_len == MAX_REGS_LEN) {
+        s->error = ERR_BAD_HEX_VALUE;
+        LOG_ERROR << "Too long hex data" << std::endl;
+        return -1;
+    }
+    LOG_VERBOSE << "Hex byte 0x" << std::hex << b << std::dec << std::endl;
+    s->hexdata[s->hexdata_len] = b;
+    s->hexdata_len++;
+    // Do not change the s->state here, we are still expecting hex data. cb_endhex will change the state
+    return 0;
+}
+
+/*
+  Callback on end of hex data string
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+
+int cb_endhex(servercmd_t *s)
+{
+    LOG_VERBOSE << "cb_endhex() state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if((s->states == NULL) || (s->states[s->state] != EXP_HEX)) {
+        s->error = ERR_HEX_NOT_EXPECTED;
+        LOG_ERROR << "Hex not expected, expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+        return -1;
+    }
+    s->state++;
+    return 0;
+}
+
+/*
+  Callback on a separator, not used.
+  Returns 0 if ok, 1 if error, the parsing will be aborted then
+*/
+int  cb_separator(servercmd_t *s)
+{
+    (void)s;
+    return 0;
+}
+
+/*
+  Callback on the parser end
+  Returns the parser result: 0 if ok, error otherwise
+*/
+void  cb_parser_end(servercmd_t *s)
+{
+    LOG_VERBOSE << "cb_parser_end() state index = " << s->state << std::endl;
+    LOG_VERBOSE << "State Machine: " << parser_state_machine_to_string(s->states) << std::endl;
+
+    if((s->error == 0) && ((s->states == NULL) || (s->states[s->state] != EXP_END)))  {
+        LOG_ERROR << "End of parser while still expecting " << (s->states?s->states[s->state]:-1) << std::endl;
+        s->error = ERR_END_NOT_EXPECTED;
+    }
+
+    free(s->hexdata);
+}
+
+/*
+  Callback on parser error
+*/
+void cb_error(servercmd_t *s, int error, const char *str)
+{
+    (void)str;
+    s->error = error;
+    LOG_ERROR << "Parser error: " << error << std::endl;
+}
+
+/*
+  Service function. Converting a hex digit from a character.
+*/
+int hexdigit(char d)
+{
+    if((d >= '0') && (d <= '9'))
+        return d-'0';
+    else if((d >= 'A') && (d <= 'F'))
+        return d-'A'+10;
+    else if((d >- 'a') && (d <= 'f'))
+        return d-'a'+10;
+    else	// This shouldn't happen, it's the parser's responsibility to parse valid hex digits
+        return 0;
+}
diff --git a/debug-tools/remoteserver/servercmd.h b/debug-tools/remoteserver/servercmd.h
new file mode 100644
index 0000000..c63e3c7
--- /dev/null
+++ b/debug-tools/remoteserver/servercmd.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __servercmd_h
+#define __servercmd_h
+
+// This header is included by the parser, which is flex-generated C code
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Commands list
+#define CMD_COMMAND_UNKNOWN     (-1)
+#define CMD_GET_INTERFACES      0
+#define CMD_OPEN_INTERFACE      1
+#define CMD_CLOSE_INTERFACE     2
+#define CMD_R                   3
+#define CMD_RB                  4
+#define CMD_W                   5
+#define CMD_WB                  6
+#define CMD_INTERFACE_RESET     7
+#define CMD_SW_RESET            8
+#define CMD_EXIT                9  // debug command
+#define CMD_ALLOC_PMC           10
+#define CMD_READ_PMC            11
+#define CMD_READ_PMC_FILE       12
+#define CMD_SET_HOST_ALIAS		13
+
+
+const char* command_to_string(int cmdCode);
+
+#define MAX_INTERFACE_NAME 32          // TODO: better to include WlctPciAcss.h that defines MAX_IF_NAME_LENGTH==32
+#define MAX_REGS_LEN    (256* 1024)    // Max registers to read/write at once
+
+// Parser errors
+#define ERR_BAD_TOKEN (-1)
+#define ERR_BAD_VALUE (-2)
+#define ERR_UNTERMINATED_STRING (-3)
+#define ERR_BAD_HEX_VALUE (-4)
+#define ERR_CMD_NOT_EXPECTED (-5)
+#define ERR_IFACE_NOT_EXPECTED (-6)
+#define ERR_VALUE_NOT_EXPECTED (-7)
+#define ERR_HEX_NOT_EXPECTED (-8)
+#define ERR_END_NOT_EXPECTED (-9)
+
+const char* parser_error_to_string(int parserError);
+
+
+/*
+ Parser result/state structure
+*/
+typedef struct {
+	int state;
+	int cmd;
+	int *states;
+	char interface[MAX_INTERFACE_NAME+1];
+	unsigned int address;
+	unsigned int value;
+	unsigned int* hexdata;
+	int hexdata_len;
+	int error;
+} servercmd_t;
+
+
+
+/*
+ Parser callbacks
+*/
+void cb_parser_start(servercmd_t *s);
+int  cb_cmd(servercmd_t *s, int cmd);
+int  cb_id(servercmd_t *s, const char *id);
+int  cb_number(servercmd_t *s, const char *id);
+int  cb_hexbyte(servercmd_t *s, int b);
+int  cb_endhex(servercmd_t *s);
+int  cb_separator(servercmd_t *s);
+void cb_parser_end(servercmd_t *s);
+void cb_error(servercmd_t *s, int error, const char *str);
+
+/* helper functions */
+int hexdigit(char d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // servercmd_h
diff --git a/debug-tools/remoteserver/udp_server.cpp b/debug-tools/remoteserver/udp_server.cpp
new file mode 100644
index 0000000..64c161d
--- /dev/null
+++ b/debug-tools/remoteserver/udp_server.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cerrno>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fstream>
+#include "server.h"
+#include "cmdiface.h"
+#include "debug.h"
+#include "pmc_file.h"
+#include "file_reader.h"
+#include "udp_server.h"
+
+const std::string UdpServer::local_host = "127.0.0.1";
+const std::string UdpServer::host_details_file_name = "/etc/wigig_remoteserver_details";
+const std::string UdpServer::cmd_get_host_identity = "GetHostIdentity";
+const std::string UdpServer::cmd_delimiter = ";";
+
+std::string UdpServer::host_broadcast_ip = "";
+std::string UdpServer::host_ip = "";
+std::string UdpServer::host_alias = "";
+int UdpServer::sock_in = 0;
+int UdpServer::sock_out = 0;
+int UdpServer::port_in = 0;
+int UdpServer::port_out = 0;
+
+int UdpServer::SendAll(std::string message)
+{
+    int result = -1;
+
+    struct sockaddr_in dstAddress;
+    dstAddress.sin_family = AF_INET;
+    inet_pton(AF_INET , host_broadcast_ip.c_str(), &dstAddress.sin_addr.s_addr);
+    dstAddress.sin_port = htons(UdpServer::port_out);
+    int messageSize = message.length() * sizeof(char);
+    result = sendto(UdpServer::sock_out, message.c_str(), messageSize, 0, (sockaddr*)&dstAddress, sizeof(dstAddress));
+    LOG_DEBUG << "INFO : sendto with sock_out=" << UdpServer::sock_out << ", message=" << message << " messageSize=" << messageSize << " returned with " << result << std::endl;
+    if (result < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot send udp broadcast message, error " << errno << ": " << strerror(errno)  << std::endl;
+        return -4;
+    }
+
+    return 0;
+}
+
+int UdpServer::HandleRequest(char* buf)
+{
+    if(NULL == buf)
+    {
+        return 0;
+    }
+
+    LOG_DEBUG << "INFO : Client Command: " << PlainStr(buf) << std::endl;
+
+    std::string cmd(buf);
+    std::string answer;
+
+    if (UdpServer::local_host == host_ip)
+    {
+        LOG_DEBUG << "WARNING : There is no support in UDP srevices when using local host" << std::endl;
+        return 0;
+    }
+
+    if (UdpServer::cmd_get_host_identity == cmd)
+    {
+        answer = GetHostDetails();
+    }
+    else
+    {
+        LOG_DEBUG << "ERROR : Unkonwn UDP command" << std::endl;
+    }
+
+    // send back response in broadcast
+    // For the time being, all requests will have broadcast response
+    // All responses will use the same outgoing communication port
+    LOG_DEBUG << "INFO : Answer is: " << PlainStr(answer.c_str()) << std::endl;
+    SendAll(answer);
+
+    return 0;
+}
+
+
+/*
+  Close the server to allow un-bind te socket - allowing future connections without delay
+*/
+int UdpServer::stop()
+{
+    LOG_DEBUG << "INFO : Stopping the UDP server" << std::endl;
+    shutdown(UdpServer::sock_in, SHUT_RDWR);
+    return 0;
+}
+
+/*
+  Initialize UPD server on the given port. The function returns in case of error,
+  otherwise it doesn't return
+*/
+int UdpServer::start(int localUdpPortIn, int remoteUdpPortIn)
+{
+    LOG_DEBUG << "INFO : Starting UDP server on port " << localUdpPortIn << std::endl;
+    LOG_DEBUG << "INFO : Sending broadcast answers to port " << remoteUdpPortIn << std::endl;
+
+    //  open the UDP server on a new thread
+    UdpServer::port_in = localUdpPortIn;
+    UdpServer::port_out = remoteUdpPortIn;
+    pthread_t thread;
+    pthread_create(&thread, 0, start_udp_server, NULL);
+    pthread_detach(thread);
+
+    return 0;
+}
+
+void* UdpServer::start_udp_server(void* unused)
+{
+    (void)unused;
+    if (LoadHostDetails() < 0)
+    {
+        return NULL;
+    }
+
+    // Create outgoing response socket
+    UdpServer::sock_out = socket(AF_INET, SOCK_DGRAM, 0);
+    if (UdpServer::sock_out < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot open udp broadcast outgoing socket" << std::endl;
+        return NULL;
+    }
+
+    int enabled = 1;
+    int result;
+    result = setsockopt(UdpServer::sock_out, SOL_SOCKET, SO_BROADCAST, (char*)&enabled, sizeof(enabled));
+    if (result < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot set broadcast option for udp socket, error " << errno << ": " << strerror(errno) << std::endl;
+        shutdown(UdpServer::sock_out, SHUT_RDWR);
+        return NULL;
+    }
+
+    // Create incoming request socket
+    struct sockaddr_in address;
+    UdpServer::sock_in = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if(UdpServer::sock_in < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot create a socket on port " << UdpServer::port_in << std::endl;
+        return NULL;
+    }
+
+    address.sin_family = AF_INET;
+    address.sin_addr.s_addr = INADDR_ANY;
+    address.sin_port = htons(UdpServer::port_in);
+    // Set the "Re-Use" socket option - allows reconnections after wilserver exit
+    int reuse = 1;
+    setsockopt(UdpServer::sock_in, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
+    if(bind(UdpServer::sock_in, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot bind socket to port " << UdpServer::port_in << ", error " << errno << ": " << strerror(errno)  << std::endl;
+        return NULL;
+    }
+
+    char* buf = new char[MAX_INPUT_BUF];
+
+    do
+    {
+        if (recvfrom(UdpServer::sock_in, buf, MAX_INPUT_BUF, 0, NULL, 0) < 0)
+        {
+            LOG_DEBUG << "ERROR : Cannot listen on port " << UdpServer::port_in << std::endl;
+            return NULL;
+        }
+
+        HandleRequest(buf);
+
+    } while (true);
+
+    LOG_DEBUG << "INFO : UDP server shutdown" << std::endl;
+    return NULL; // Wont get here, just to avoid the warning
+}
+
+bool FindEthernetInterface(struct ifreq& ifr, int& fd)
+{
+    fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if(fd < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot get host and broadcast IPs" << std::endl;
+        return -1;
+    }
+
+    for (int i = 0; i < 100; i++)
+    {
+        snprintf(ifr.ifr_name, IFNAMSIZ-1, "eth%d", i);
+
+        if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+int UdpServer::LoadHostAndBroadcastIps()
+{
+    int fd;
+    struct ifreq ifr;
+
+    ifr.ifr_addr.sa_family = AF_INET; // IP4V
+
+    // Get IP address according to OS
+    if (FindEthernetInterface(ifr, fd))
+    {
+        LOG_INFO << "Linux OS" << std::endl;
+    }
+    else
+    {
+        snprintf(ifr.ifr_name, IFNAMSIZ, "br-lan");
+        if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0)
+        {
+            LOG_INFO << "OpenWRT OS" << std::endl;
+        }
+        else
+        {
+            // Probably Android OS
+            LOG_INFO << "Android OS (no external IP Adress)" << std::endl;
+            host_ip = UdpServer::local_host;
+            host_broadcast_ip = UdpServer::local_host;
+            return 0;
+        }
+    }
+    host_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
+
+    if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
+    {
+        LOG_DEBUG << "ERROR : Cannot get broadcast IP" << std::endl;
+        return -3;
+    }
+    host_broadcast_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
+    LOG_DEBUG << "INFO : " << "host_ip=" << host_ip << std::endl;
+    LOG_DEBUG << "INFO : " << "host_broadcast_ip=" << host_broadcast_ip << std::endl;
+
+    close(fd);
+    return 0;
+}
+
+void UdpServer::LoadHostAlias()
+{
+    std::ifstream infile;
+    infile.open(host_details_file_name.c_str());
+    std::getline(infile, host_alias);
+    infile.close();
+}
+
+int UdpServer::LoadHostDetails()
+{
+    if (LoadHostAndBroadcastIps() < 0)
+    {
+        return -1;
+    }
+    LoadHostAlias();
+    return 0;
+}
diff --git a/debug-tools/remoteserver/udp_server.h b/debug-tools/remoteserver/udp_server.h
new file mode 100644
index 0000000..01855d7
--- /dev/null
+++ b/debug-tools/remoteserver/udp_server.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __udp_server_h
+#define __udp_server_h
+
+class UdpServer
+{
+public:
+    int start(int localUdpPortIn, int remoteUdpPortIn);
+    int stop();
+
+    static int SendAll(std::string message);
+    static std::string GetHostDetails() { return  UdpServer::cmd_get_host_identity + UdpServer::cmd_delimiter + host_ip + UdpServer::cmd_delimiter + host_alias; }
+    static void SetHostAlias(std::string alias) { host_alias = alias; }
+
+    static const std::string host_details_file_name;
+
+private:
+    // members
+    static const std::string local_host;
+    static const std::string cmd_get_host_identity;
+    static const std::string cmd_delimiter;
+    static std::string host_broadcast_ip;
+    static std::string host_ip;
+    static std::string host_alias;
+    static int sock_in;
+    static int sock_out;
+    static int port_in;
+    static int port_out;
+
+    // methods
+    static void* start_udp_server(void* unused);
+    static int LoadHostDetails();
+    static int  LoadHostIp(); // assumption: each host has only one IP address for ethernet interfaces
+    static void LoadHostAlias();
+    static int HandleRequest(char* buf);
+    static int LoadHostAndBroadcastIps();
+};
+
+#endif // udp_server_h