1 /**
2  * Copyright © 2018 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "argument.hpp"
17 #include "ncsi_util.hpp"
18 
19 #include <phosphor-logging/lg2.hpp>
20 
21 #include <string>
22 #include <vector>
23 
24 static void exitWithError(const char* err, char** argv)
25 {
26     phosphor::network::ncsi::ArgumentParser::usage(argv);
27     lg2::error("ERROR: {ERROR}", "ERROR", err);
28     exit(EXIT_FAILURE);
29 }
30 
31 int main(int argc, char** argv)
32 {
33     using namespace phosphor::network;
34     using namespace phosphor::network::ncsi;
35     // Read arguments.
36     auto options = ArgumentParser(argc, argv);
37     int packageInt{};
38     int channelInt{};
39     int indexInt{};
40     int operationInt{DEFAULT_VALUE};
41 
42     // Parse out interface argument.
43     auto ifIndex = (options)["index"];
44     try
45     {
46         indexInt = stoi(ifIndex, nullptr);
47     }
48     catch (const std::exception& e)
49     {
50         exitWithError("Interface not specified.", argv);
51     }
52 
53     if (indexInt < 0)
54     {
55         exitWithError("Interface value should be greater than equal to 0",
56                       argv);
57     }
58 
59     // Parse out package argument.
60     auto package = (options)["package"];
61     try
62     {
63         packageInt = stoi(package, nullptr);
64     }
65     catch (const std::exception& e)
66     {
67         packageInt = DEFAULT_VALUE;
68     }
69 
70     if (packageInt < 0)
71     {
72         packageInt = DEFAULT_VALUE;
73     }
74 
75     // Parse out channel argument.
76     auto channel = (options)["channel"];
77     try
78     {
79         channelInt = stoi(channel, nullptr);
80     }
81     catch (const std::exception& e)
82     {
83         channelInt = DEFAULT_VALUE;
84     }
85 
86     if (channelInt < 0)
87     {
88         channelInt = DEFAULT_VALUE;
89     }
90 
91     auto payloadStr = (options)["oem-payload"];
92     if (!payloadStr.empty())
93     {
94         std::string byte(2, '\0');
95         std::vector<unsigned char> payload;
96 
97         if (payloadStr.size() % 2)
98             exitWithError("Payload invalid: specify two hex digits per byte.",
99                           argv);
100 
101         // Parse the payload string (e.g. "50000001572100") to byte data
102         // The first two characters (i.e. "50") represent the Send Cmd Operation
103         // All remaining pairs, interpreted in hex radix, represent the command
104         // payload
105         int sendCmdSelect{};
106         for (unsigned int i = 1; i < payloadStr.size(); i += 2)
107         {
108             byte[0] = payloadStr[i - 1];
109             byte[1] = payloadStr[i];
110 
111             try
112             {
113                 sendCmdSelect = stoi(byte, nullptr, 16);
114             }
115             catch (const std::exception& e)
116             {
117                 exitWithError("Payload invalid.", argv);
118             }
119             if (i == 1)
120             {
121                 operationInt = sendCmdSelect;
122             }
123             else
124             {
125                 payload.push_back(sendCmdSelect);
126             }
127         }
128 
129         if (operationInt == DEFAULT_VALUE)
130         {
131             exitWithError("No payload specified.", argv);
132         }
133 
134         if (packageInt == DEFAULT_VALUE)
135         {
136             exitWithError("Package not specified.", argv);
137         }
138 
139         return ncsi::sendOemCommand(
140             indexInt, packageInt, channelInt, operationInt,
141             std::span<const unsigned char>(payload.begin(), payload.end()));
142     }
143     else if ((options)["set"] == "true")
144     {
145         // Can not perform set operation without package.
146         if (packageInt == DEFAULT_VALUE)
147         {
148             exitWithError("Package not specified.", argv);
149         }
150         return ncsi::setChannel(indexInt, packageInt, channelInt);
151     }
152     else if ((options)["info"] == "true")
153     {
154         return ncsi::getInfo(indexInt, packageInt);
155     }
156     else if ((options)["clear"] == "true")
157     {
158         return ncsi::clearInterface(indexInt);
159     }
160     else if (!(options)["pmask"].empty())
161     {
162         unsigned int mask{};
163         try
164         {
165             size_t lastChar{};
166             mask = std::stoul((options)["pmask"], &lastChar, 0);
167             if (lastChar < (options["pmask"].size()))
168             {
169                 exitWithError("Package mask value is not valid", argv);
170             }
171         }
172         catch (const std::exception& e)
173         {
174             exitWithError("Package mask value is not valid", argv);
175         }
176         return ncsi::setPackageMask(indexInt, mask);
177     }
178     else if (!(options)["cmask"].empty())
179     {
180         if (packageInt == DEFAULT_VALUE)
181         {
182             exitWithError("Package is not specified", argv);
183         }
184         unsigned int mask{};
185         try
186         {
187             size_t lastChar{};
188             mask = stoul((options)["cmask"], &lastChar, 0);
189             if (lastChar < (options["cmask"].size()))
190             {
191                 exitWithError("Channel mask value is not valid", argv);
192             }
193         }
194         catch (const std::exception& e)
195         {
196             exitWithError("Channel mask value is not valid", argv);
197         }
198         return ncsi::setChannelMask(indexInt, packageInt, mask);
199     }
200     else
201     {
202         exitWithError("No Command specified", argv);
203     }
204     return 0;
205 }
206