PLDMTOOL: Implement raw option in the pldmtool

raw option enables user sending raw bytes and printing response

HELP OUTPUT:
root@witherspoon-128:/tmp# ./pldmtool -h
PLDM requester tool for OpenBMC
Usage: ./pldmtool [OPTIONS] [—command...] [raw] [GetPLDMTypes] [GetPLDMVersion] [SUBCOMMAND]

Positionals:
  —command TEXT ...           PLDM request command
  raw TEXT                    Send a RAW PLDM request and print response
  GetPLDMTypes TEXT           Get PLDM Type
  GetPLDMVersion TEXT         Get PLDM Version

Options:
  -h,--help                   Print this help message and exit
  -c TEXT ...                   PLDM request command

Subcommands:
  BASE                        PLDM Command Type = BASE
  BIOS                        PLDM Command Type = BIOS
  OEM                         PLDM Command Type = OEM

Currently option to be given as raw instead of --raw because
of bug in the CLI11 :
FIX: required positional arguments and a vector positionals #306

pldm_set_state_effecter_states:
root@witherspoon-128:/tmp# ./pldmtool raw 0x80 0x02 0x39 0x00 0x01 0x00 0x01 0x09
Request Message
08 01 80 02 39 00 01 00 01 09
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 10
Total length:10
Loopback response message:
08 01 80 02 39 00 01 00 01 09
On first recv(),response == request : RC = 0
Total length: 6
Shutdown Socket successful :  RC = 0
Socket recv() successful : RC = 0
Response Message:
08 01 00 02 39 00

GetPLDMVersion:
./pldmtool raw 0x80 0x00 0x03 0x00 0x00 0x00 0x00 0x01 0x00
Request Message
08 01 80 00 03 00 00 00 00 01 00
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 11
Total length:11
Loopback response message:
08 01 80 00 03 00 00 00 00 01 00
On first recv(),response == request : RC = 0
Total length: 15
Shutdown Socket successful :  RC = 0
Socket recv() successful : RC = 0
Response Message:
08 01 00 00 03 00 00 00 00 00 05 f1 f0 f0 00

Signed-off-by: Lakshminarayana R. Kammath <lkammath@in.ibm.com>
Change-Id: I4057108444db8f8809f4310e1ffbb0565adbbf3c
diff --git a/tool/pldm_base_cmd.cpp b/tool/pldm_base_cmd.cpp
index 3ebd123..b203423 100644
--- a/tool/pldm_base_cmd.cpp
+++ b/tool/pldm_base_cmd.cpp
@@ -70,6 +70,7 @@
     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
                                     PLDM_GET_VERSION_REQ_BYTES);
     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
     uint8_t pldmType = 0x0;
 
     if (!args[1].c_str())
@@ -132,3 +133,112 @@
         return;
     }
 }
+
+/*
+ * Main function that handles the PLDM raw command response callback via mctp
+ *
+ */
+void handleRawOp(vector<std::string>&& args)
+{
+    // Minimu 3 bytes of header data needs to passed. else its a invalid request
+    if (size(args) < 3)
+    {
+        cerr << "Not enough arguments passed."
+                " Minimum, need to pass PLDM header raw data"
+             << endl;
+        return;
+    }
+
+    // Create a request packet and initialize it
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+    requestMsg.clear();
+
+    // Read the raw data passed in the command line
+    // Form request message from the raw data passed
+    for (auto&& rawByte : args)
+    {
+        requestMsg.insert(requestMsg.end(), stoi(rawByte, nullptr, 16));
+    }
+
+    // Validating the payload raw data based on pldm command type
+    uint8_t pldmCmd = requestMsg[2];
+    switch (pldmCmd)
+    {
+        case PLDM_GET_PLDM_VERSION:
+            if (size(requestMsg) !=
+                (sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES))
+            {
+                cerr << "Not enough raw data provided." << endl;
+                cerr << "Total length can be = 3 bytes of header + 6 bytes"
+                        " for payload. Please refer spec for details"
+                     << endl;
+                return;
+            }
+            break;
+        case PLDM_GET_TID:
+        case PLDM_GET_PLDM_TYPES:
+            if (size(requestMsg) != sizeof(pldm_msg_hdr))
+            {
+                cerr << "Total length can be = 3 bytes of header + 0 bytes"
+                        " for payload. Please refer spec for details"
+                     << endl;
+                return;
+            }
+            break;
+        case PLDM_GET_PLDM_COMMANDS:
+            if (size(requestMsg) !=
+                sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES)
+            {
+                cerr << "Total length can be = 3 bytes of header + 5 bytes"
+                        " for payload. Please refer spec for details"
+                     << endl;
+                return;
+            }
+            break;
+        case PLDM_SET_STATE_EFFECTER_STATES:
+            // payload size depends on comp_effecter_count
+            // if count=1 then, request size will be 8 bytes including header
+            // if count=9 then, request size will be 19 bytes including header
+            if ((size(requestMsg) < 8) ||
+                (size(requestMsg) >
+                 sizeof(pldm_msg_hdr) +
+                     PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES))
+            {
+                cerr << "Total length can be = 3 bytes of header + min/max 8/19"
+                        " bytes for payload. Please refer spec for details"
+                     << endl;
+                return;
+            }
+            break;
+        default:
+            cerr << "Command Not supported/implemented : " << args[2] << endl;
+            cerr << "Contact backend Team" << endl;
+            return;
+    }
+
+    // Add the MCTP type and PLDM entity id at the end
+    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
+    requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
+
+    cout << "Request Message" << endl;
+    printBuffer(requestMsg);
+
+    // Create the response message
+    vector<uint8_t> responseMsg;
+
+    // Compares the response with request packet on first socket recv() call.
+    // If above condition is qualified then, reads the actual response from
+    // the socket to output buffer responseMsg.
+    int returnCode = mctpSockSendRecv(requestMsg, responseMsg);
+    if (!returnCode)
+    {
+        cout << "Socket recv() successful : RC = " << returnCode << endl;
+        cout << "Response Message:" << endl;
+        printBuffer(responseMsg);
+    }
+    else
+    {
+        cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
+        return;
+    }
+}