• 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/parseint.h>
19 #include <gflags/gflags.h>
20 
21 #include <cstdlib>
22 #include <functional>
23 #include <iomanip>
24 #include <iostream>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28 
29 #include "host/libs/config/cuttlefish_config.h"
30 #include "host/libs/wmediumd_controller/wmediumd_controller.h"
31 
32 const std::string usageMessage =
33     "wmediumd control commandline utility\n\n"
34     "  Usage: wmediumd_control [option] command [args...]\n\n"
35     "  Commands:\n\n"
36     "    set_snr mac1 mac2 snr\n"
37     "      set SNR between two nodes. (0 <= snr <= 255)\n\n"
38     "    reload_config [path]\n"
39     "      force reload wmediumd configuration file\n\n"
40     "      if path is not specified, reload current configuration file\n\n"
41     "    start_pcap path\n"
42     "      start packet capture and save capture result to file.\n"
43     "      file format is pcap capture format.\n\n"
44     "    stop_pcap\n"
45     "      stop packet capture\n\n"
46     "    list_stations\n"
47     "      listing stations connected to wmediumd\n\n";
48 
49 DEFINE_string(wmediumd_api_server, "",
50               "Unix socket path of wmediumd api server");
51 
52 const int kMacAddrStringSize = 17;
53 
ValidMacAddr(const std::string & macAddr)54 bool ValidMacAddr(const std::string& macAddr) {
55   if (macAddr.size() != kMacAddrStringSize) {
56     return false;
57   }
58 
59   if (macAddr[2] != ':' || macAddr[5] != ':' || macAddr[8] != ':' ||
60       macAddr[11] != ':' || macAddr[14] != ':') {
61     return false;
62   }
63 
64   for (int i = 0; i < kMacAddrStringSize; ++i) {
65     if ((i - 2) % 3 == 0) continue;
66     char c = macAddr[i];
67 
68     if (isupper(c)) {
69       c = tolower(c);
70     }
71 
72     if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
73   }
74 
75   return true;
76 }
77 
MacToString(const char * macAddr)78 std::string MacToString(const char* macAddr) {
79   std::stringstream result;
80 
81   for (int i = 0; i < ETH_ALEN; i++) {
82     result << std::setfill('0') << std::setw(2) << std::right << std::hex
83            << static_cast<int>(static_cast<uint8_t>(macAddr[i]));
84 
85     if (i != 5) {
86       result << ":";
87     }
88   }
89 
90   return result.str();
91 }
92 
HandleSetSnrCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)93 bool HandleSetSnrCommand(cuttlefish::WmediumdController& client,
94                          const std::vector<std::string>& args) {
95   if (args.size() != 4) {
96     LOG(ERROR) << "error: set_snr must provide 3 options";
97     return false;
98   }
99 
100   if (!ValidMacAddr(args[1])) {
101     LOG(ERROR) << "error: invalid mac address " << args[1];
102     return false;
103   }
104 
105   if (!ValidMacAddr(args[2])) {
106     LOG(ERROR) << "error: invalid mac address " << args[2];
107     return false;
108   }
109 
110   uint8_t snr = 0;
111 
112   auto parseResult =
113       android::base::ParseUint<decltype(snr)>(args[3].c_str(), &snr);
114 
115   if (!parseResult) {
116     if (errno == EINVAL) {
117       LOG(ERROR) << "error: cannot parse snr: " << args[3];
118     } else if (errno == ERANGE) {
119       LOG(ERROR) << "error: snr exceeded range: " << args[3];
120     }
121 
122     return false;
123   }
124 
125   if (!client.SetSnr(args[1], args[2], snr)) {
126     return false;
127   }
128 
129   return true;
130 }
131 
HandleReloadConfigCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)132 bool HandleReloadConfigCommand(cuttlefish::WmediumdController& client,
133                                const std::vector<std::string>& args) {
134   if (args.size() > 2) {
135     LOG(ERROR) << "error: reload_config must provide 0 or 1 option";
136     return false;
137   }
138 
139   if (args.size() == 2) {
140     return client.ReloadConfig(args[1]);
141   } else {
142     return client.ReloadCurrentConfig();
143   }
144 }
145 
HandleStartPcapCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)146 bool HandleStartPcapCommand(cuttlefish::WmediumdController& client,
147                             const std::vector<std::string>& args) {
148   if (args.size() != 2) {
149     LOG(ERROR) << "error: you must provide only 1 option(path)";
150     return false;
151   }
152 
153   return client.StartPcap(args[1]);
154 }
155 
HandleStopPcapCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)156 bool HandleStopPcapCommand(cuttlefish::WmediumdController& client,
157                            const std::vector<std::string>& args) {
158   if (args.size() != 1) {
159     LOG(ERROR) << "error: you must not provide option";
160     return false;
161   }
162 
163   return client.StopPcap();
164 }
165 
HandleListStationsCommand(cuttlefish::WmediumdController & client,const std::vector<std::string> & args)166 bool HandleListStationsCommand(cuttlefish::WmediumdController& client,
167                                const std::vector<std::string>& args) {
168   if (args.size() != 1) {
169     LOG(ERROR) << "error: you must not provide option";
170     return false;
171   }
172 
173   auto result = client.GetStations();
174 
175   if (!result) {
176     LOG(ERROR) << "error: failed to get stations";
177     return false;
178   }
179 
180   auto stationList = result->GetStations();
181 
182   std::cout << "Total stations : " << stationList.size() << std::endl
183             << std::endl;
184   std::cout << "Mac Address      "
185             << "\t"
186             << "X Pos"
187             << "\t"
188             << "Y Pos"
189             << "\t"
190             << "TX Power" << std::endl;
191 
192   for (auto& station : stationList) {
193     std::cout << MacToString(station.addr) << "\t" << std::setprecision(1)
194               << std::fixed << station.x << "\t" << std::setprecision(1)
195               << std::fixed << station.y << "\t" << station.tx_power
196               << std::endl;
197   }
198 
199   std::cout << std::endl;
200 
201   return true;
202 }
203 
main(int argc,char ** argv)204 int main(int argc, char** argv) {
205   gflags::SetUsageMessage(usageMessage);
206   gflags::ParseCommandLineFlags(&argc, &argv, true);
207 
208   std::vector<std::string> args;
209 
210   for (int i = 1; i < argc; ++i) {
211     args.push_back(argv[i]);
212   }
213 
214   if (args.size() == 0) {
215     LOG(ERROR) << "error: you must provide at least 1 argument";
216     gflags::ShowUsageWithFlags(argv[0]);
217     return -1;
218   }
219 
220   std::string wmediumdApiServerPath(FLAGS_wmediumd_api_server);
221 
222   if (wmediumdApiServerPath == "") {
223     const auto cuttlefishConfig = cuttlefish::CuttlefishConfig::Get();
224 
225     if (!cuttlefishConfig) {
226       LOG(ERROR) << "error: cannot get global cuttlefish config";
227       return -1;
228     }
229 
230     wmediumdApiServerPath = cuttlefishConfig->wmediumd_api_server_socket();
231   }
232 
233   auto client = cuttlefish::WmediumdController::New(wmediumdApiServerPath);
234 
235   if (!client) {
236     LOG(ERROR) << "error: cannot connect to " << wmediumdApiServerPath;
237     return -1;
238   }
239 
240   auto commandMap =
241       std::unordered_map<std::string,
242                          std::function<bool(cuttlefish::WmediumdController&,
243                                             const std::vector<std::string>&)>>{{
244           {"set_snr", HandleSetSnrCommand},
245           {"reload_config", HandleReloadConfigCommand},
246           {"start_pcap", HandleStartPcapCommand},
247           {"stop_pcap", HandleStopPcapCommand},
248           {"list_stations", HandleListStationsCommand},
249       }};
250 
251   if (commandMap.find(args[0]) == std::end(commandMap)) {
252     LOG(ERROR) << "error: command " << args[0] << " does not exist";
253     gflags::ShowUsageWithFlags(argv[0]);
254     return -1;
255   }
256 
257   if (!commandMap[args[0]](*client, args)) {
258     LOG(ERROR) << "error: failed to execute command " << args[0];
259     return -1;
260   }
261 
262   return 0;
263 }
264