1 /* 2 * Copyright (C) 2018 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 "common/commands/wifi_relay/mac80211_hwsim.h" 18 19 #include "common/commands/wifi_relay/mac80211_hwsim_driver.h" 20 21 #include <glog/logging.h> 22 #include <netlink/genl/ctrl.h> 23 #include <netlink/genl/genl.h> 24 #include <signal.h> 25 #include <sys/uio.h> 26 #include <gflags/gflags.h> 27 28 DEFINE_string( 29 pcap, "", "Path to save a pcap file of packets"); 30 31 static constexpr char kWifiSimFamilyName[] = "MAC80211_HWSIM"; 32 static constexpr char kNl80211FamilyName[] = "nl80211"; 33 34 static constexpr uint32_t kSignalLevelDefault = -24; 35 36 #if !defined(ETH_ALEN) 37 static constexpr size_t ETH_ALEN = 6; 38 #endif 39 40 namespace { 41 42 struct pcap_hdr_t { 43 uint32_t magic_number; /* magic number */ 44 uint16_t version_major; /* major version number */ 45 uint16_t version_minor; /* minor version number */ 46 int32_t thiszone; /* GMT to local correction */ 47 uint32_t sigfigs; /* accuracy of timestamps */ 48 uint32_t snaplen; /* max length of captured packets, in octets */ 49 uint32_t network; /* data link type */ 50 }; 51 52 struct pcaprec_hdr_t { 53 uint32_t ts_sec; /* timestamp seconds */ 54 uint32_t ts_usec; /* timestamp microseconds */ 55 uint32_t incl_len; /* number of octets of packet saved in file */ 56 uint32_t orig_len; /* actual length of packet */ 57 }; 58 59 const pcap_hdr_t pcap_file_header{ 60 0xa1b2c3d4, 61 2, 62 4, 63 0, 64 0, 65 65536, 66 105 // IEEE802.11 without radiotap 67 }; 68 69 void WritePCap(const void* buffer, size_t length) { 70 if (FLAGS_pcap.empty()) { 71 return; 72 } 73 static int pcap = -1; 74 if (pcap == -1) { 75 pcap = open(FLAGS_pcap.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0644); 76 if (pcap == -1) { 77 return; 78 } 79 (void)write(pcap, &pcap_file_header, sizeof(pcap_file_header)); 80 } 81 size_t write_length = length; 82 if (write_length > pcap_file_header.snaplen) { 83 write_length = pcap_file_header.snaplen; 84 } 85 pcaprec_hdr_t hdr; 86 struct timespec now; 87 clock_gettime(CLOCK_REALTIME, &now); 88 hdr.ts_sec = now.tv_sec; 89 hdr.ts_usec = now.tv_nsec / 1000; 90 hdr.incl_len = write_length; 91 hdr.orig_len = length; 92 struct iovec iov[2] { {&hdr, sizeof(hdr)}, 93 { const_cast<void*>(buffer), static_cast<size_t>(write_length)}}; 94 (void)writev(pcap, iov, 2); 95 } 96 97 } 98 99 Mac80211HwSim::Remote::Remote( 100 Mac80211HwSim *parent, 101 vsoc::wifi::WifiExchangeView *wifiExchange) 102 : mParent(parent), 103 mWifiExchange(wifiExchange) { 104 mWifiWorker = mWifiExchange->StartWorker(); 105 106 mThread = std::thread([this]{ 107 std::unique_ptr<uint8_t[]> buf( 108 new uint8_t[Mac80211HwSim::kMessageSizeMax]); 109 110 for (;;) { 111 intptr_t res = 112 mWifiExchange->Recv(buf.get(), Mac80211HwSim::kMessageSizeMax); 113 114 if (res < 0) { 115 LOG(ERROR) << "WifiExchangeView::Recv failed w/ res " << res; 116 continue; 117 } 118 WritePCap(buf.get(), static_cast<size_t>(res)); 119 120 // LOG(INFO) << "GUEST->HOST packet of size " << res; 121 mParent->injectFrame(buf.get(), res); 122 }}); 123 } 124 125 Mac80211HwSim::Remote::~Remote() { 126 mDone = true; 127 mWifiExchange->InterruptSelf(); 128 129 mThread.join(); 130 } 131 132 intptr_t Mac80211HwSim::Remote::send(const void *data, size_t size) { 133 WritePCap(data, size); 134 return mWifiExchange->Send(data, size); 135 } 136 137 Mac80211HwSim::Mac80211HwSim(const MacAddress &mac) 138 : mMAC(mac), 139 mSock(nullptr, nl_socket_free) { 140 int res; 141 142 mSock.reset(nl_socket_alloc()); 143 144 if (mSock == nullptr) { 145 goto bail; 146 } 147 148 res = nl_connect(mSock.get(), NETLINK_GENERIC); 149 if (res < 0) { 150 LOG(ERROR) << "nl_connect failed (" << nl_geterror(res) << ")"; 151 mInitCheck = res; 152 goto bail; 153 } 154 155 nl_socket_disable_seq_check(mSock.get()); 156 157 res = nl_socket_set_buffer_size( 158 mSock.get(), kMessageSizeMax, kMessageSizeMax); 159 160 if (res < 0) { 161 LOG(ERROR) 162 << "nl_socket_set_buffer_size failed (" 163 << nl_geterror(res) 164 << ")"; 165 166 mInitCheck = res; 167 goto bail; 168 } 169 170 mMac80211Family = genl_ctrl_resolve(mSock.get(), kWifiSimFamilyName); 171 if (mMac80211Family <= 0) { 172 LOG(ERROR) << "genl_ctrl_resolve failed."; 173 mInitCheck = -ENODEV; 174 goto bail; 175 } 176 177 mNl80211Family = genl_ctrl_resolve(mSock.get(), kNl80211FamilyName); 178 if (mNl80211Family <= 0) { 179 LOG(ERROR) << "genl_ctrl_resolve failed."; 180 mInitCheck = -ENODEV; 181 goto bail; 182 } 183 184 #if !defined(CUTTLEFISH_HOST) 185 res = registerOrSubscribe(mMAC); 186 187 if (res < 0) { 188 mInitCheck = res; 189 goto bail; 190 } 191 #endif 192 193 mInitCheck = 0; 194 return; 195 196 bail: 197 ; 198 } 199 200 int Mac80211HwSim::initCheck() const { 201 return mInitCheck; 202 } 203 204 int Mac80211HwSim::socketFd() const { 205 return nl_socket_get_fd(mSock.get()); 206 } 207 208 void Mac80211HwSim::ackFrame(nlmsghdr *inMsg) { 209 nlattr *attrs[__HWSIM_ATTR_MAX + 1]; 210 int res = genlmsg_parse( 211 inMsg, 212 0 /* hdrlen */, 213 attrs, 214 __HWSIM_ATTR_MAX, 215 nullptr /* policy */); 216 217 if (res < 0) { 218 LOG(ERROR) << "genlmsg_parse failed."; 219 return; 220 } 221 222 uint32_t flags = nla_get_u32(attrs[HWSIM_ATTR_FLAGS]); 223 224 if (!(flags & HWSIM_TX_CTL_REQ_TX_STATUS)) { 225 LOG(VERBOSE) << "Frame doesn't require TX_STATUS."; 226 return; 227 } 228 229 flags |= HWSIM_TX_STAT_ACK; 230 231 const uint8_t *xmitterAddr = 232 static_cast<const uint8_t *>( 233 nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER])); 234 235 size_t txRatesLen = nla_len(attrs[HWSIM_ATTR_TX_INFO]); 236 237 const struct hwsim_tx_rate *txRates = 238 static_cast<const struct hwsim_tx_rate *>( 239 nla_data(attrs[HWSIM_ATTR_TX_INFO])); 240 241 uint64_t cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]); 242 243 std::unique_ptr<nl_msg, void (*)(nl_msg *)> outMsg( 244 nlmsg_alloc(), nlmsg_free); 245 246 genlmsg_put( 247 outMsg.get(), 248 NL_AUTO_PID, 249 NL_AUTO_SEQ, 250 mMac80211Family, 251 0 /* hdrlen */, 252 NLM_F_REQUEST, 253 HWSIM_CMD_TX_INFO_FRAME, 254 0 /* version */); 255 256 nla_put(outMsg.get(), HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, xmitterAddr); 257 nla_put_u32(outMsg.get(), HWSIM_ATTR_FLAGS, flags); 258 nla_put_u32(outMsg.get(), HWSIM_ATTR_SIGNAL, kSignalLevelDefault); 259 nla_put(outMsg.get(), HWSIM_ATTR_TX_INFO, txRatesLen, txRates); 260 nla_put_u64(outMsg.get(), HWSIM_ATTR_COOKIE, cookie); 261 262 res = nl_send_auto_complete(mSock.get(), outMsg.get()); 263 if (res < 0) { 264 LOG(ERROR) << "Sending TX Info failed. (" << nl_geterror(res) << ")"; 265 } else { 266 LOG(VERBOSE) << "Sending TX Info SUCCEEDED."; 267 } 268 } 269 270 void Mac80211HwSim::injectFrame(const void *data, size_t size) { 271 std::unique_ptr<nl_msg, void (*)(nl_msg *)> msg(nlmsg_alloc(), nlmsg_free); 272 273 genlmsg_put( 274 msg.get(), 275 NL_AUTO_PID, 276 NL_AUTO_SEQ, 277 mMac80211Family, 278 0 /* hdrlen */, 279 NLM_F_REQUEST, 280 HWSIM_CMD_FRAME, 281 0 /* version */); 282 283 CHECK_EQ(mMAC.size(), static_cast<size_t>(ETH_ALEN)); 284 nla_put(msg.get(), HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, &mMAC[0]); 285 286 nla_put(msg.get(), HWSIM_ATTR_FRAME, size, data); 287 nla_put_u32(msg.get(), HWSIM_ATTR_RX_RATE, 1); 288 nla_put_u32(msg.get(), HWSIM_ATTR_SIGNAL, kSignalLevelDefault); 289 290 LOG(VERBOSE) << "INJECTING!"; 291 292 int res = nl_send_auto_complete(mSock.get(), msg.get()); 293 294 if (res < 0) { 295 LOG(ERROR) << "Injection failed. (" << nl_geterror(res) << ")"; 296 } else { 297 LOG(VERBOSE) << "Injection SUCCEEDED."; 298 } 299 } 300 301 void Mac80211HwSim::handlePacket() { 302 sockaddr_nl from; 303 uint8_t *data; 304 305 int len = nl_recv(mSock.get(), &from, &data, nullptr /* creds */); 306 if (len == 0) { 307 LOG(ERROR) << "nl_recv received EOF."; 308 return; 309 } else if (len < 0) { 310 LOG(ERROR) << "nl_recv failed (" << nl_geterror(len) << ")"; 311 return; 312 } 313 314 std::unique_ptr<nlmsghdr, void (*)(nlmsghdr *)> msg( 315 reinterpret_cast<nlmsghdr *>(data), 316 [](nlmsghdr *hdr) { free(hdr); }); 317 318 if (msg->nlmsg_type != mMac80211Family) { 319 LOG(VERBOSE) 320 << "Received msg of type other than MAC80211: " 321 << msg->nlmsg_type; 322 323 return; 324 } 325 326 #ifdef CUTTLEFISH_HOST 327 LOG(VERBOSE) << "------------------- Host -> Guest -----------------------"; 328 #else 329 LOG(VERBOSE) << "------------------- Guest -> Host -----------------------"; 330 #endif 331 332 genlmsghdr *hdr = genlmsg_hdr(msg.get()); 333 if (hdr->cmd != HWSIM_CMD_FRAME) { 334 LOG(VERBOSE) << "cmd HWSIM_CMD_FRAME."; 335 return; 336 } 337 338 nlattr *attrs[__HWSIM_ATTR_MAX + 1]; 339 int res = genlmsg_parse( 340 msg.get(), 341 0 /* hdrlen */, 342 attrs, 343 __HWSIM_ATTR_MAX, 344 nullptr /* policy */); 345 346 if (res < 0) { 347 LOG(ERROR) << "genlmsg_parse failed."; 348 return; 349 } 350 351 nlattr *attr = attrs[HWSIM_ATTR_FRAME]; 352 if (!attr) { 353 LOG(ERROR) << "no HWSIM_ATTR_FRAME."; 354 return; 355 } 356 std::lock_guard<std::mutex> autoLock(mRemotesLock); 357 for (auto &remoteEntry : mRemotes) { 358 // TODO(andih): Check which remotes to forward this packet to based 359 // on the destination address. 360 remoteEntry.second->send(nla_data(attr), nla_len(attr)); 361 } 362 363 #if !defined(CUTTLEFISH_HOST) 364 ackFrame(msg.get()); 365 #endif 366 367 } 368 369 int Mac80211HwSim::registerOrSubscribe(const MacAddress &mac) { 370 std::unique_ptr<nl_msg, void (*)(nl_msg *)> msg(nullptr, nlmsg_free); 371 372 msg.reset(nlmsg_alloc()); 373 374 genlmsg_put( 375 msg.get(), 376 NL_AUTO_PID, 377 NL_AUTO_SEQ, 378 mMac80211Family, 379 0, 380 NLM_F_REQUEST, 381 #ifdef CUTTLEFISH_HOST 382 HWSIM_CMD_SUBSCRIBE, 383 #else 384 HWSIM_CMD_REGISTER, 385 #endif 386 0); 387 388 #ifdef CUTTLEFISH_HOST 389 nla_put(msg.get(), HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, &mac[0]); 390 #else 391 // HWSIM_CMD_REGISTER is a global command not specific to a MAC. 392 (void)mac; 393 #endif 394 395 int res = nl_send_auto_complete(mSock.get(), msg.get()); 396 397 if (res < 0) { 398 LOG(ERROR) 399 << "Registration/subscription failed. (" << nl_geterror(res) << ")"; 400 401 return res; 402 } 403 404 return 0; 405 } 406 407 int Mac80211HwSim::addRemote( 408 const MacAddress &mac, 409 vsoc::wifi::WifiExchangeView *wifiExchange) { 410 #ifdef CUTTLEFISH_HOST 411 int res = registerOrSubscribe(mac); 412 413 if (res < 0) { 414 return res; 415 } 416 #endif 417 418 std::lock_guard<std::mutex> autoLock(mRemotesLock); 419 420 std::unique_ptr<Remote> remote(new Remote(this, wifiExchange)); 421 mRemotes.insert(std::make_pair(mac, std::move(remote))); 422 423 return 0; 424 } 425 426 void Mac80211HwSim::removeRemote(const MacAddress &mac) { 427 std::lock_guard<std::mutex> autoLock(mRemotesLock); 428 auto it = mRemotes.find(mac); 429 if (it != mRemotes.end()) { 430 mRemotes.erase(it); 431 } 432 } 433