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/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)
+{
+}