Make wifirouter available on guest

This code is exact copy of wifi router from
cloud-android-containerization repository. Differences:
- include header path
- build files.

Change-Id: I82f978a1bd8242f763386c3afaa24f7439196849
diff --git a/Android.bp b/Android.bp
index 73d7264..f6d570a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,6 +15,7 @@
 
 subdirs = [
     "common",
+    "guest",
     "host",
 ]
 
diff --git a/guest/Android.bp b/guest/Android.bp
new file mode 100644
index 0000000..ee8105d
--- /dev/null
+++ b/guest/Android.bp
@@ -0,0 +1,18 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+subdirs = [
+    "commands",
+]
diff --git a/guest/commands/Android.bp b/guest/commands/Android.bp
new file mode 100644
index 0000000..cbd09e8
--- /dev/null
+++ b/guest/commands/Android.bp
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+subdirs = [
+    "wifirouter",
+]
+
diff --git a/guest/commands/wifirouter/Android.bp b/guest/commands/wifirouter/Android.bp
new file mode 100644
index 0000000..9302839
--- /dev/null
+++ b/guest/commands/wifirouter/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+cc_binary {
+    name: "wifirouter",
+    srcs: ["router.cc"],
+    static_libs: [
+        "libbase",
+        "libgflags",
+        "liblog",
+        "libnl",
+    ],
+    header_libs: [
+        "cuttlefish_common_headers",
+        "cuttlefish_glog",
+    ],
+}
+
diff --git a/guest/commands/wifirouter/router.cc b/guest/commands/wifirouter/router.cc
new file mode 100644
index 0000000..d01c3eb
--- /dev/null
+++ b/guest/commands/wifirouter/router.cc
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "common/libs/wifi/router.h"
+
+#include <cerrno>
+#include <cstddef>
+#include <map>
+#include <memory>
+#include <set>
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/genl.h>
+#include <netlink/netlink.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+DEFINE_string(socket_name, "cvd-wifirouter",
+              "Name of the unix-domain socket providing access for routing. "
+              "Socket will be created in abstract namespace.");
+
+namespace cvd {
+namespace {
+using MacHash = uint64_t;
+using MacToClientsTable = std::multimap<MacHash, int>;
+using ClientsTable = std::set<int>;
+
+// Copied out of mac80211_hwsim.h header.
+constexpr int HWSIM_CMD_REGISTER = 1;
+constexpr int HWSIM_ATTR_ADDR_TRANSMITTER = 2;
+constexpr int HWSIM_ATTR_MAX = 19;
+
+// Name of the WIFI SIM Netlink Family.
+constexpr char kWifiSimFamilyName[] = "MAC80211_HWSIM";
+const int kMaxSupportedPacketSize = getpagesize();
+
+// Get hash for mac address serialized to 6 bytes of data starting at specified
+// location.
+// We don't care about byte ordering as much as we do about having all bytes
+// there. Byte order does not matter, we want to use it as a key in our map.
+uint64_t GetMacHash(const void* macaddr) {
+  auto typed = reinterpret_cast<const uint16_t*>(macaddr);
+  return (1ull * typed[0] << 32) | (typed[1] << 16) | typed[2];
+}
+
+// Enable asynchronous notifications from MAC80211_HWSIM.
+// - `sock` is a valid netlink socket connected to NETLINK_GENERIC,
+// - `family` is MAC80211_HWSIM genl family number.
+//
+// Upon failure, this function will terminate execution of the program.
+void RegisterForHWSimNotifications(nl_sock* sock, int family) {
+  std::unique_ptr<nl_msg, void (*)(nl_msg*)> msg(
+      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
+  genlmsg_put(msg.get(), NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST,
+              HWSIM_CMD_REGISTER, 0);
+  nl_send_auto(sock, msg.get());
+  auto res = nl_wait_for_ack(sock);
+  if (res < 0) {
+    LOG(ERROR) << "Could not register for notifications: " << nl_geterror(res);
+    exit(1);
+  }
+}
+
+// Create and configure WIFI Router server socket.
+// This function is guaranteed to success. If at any point an error is detected,
+// the function will terminate execution of the program.
+int CreateWifiRouterServerSocket() {
+  auto fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+  if (fd <= 0) {
+    LOG(ERROR) << "Could not create unix socket: " << strerror(-fd);
+    exit(1);
+  }
+
+  sockaddr_un addr{};
+  addr.sun_family = AF_UNIX;
+  auto len = std::min(sizeof(addr.sun_path) - 2, FLAGS_socket_name.size());
+  strncpy(&addr.sun_path[1], FLAGS_socket_name.c_str(), len);
+  len += offsetof(sockaddr_un, sun_path) + 1;  // include heading \0 byte.
+  auto res = bind(fd, reinterpret_cast<sockaddr*>(&addr), len);
+
+  if (res < 0) {
+    LOG(ERROR) << "Could not bind unix socket: " << strerror(-res);
+    exit(1);
+  }
+
+  listen(fd, 4);
+  return fd;
+}
+
+// Accept new WIFI Router client. When successful, client will be placed in
+// clients table.
+void AcceptNewClient(int server_fd, ClientsTable* clients) {
+  auto client = accept(server_fd, nullptr, nullptr);
+  if (client < 0) {
+    LOG(ERROR) << "Could not accept client: " << strerror(errno);
+    return;
+  }
+
+  clients->insert(client);
+  LOG(INFO) << "Client " << client << " added.";
+}
+
+// Disconnect and remove client from list of registered clients and recipients
+// of WLAN traffic.
+void RemoveClient(int client, ClientsTable* clients,
+                  MacToClientsTable* targets) {
+  close(client);
+  clients->erase(client);
+  for (auto iter = targets->begin(); iter != targets->end();) {
+    if (iter->second == client) {
+      iter = targets->erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+  LOG(INFO) << "Client " << client << " removed.";
+}
+
+// Read MAC80211HWSIM packet, find the originating MAC address and redirect it
+// to proper sink.
+void RouteWIFIPacket(nl_sock* nl, int simfamily, ClientsTable* clients,
+                     MacToClientsTable* targets) {
+  sockaddr_nl tmp;
+  uint8_t* buf;
+
+  const auto len = nl_recv(nl, &tmp, &buf, nullptr);
+  if (len < 0) {
+    LOG(ERROR) << "Could not read from netlink: " << nl_geterror(len);
+    return;
+  }
+
+  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
+      reinterpret_cast<nlmsghdr*>(buf), [](nlmsghdr* m) { free(m); });
+
+  // Discard messages that originate from anything else than MAC80211_HWSIM.
+  if (msg->nlmsg_type != simfamily) return;
+
+  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rep(
+      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
+  genlmsg_put(rep.get(), 0, 0, 0, 0, 0, WIFIROUTER_CMD_NOTIFY, 0);
+
+  // Note, this is generic netlink message, and uses different parsing
+  // technique.
+  nlattr* attrs[HWSIM_ATTR_MAX + 1];
+  if (genlmsg_parse(msg.get(), 0, attrs, HWSIM_ATTR_MAX, nullptr)) return;
+
+  std::set<int> pending_removals;
+  auto addr = attrs[HWSIM_ATTR_ADDR_TRANSMITTER];
+  if (addr != nullptr) {
+    nla_put(rep.get(), WIFIROUTER_ATTR_MAC, nla_len(addr), nla_data(addr));
+    nla_put(rep.get(), WIFIROUTER_ATTR_PACKET, len, buf);
+    auto hdr = nlmsg_hdr(rep.get());
+
+    auto key = GetMacHash(nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]));
+    LOG(INFO) << "Received netlink packet from " << std::hex << key;
+    for (auto it = targets->find(key); it != targets->end() && it->first == key;
+         ++it) {
+      auto num_written =
+          send(it->second, hdr, hdr->nlmsg_len, MSG_NOSIGNAL);
+      if (num_written != static_cast<int64_t>(hdr->nlmsg_len)) {
+        pending_removals.insert(it->second);
+      }
+    }
+
+    for (auto client : pending_removals) {
+      RemoveClient(client, clients, targets);
+    }
+  }
+}
+
+bool HandleClientMessage(int client, MacToClientsTable* targets) {
+  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
+      reinterpret_cast<nlmsghdr*>(malloc(kMaxSupportedPacketSize)),
+      [](nlmsghdr* h) { free(h); });
+  int64_t size = recv(client, msg.get(), kMaxSupportedPacketSize, 0);
+
+  // Invalid message or no data -> client invalid or disconnected.
+  if (size == 0 || size != msg->nlmsg_len || size < sizeof(nlmsghdr)) {
+    return false;
+  }
+
+  int result = -EINVAL;
+  genlmsghdr* ghdr = reinterpret_cast<genlmsghdr*>(nlmsg_data(msg.get()));
+
+  switch (ghdr->cmd) {
+    case WIFIROUTER_CMD_REGISTER:
+      // Register client to receive notifications for specified MAC address.
+      nlattr* attrs[WIFIROUTER_ATTR_MAX];
+      if (!nlmsg_parse(msg.get(), sizeof(genlmsghdr), attrs,
+                       WIFIROUTER_ATTR_MAX - 1, nullptr)) {
+        if (attrs[WIFIROUTER_ATTR_MAC] != nullptr) {
+          targets->emplace(GetMacHash(nla_data(attrs[WIFIROUTER_ATTR_MAC])),
+                           client);
+          result = 0;
+        }
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  nlmsgerr err{.error = result};
+  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rsp(nlmsg_alloc(), nlmsg_free);
+  nlmsg_put(rsp.get(), msg->nlmsg_pid, msg->nlmsg_seq, NLMSG_ERROR, 0, 0);
+  nlmsg_append(rsp.get(), &err, sizeof(err), 0);
+  auto hdr = nlmsg_hdr(rsp.get());
+  if (send(client, hdr, hdr->nlmsg_len, MSG_NOSIGNAL) !=
+      static_cast<int64_t>(hdr->nlmsg_len)) {
+    return false;
+  }
+  return true;
+}
+
+// Process incoming requests from netlink, server or clients.
+void ServerLoop(int server_fd, nl_sock* netlink_sock, int family) {
+  ClientsTable clients;
+  MacToClientsTable targets;
+  int netlink_fd = nl_socket_get_fd(netlink_sock);
+
+  while (true) {
+    auto max_fd = server_fd;
+    fd_set reads{};
+
+    auto fdset = [&max_fd, &reads](int fd) {
+      FD_SET(fd, &reads);
+      max_fd = std::max(max_fd, fd);
+    };
+
+    fdset(server_fd);
+    fdset(netlink_fd);
+    for (int client : clients) fdset(client);
+
+    if (select(max_fd + 1, &reads, nullptr, nullptr, nullptr) <= 0) continue;
+
+    if (FD_ISSET(server_fd, &reads)) AcceptNewClient(server_fd, &clients);
+    if (FD_ISSET(netlink_fd, &reads))
+      RouteWIFIPacket(netlink_sock, family, &clients, &targets);
+
+    // Process any client messages left. Drop any client that is no longer
+    // talking with us.
+    for (auto client = clients.begin(); client != clients.end();) {
+      auto cfd = *client++;
+      // Is our client sending us data?
+      if (FD_ISSET(cfd, &reads)) {
+        if (!HandleClientMessage(cfd, &targets)) {
+          // Client should be disconnected.
+          RemoveClient(cfd, &clients, &targets);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace
+}  // namespace cvd
+
+int main(int argc, char* argv[]) {
+  using namespace cvd;
+  google::ParseCommandLineFlags(&argc, &argv, true);
+#if !defined(ANDROID)
+  // We should check for legitimate google logging here.
+  google::InitGoogleLogging(argv[0]);
+  google::InstallFailureSignalHandler();
+#endif
+
+  std::unique_ptr<nl_sock, void (*)(nl_sock*)> sock(nl_socket_alloc(),
+                                                    nl_socket_free);
+
+  auto res = nl_connect(sock.get(), NETLINK_GENERIC);
+  if (res < 0) {
+    LOG(ERROR) << "Could not connect to netlink generic: " << nl_geterror(res);
+    exit(1);
+  }
+
+  auto mac80211_family = genl_ctrl_resolve(sock.get(), kWifiSimFamilyName);
+  if (mac80211_family <= 0) {
+    LOG(ERROR) << "Could not find MAC80211 HWSIM. Please make sure module "
+               << "'mac80211_hwsim' is loaded on your system.";
+    exit(1);
+  }
+
+  RegisterForHWSimNotifications(sock.get(), mac80211_family);
+  auto server_fd = CreateWifiRouterServerSocket();
+  ServerLoop(server_fd, sock.get(), mac80211_family);
+}