• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
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 
17 #include <android-base/logging.h>
18 #include <android-base/parsedouble.h>
19 #include <android-base/parseint.h>
20 #include <gflags/gflags.h>
21 
22 #include <cstdlib>
23 #include <functional>
24 #include <iomanip>
25 #include <iostream>
26 #include <string>
27 #include <unordered_map>
28 #include <vector>
29 
30 #include "host/libs/config/cuttlefish_config.h"
31 #include "host/libs/wmediumd_controller/wmediumd_api_protocol.h"
32 #include "host/libs/wmediumd_controller/wmediumd_controller.h"
33 
34 const std::string usageMessage =
35     "wmediumd control commandline utility\n\n"
36     "  Usage: wmediumd_control [option] command [args...]\n\n"
37     "  Commands:\n\n"
38     "    set_snr mac1 mac2 snr\n"
39     "      set SNR between two nodes. (0 <= snr <= 255)\n\n"
40     "    reload_config [path]\n"
41     "      force reload wmediumd configuration file\n\n"
42     "      if path is not specified, reload current configuration file\n\n"
43     "    start_pcap path\n"
44     "      start packet capture and save capture result to file.\n"
45     "      file format is pcap capture format.\n\n"
46     "    stop_pcap\n"
47     "      stop packet capture\n\n"
48     "    list_stations\n"
49     "      listing stations connected to wmediumd\n\n"
50     "    set_position mac xpos ypos\n"
51     "      set X, Y positions of specific station\n"
52     "      use -- before set_position if you want to set the position with "
53     "negative values\n"
54     "        e.g. wmediumd_control -- set_position 42:00:00:00:00:00 -1.0 "
55     "-2.0\n\n"
56     "    set_lci mac lci\n"
57     "      set LCI (latitude, longitude, altitude) of the specific station\n"
58     "      it's free-form string and may not match with other location nor"
59     "position information\n\n"
60     "    set_civicloc mac civicloc\n"
61     "      set CIVIC location (e.g. postal address) of the specific station\n"
62     "      it's free-form string and may not match with other location nor"
63     "position information\n";
64 
65 DEFINE_string(wmediumd_api_server, "",
66               "Unix socket path of wmediumd api server");
67 
HandleSetSnrCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)68 bool HandleSetSnrCommand(cuttlefish::WmediumdController& client,
69                          const std::vector<std::string>& args) {
70   if (args.size() != 4) {
71     LOG(ERROR) << "error: set_snr must provide 3 options";
72     return false;
73   }
74 
75   if (!cuttlefish::ValidMacAddr(args[1])) {
76     LOG(ERROR) << "error: invalid mac address " << args[1];
77     return false;
78   }
79 
80   if (!cuttlefish::ValidMacAddr(args[2])) {
81     LOG(ERROR) << "error: invalid mac address " << args[2];
82     return false;
83   }
84 
85   uint8_t snr = 0;
86 
87   auto parseResult =
88       android::base::ParseUint<decltype(snr)>(args[3].c_str(), &snr);
89 
90   if (!parseResult) {
91     if (errno == EINVAL) {
92       LOG(ERROR) << "error: cannot parse snr: " << args[3];
93     } else if (errno == ERANGE) {
94       LOG(ERROR) << "error: snr exceeded range: " << args[3];
95     }
96 
97     return false;
98   }
99 
100   if (!client.SetSnr(args[1], args[2], snr)) {
101     return false;
102   }
103 
104   return true;
105 }
106 
HandleReloadConfigCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)107 bool HandleReloadConfigCommand(cuttlefish::WmediumdController& client,
108                                const std::vector<std::string>& args) {
109   if (args.size() > 2) {
110     LOG(ERROR) << "error: reload_config must provide 0 or 1 option";
111     return false;
112   }
113 
114   if (args.size() == 2) {
115     return client.ReloadConfig(args[1]);
116   } else {
117     return client.ReloadCurrentConfig();
118   }
119 }
120 
HandleStartPcapCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)121 bool HandleStartPcapCommand(cuttlefish::WmediumdController& client,
122                             const std::vector<std::string>& args) {
123   if (args.size() != 2) {
124     LOG(ERROR) << "error: you must provide only 1 option(path)";
125     return false;
126   }
127 
128   return client.StartPcap(args[1]);
129 }
130 
HandleStopPcapCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)131 bool HandleStopPcapCommand(cuttlefish::WmediumdController& client,
132                            const std::vector<std::string>& args) {
133   if (args.size() != 1) {
134     LOG(ERROR) << "error: you must not provide option";
135     return false;
136   }
137 
138   return client.StopPcap();
139 }
140 
HandleListStationsCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)141 bool HandleListStationsCommand(cuttlefish::WmediumdController& client,
142                                const std::vector<std::string>& args) {
143   if (args.size() != 1) {
144     LOG(ERROR) << "error: you must not provide option";
145     return false;
146   }
147 
148   auto result = client.GetStations();
149 
150   if (!result) {
151     LOG(ERROR) << "error: failed to get stations";
152     return false;
153   }
154 
155   auto stationList = result->GetStations();
156 
157   std::cout << "Total stations : " << stationList.size() << std::endl
158             << std::endl;
159   std::cout << "Mac Address      "
160             << "\t"
161             << "X Pos"
162             << "\t"
163             << "Y Pos"
164             << "\t"
165             << "LCI"
166             << "\t"
167             << "CIVICLOC"
168             << "\t"
169             << "TX Power" << std::endl;
170 
171   for (auto& station : stationList) {
172     std::cout << cuttlefish::MacToString(station.addr) << "\t"
173               << std::setprecision(1) << std::fixed << station.x << "\t"
174               << std::setprecision(1) << std::fixed << station.y << "\t\""
175               << station.lci << "\"\t\"" << station.civicloc << "\"\t"
176               << station.tx_power << std::endl;
177   }
178 
179   std::cout << std::endl;
180 
181   return true;
182 }
183 
HandleSetPositionCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)184 bool HandleSetPositionCommand(cuttlefish::WmediumdController& client,
185                               const std::vector<std::string>& args) {
186   if (args.size() != 4) {
187     LOG(ERROR) << "error: set_position must provide 3 options";
188     return false;
189   }
190 
191   if (!cuttlefish::ValidMacAddr(args[1])) {
192     LOG(ERROR) << "error: invalid mac address " << args[1];
193     return false;
194   }
195 
196   double x = 0;
197   double y = 0;
198 
199   auto parseResultX = android::base::ParseDouble(args[2].c_str(), &x);
200   auto parseResultY = android::base::ParseDouble(args[3].c_str(), &y);
201 
202   if (!parseResultX) {
203     LOG(ERROR) << "error: cannot parse X: " << args[2];
204     return false;
205   }
206 
207   if (!parseResultY) {
208     LOG(ERROR) << "error: cannot parse Y: " << args[3];
209     return false;
210   }
211 
212   if (!client.SetPosition(args[1], x, y)) {
213     return false;
214   }
215 
216   return true;
217 }
218 
HandleSetLciCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)219 bool HandleSetLciCommand(cuttlefish::WmediumdController& client,
220                          const std::vector<std::string>& args) {
221   if (args.size() != 3) {
222     LOG(ERROR) << "error: set_lci must provide 2 options";
223     return false;
224   }
225 
226   if (!cuttlefish::ValidMacAddr(args[1])) {
227     LOG(ERROR) << "error: invalid mac address " << args[1];
228     return false;
229   }
230 
231   if (!client.SetLci(args[1], args[2])) {
232     return false;
233   }
234 
235   return true;
236 }
237 
HandleSetCiviclocCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)238 bool HandleSetCiviclocCommand(cuttlefish::WmediumdController& client,
239                               const std::vector<std::string>& args) {
240   if (args.size() != 3) {
241     LOG(ERROR) << "error: set_civicloc must provide 2 options";
242     return false;
243   }
244 
245   if (!cuttlefish::ValidMacAddr(args[1])) {
246     LOG(ERROR) << "error: invalid mac address " << args[1];
247     return false;
248   }
249 
250   if (!client.SetCivicloc(args[1], args[2])) {
251     return false;
252   }
253 
254   return true;
255 }
256 
main(int argc,char ** argv)257 int main(int argc, char** argv) {
258   gflags::SetUsageMessage(usageMessage);
259   gflags::ParseCommandLineFlags(&argc, &argv, true);
260 
261   std::vector<std::string> args;
262 
263   for (int i = 1; i < argc; ++i) {
264     args.push_back(argv[i]);
265   }
266 
267   if (args.size() == 0) {
268     LOG(ERROR) << "error: you must provide at least 1 argument";
269     gflags::ShowUsageWithFlags(argv[0]);
270     return -1;
271   }
272 
273   std::string wmediumdApiServerPath(FLAGS_wmediumd_api_server);
274 
275   if (wmediumdApiServerPath == "") {
276     const auto cuttlefishConfig = cuttlefish::CuttlefishConfig::Get();
277 
278     if (!cuttlefishConfig) {
279       LOG(ERROR) << "error: cannot get global cuttlefish config";
280       return -1;
281     }
282 
283     wmediumdApiServerPath = cuttlefishConfig->wmediumd_api_server_socket();
284   }
285 
286   auto client = cuttlefish::WmediumdController::New(wmediumdApiServerPath);
287 
288   if (!client) {
289     LOG(ERROR) << "error: cannot connect to " << wmediumdApiServerPath;
290     return -1;
291   }
292 
293   auto commandMap =
294       std::unordered_map<std::string,
295                          std::function<bool(cuttlefish::WmediumdController&,
296                                             const std::vector<std::string>&)>>{
297           {{"set_snr", HandleSetSnrCommand},
298            {"reload_config", HandleReloadConfigCommand},
299            {"start_pcap", HandleStartPcapCommand},
300            {"stop_pcap", HandleStopPcapCommand},
301            {"list_stations", HandleListStationsCommand},
302            {"set_position", HandleSetPositionCommand},
303            {"set_lci", HandleSetLciCommand},
304            {"set_civicloc", HandleSetCiviclocCommand}}};
305 
306   if (commandMap.find(args[0]) == std::end(commandMap)) {
307     LOG(ERROR) << "error: command " << args[0] << " does not exist";
308     gflags::ShowUsageWithFlags(argv[0]);
309     return -1;
310   }
311 
312   if (!commandMap[args[0]](*client, args)) {
313     LOG(ERROR) << "error: failed to execute command " << args[0];
314     return -1;
315   }
316 
317   return 0;
318 }
319