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 "wmediumd_api_protocol.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/strings.h>
21
22 #include <cstdlib>
23 #include <iomanip>
24 #include <iostream>
25 #include <string>
26 #include <vector>
27
28 #include "common/libs/fs/shared_buf.h"
29
30 #define MAC_ADDR_LEN 6
31 #define STR_MAC_ADDR_LEN 17
32
33 template <class T>
AppendBinaryRepresentation(std::string & buf,const T & data)34 static void AppendBinaryRepresentation(std::string& buf, const T& data) {
35 std::copy(reinterpret_cast<const char*>(&data),
36 reinterpret_cast<const char*>(&data) + sizeof(T),
37 std::back_inserter(buf));
38 }
39
ParseMacAddress(const std::string & macAddr)40 static std::array<uint8_t, 6> ParseMacAddress(const std::string& macAddr) {
41 if (!cuttlefish::ValidMacAddr(macAddr)) {
42 LOG(FATAL) << "invalid mac address " << macAddr;
43 }
44
45 auto split_mac = android::base::Split(macAddr, ":");
46 std::array<uint8_t, 6> mac;
47 for (int i = 0; i < 6; i++) {
48 char* end_ptr;
49 mac[i] = (uint8_t)strtol(split_mac[i].c_str(), &end_ptr, 16);
50 }
51
52 return mac;
53 }
54
55 namespace cuttlefish {
56
ValidMacAddr(const std::string & macAddr)57 bool ValidMacAddr(const std::string& macAddr) {
58 if (macAddr.size() != STR_MAC_ADDR_LEN) {
59 return false;
60 }
61
62 if (macAddr[2] != ':' || macAddr[5] != ':' || macAddr[8] != ':' ||
63 macAddr[11] != ':' || macAddr[14] != ':') {
64 return false;
65 }
66
67 for (int i = 0; i < STR_MAC_ADDR_LEN; ++i) {
68 if ((i - 2) % 3 == 0) continue;
69 char c = macAddr[i];
70
71 if (isupper(c)) {
72 c = tolower(c);
73 }
74
75 if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
76 }
77
78 return true;
79 }
80
MacToString(const char * macAddr)81 std::string MacToString(const char* macAddr) {
82 std::stringstream result;
83
84 for (int i = 0; i < MAC_ADDR_LEN; i++) {
85 result << std::setfill('0') << std::setw(2) << std::right << std::hex
86 << static_cast<int>(static_cast<uint8_t>(macAddr[i]));
87
88 if (i != 5) {
89 result << ":";
90 }
91 }
92
93 return result.str();
94 }
95
Serialize(void) const96 std::string WmediumdMessage::Serialize(void) const {
97 std::string result;
98
99 AppendBinaryRepresentation(result, this->Type());
100
101 std::string body;
102 this->SerializeBody(body);
103
104 AppendBinaryRepresentation(result, static_cast<uint32_t>(body.size()));
105
106 std::copy(std::begin(body), std::end(body), std::back_inserter(result));
107
108 return result;
109 }
110
SerializeBody(std::string & buf) const111 void WmediumdMessageSetControl::SerializeBody(std::string& buf) const {
112 AppendBinaryRepresentation(buf, flags_);
113 }
114
WmediumdMessageSetSnr(const std::string & node1,const std::string & node2,uint8_t snr)115 WmediumdMessageSetSnr::WmediumdMessageSetSnr(const std::string& node1,
116 const std::string& node2,
117 uint8_t snr) {
118 node1_mac_ = ParseMacAddress(node1);
119 node2_mac_ = ParseMacAddress(node2);
120 snr_ = snr;
121 }
122
SerializeBody(std::string & buf) const123 void WmediumdMessageSetSnr::SerializeBody(std::string& buf) const {
124 std::copy(std::begin(node1_mac_), std::end(node1_mac_),
125 std::back_inserter(buf));
126 std::copy(std::begin(node2_mac_), std::end(node2_mac_),
127 std::back_inserter(buf));
128 buf.push_back(snr_);
129 }
130
SerializeBody(std::string & buf) const131 void WmediumdMessageReloadConfig::SerializeBody(std::string& buf) const {
132 std::copy(std::begin(config_path_), std::end(config_path_),
133 std::back_inserter(buf));
134 buf.push_back('\0');
135 }
136
SerializeBody(std::string & buf) const137 void WmediumdMessageStartPcap::SerializeBody(std::string& buf) const {
138 std::copy(std::begin(pcap_path_), std::end(pcap_path_),
139 std::back_inserter(buf));
140 buf.push_back('\0');
141 }
142
WmediumdMessageSetPosition(const std::string & node,double x,double y)143 WmediumdMessageSetPosition::WmediumdMessageSetPosition(const std::string& node,
144 double x, double y) {
145 mac_ = ParseMacAddress(node);
146 x_ = x;
147 y_ = y;
148 }
149
SerializeBody(std::string & buf) const150 void WmediumdMessageSetPosition::SerializeBody(std::string& buf) const {
151 std::copy(std::begin(mac_), std::end(mac_), std::back_inserter(buf));
152 AppendBinaryRepresentation(buf, x_);
153 AppendBinaryRepresentation(buf, y_);
154 }
155
WmediumdMessageSetLci(const std::string & node,const std::string & lci)156 WmediumdMessageSetLci::WmediumdMessageSetLci(const std::string& node,
157 const std::string& lci) {
158 mac_ = ParseMacAddress(node);
159 lci_ = lci;
160 }
161
SerializeBody(std::string & buf) const162 void WmediumdMessageSetLci::SerializeBody(std::string& buf) const {
163 std::copy(std::begin(mac_), std::end(mac_), std::back_inserter(buf));
164 std::copy(std::begin(lci_), std::end(lci_), std::back_inserter(buf));
165 buf.push_back('\0');
166 }
167
WmediumdMessageSetCivicloc(const std::string & node,const std::string & civicloc)168 WmediumdMessageSetCivicloc::WmediumdMessageSetCivicloc(
169 const std::string& node, const std::string& civicloc) {
170 mac_ = ParseMacAddress(node);
171 civicloc_ = civicloc;
172 }
173
SerializeBody(std::string & buf) const174 void WmediumdMessageSetCivicloc::SerializeBody(std::string& buf) const {
175 std::copy(std::begin(mac_), std::end(mac_), std::back_inserter(buf));
176 std::copy(std::begin(civicloc_), std::end(civicloc_),
177 std::back_inserter(buf));
178 buf.push_back('\0');
179 }
180
Parse(const WmediumdMessageReply & reply)181 std::optional<WmediumdMessageStationsList> WmediumdMessageStationsList::Parse(
182 const WmediumdMessageReply& reply) {
183 size_t pos = 0;
184 size_t dataSize = reply.Size();
185 auto data = reply.Data();
186
187 if (reply.Type() != WmediumdMessageType::kStationsList) {
188 LOG(FATAL) << "expected reply type "
189 << static_cast<uint32_t>(WmediumdMessageType::kStationsList)
190 << ", got " << static_cast<uint32_t>(reply.Type()) << std::endl;
191 }
192
193 WmediumdMessageStationsList result;
194
195 if (pos + sizeof(uint32_t) > dataSize) {
196 LOG(ERROR) << "invalid response size";
197 return std::nullopt;
198 }
199
200 uint32_t count = *reinterpret_cast<const uint32_t*>(data + pos);
201 pos += sizeof(uint32_t);
202
203 for (uint32_t i = 0; i < count; ++i) {
204 if (pos + sizeof(wmediumd_station_info) > dataSize) {
205 LOG(ERROR) << "invalid response size";
206 return std::nullopt;
207 }
208
209 const wmediumd_station_info* station =
210 reinterpret_cast<const wmediumd_station_info*>(data + pos);
211 std::string lci((char*)station + station->lci_offset);
212 std::string civicloc((char*)station + station->civicloc_offset);
213 result.station_list_.emplace_back(station->addr, station->hwaddr,
214 station->x, station->y, lci, civicloc,
215 station->tx_power);
216 pos += sizeof(wmediumd_station_info);
217 }
218
219 return result;
220 }
221
222 } // namespace cuttlefish
223