Merge "(wifi) Removes unique_ptr<thread> and detaches" into gce-dev
diff --git a/common/commands/wifi_relay/wifi_relay.cpp b/common/commands/wifi_relay/wifi_relay.cpp
index 5db8a10..b57d710 100644
--- a/common/commands/wifi_relay/wifi_relay.cpp
+++ b/common/commands/wifi_relay/wifi_relay.cpp
@@ -33,16 +33,6 @@
 
 #include <fstream>
 
-DEFINE_string(
-        guest_mac_address,
-        "00:43:56:44:80:02",
-        "MAC address of the wifi interface to be created on the guest.");
-
-DEFINE_string(
-        host_mac_address,
-        "42:00:00:00:00:00",
-        "MAC address of the wifi interface running on the host.");
-
 #if !defined(CUTTLEFISH_HOST)
 DEFINE_string(
         iface_name, "wlan0", "Name of the wifi interface to be created.");
@@ -241,11 +231,14 @@
 int main(int argc, char **argv) {
   gflags::ParseCommandLineFlags(&argc, &argv, true);
 
-  Mac80211HwSim::MacAddress guestMAC, hostMAC;
-  if (!Mac80211HwSim::ParseMACAddress(FLAGS_guest_mac_address, &guestMAC)
-          || !Mac80211HwSim::ParseMACAddress(FLAGS_host_mac_address, &hostMAC)) {
-      exit(1);
-  }
+  auto wifi_view = vsoc::wifi::WifiExchangeView::GetInstance(
+#if defined(CUTTLEFISH_HOST)
+      vsoc::GetDomain().c_str()
+#endif
+  );
+
+  Mac80211HwSim::MacAddress guestMAC = wifi_view->GetGuestMACAddress();
+  Mac80211HwSim::MacAddress hostMAC = wifi_view->GetHostMACAddress();
 
 #ifdef CUTTLEFISH_HOST
   WifiRelay relay(hostMAC, guestMAC);
diff --git a/common/commands/wifi_relay/wifi_relay.h b/common/commands/wifi_relay/wifi_relay.h
index 98dce3a..db94648 100644
--- a/common/commands/wifi_relay/wifi_relay.h
+++ b/common/commands/wifi_relay/wifi_relay.h
@@ -44,4 +44,3 @@
 
   std::unique_ptr<Mac80211HwSim> mMac80211HwSim;
 };
-
diff --git a/common/frontend/socket_forward_proxy/Android.bp b/common/frontend/socket_forward_proxy/Android.bp
index c70983e..caad62b 100644
--- a/common/frontend/socket_forward_proxy/Android.bp
+++ b/common/frontend/socket_forward_proxy/Android.bp
@@ -21,6 +21,7 @@
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libcuttlefish_strings",
         "cuttlefish_auto_resources",
         "vsoc_lib",
         "liblog",
diff --git a/common/frontend/socket_forward_proxy/main.cpp b/common/frontend/socket_forward_proxy/main.cpp
index ad1ca10..ed4196e 100644
--- a/common/frontend/socket_forward_proxy/main.cpp
+++ b/common/frontend/socket_forward_proxy/main.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/strings/str_split.h"
 #include "common/vsoc/lib/socket_forward_region_view.h"
 
 #ifdef CUTTLEFISH_HOST
@@ -39,9 +40,12 @@
 using vsoc::socket_forward::SocketForwardRegionView;
 
 #ifdef CUTTLEFISH_HOST
-DEFINE_string(ports, "",
-              "Comma-separated list of ports from which to forward TCP "
-              "connections.");
+DEFINE_string(guest_ports, "",
+              "Comma-separated list of ports on which to forward TCP "
+              "connections to the guest.");
+DEFINE_string(host_ports, "",
+              "Comma-separated list of ports on which to run TCP servers on "
+              "the host.");
 #endif
 
 namespace {
@@ -154,44 +158,53 @@
 }
 
 #ifdef CUTTLEFISH_HOST
+struct PortPair {
+  int guest_port;
+  int host_port;
+};
+
+
 [[noreturn]] void host_impl(SocketForwardRegionView* shm,
-                            std::vector<int> ports, std::size_t index) {
+                            std::vector<PortPair> ports, std::size_t index) {
   // launch a worker for the following port before handling the current port.
   // recursion (instead of a loop) removes the need fore any join() or having
   // the main thread do no work.
   if (index + 1 < ports.size()) {
     std::thread(host_impl, shm, ports, index + 1).detach();
   }
-  auto remote_port = ports[index];
-  auto local_port = vsoc::GetPerInstanceDefault(remote_port);
-  LOG(INFO) << "starting server on " << local_port
-            << " for guest port " << remote_port;
-  auto server = cvd::SharedFD::SocketLocalServer(local_port, SOCK_STREAM);
-  CHECK(server->IsOpen()) << "Could not start server on port " << local_port;
+  auto guest_port = ports[index].guest_port;
+  auto host_port = ports[index].host_port;
+  LOG(INFO) << "starting server on " << host_port
+            << " for guest port " << guest_port;
+  auto server = cvd::SharedFD::SocketLocalServer(host_port, SOCK_STREAM);
+  CHECK(server->IsOpen()) << "Could not start server on port " << host_port;
   while (true) {
     auto client_socket = cvd::SharedFD::Accept(*server);
     CHECK(client_socket->IsOpen()) << "error creating client socket";
     LOG(INFO) << "client socket accepted";
-    auto conn = shm->OpenConnection(remote_port);
+    auto conn = shm->OpenConnection(guest_port);
     LOG(INFO) << "shm connection opened";
     LaunchWorkers(std::move(conn), std::move(client_socket));
   }
 }
 
 [[noreturn]] void host(SocketForwardRegionView* shm,
-                           std::vector<int> ports) {
+                       std::vector<PortPair> ports) {
   CHECK(!ports.empty());
   host_impl(shm, ports, 0);
 }
 
-std::vector<int> ParsePortsList(const std::string& ports_flag) {
-  std::istringstream ports_stream{ports_flag};
-  std::vector<int> ports;
-  std::string port_str{};
-  while (std::getline(ports_stream, port_str, ',')) {
-    ports.push_back(std::stoi(port_str));
+std::vector<PortPair> ParsePortsList(const std::string& guest_ports_str,
+                                const std::string& host_ports_str) {
+  std::vector<PortPair> ports{};
+  auto guest_ports = cvd::StrSplit(guest_ports_str, ',');
+  auto host_ports = cvd::StrSplit(host_ports_str, ',');
+  CHECK(guest_ports.size() == host_ports.size());
+  for (std::size_t i = 0; i < guest_ports.size(); ++i) {
+    ports.push_back({std::stoi(guest_ports[i]), std::stoi(host_ports[i])});
   }
   return ports;
+
 }
 
 #else
@@ -250,8 +263,9 @@
   auto worker = shm->StartWorker();
 
 #ifdef CUTTLEFISH_HOST
-  CHECK(!FLAGS_ports.empty()) << "Must specify --ports flag";
-  host(shm, ParsePortsList(FLAGS_ports));
+  CHECK(!FLAGS_guest_ports.empty()) << "Must specify --guest_ports flag";
+  CHECK(!FLAGS_host_ports.empty()) << "Must specify --host_ports flag";
+  host(shm, ParsePortsList(FLAGS_guest_ports, FLAGS_host_ports));
 #else
   guest(shm);
 #endif
diff --git a/common/libs/Android.bp b/common/libs/Android.bp
index b23571f..cb4ec3e 100644
--- a/common/libs/Android.bp
+++ b/common/libs/Android.bp
@@ -17,6 +17,7 @@
     "auto_resources",
     "fs",
     "net",
+    "strings",
     "tcp_socket",
     "threads",
     "time",
diff --git a/common/libs/net/network_interface_manager.cpp b/common/libs/net/network_interface_manager.cpp
index 32d5583..4ee96b7 100644
--- a/common/libs/net/network_interface_manager.cpp
+++ b/common/libs/net/network_interface_manager.cpp
@@ -75,15 +75,22 @@
     : nl_client_(std::move(nl_client)) {}
 
 std::unique_ptr<NetworkInterface> NetworkInterfaceManager::Open(
-    const std::string& if_name) {
+    const std::string& if_name, const std::string& if_name_alt) {
   std::unique_ptr<NetworkInterface> iface;
   // NOTE: do not replace this code with an IOCTL call.
   // On SELinux enabled Androids, RILD is not permitted to execute an IOCTL
   // and this call will fail.
-  const int32_t index = if_nametoindex(if_name.c_str());
-  if (index < 0) {
-    LOG(ERROR) << "Failed to get interface (" << if_name << ") index.";
-    return iface;
+  int32_t index = if_nametoindex(if_name.c_str());
+  if (index == 0) {
+    // Try the alternate name. This will be renamed to our preferred name
+    // by the kernel, because we specify IFLA_IFNAME, but open by index.
+    LOG(ERROR) << "Failed to get interface (" << if_name << ") index, "
+               << "trying alternate.";
+    index = if_nametoindex(if_name_alt.c_str());
+    if (index == 0) {
+      LOG(ERROR) << "Failed to get interface (" << if_name_alt << ") index.";
+      return iface;
+    }
   }
 
   iface.reset(new NetworkInterface(index));
diff --git a/common/libs/net/network_interface_manager.h b/common/libs/net/network_interface_manager.h
index 3d6ccc5..f28b0ff 100644
--- a/common/libs/net/network_interface_manager.h
+++ b/common/libs/net/network_interface_manager.h
@@ -32,14 +32,15 @@
 //
 //   std::unique_ptr<NetlinkClient> client(NetlinkClient::GetDefault());
 //   NetworkInterfaceManager manager(client.get());
-//   std::unique_ptr<NetworkInterface> iface(manager.Open("eth0"));
+//   std::unique_ptr<NetworkInterface> iface(manager.Open("eth0", "em0"));
 //
 class NetworkInterfaceManager {
  public:
   // Open existing network interface.
   //
   // NOTE: this method does not fill in any NetworkInterface details yet.
-  std::unique_ptr<NetworkInterface> Open(const std::string& if_name);
+  std::unique_ptr<NetworkInterface> Open(const std::string& if_name,
+                                         const std::string& if_name_alt);
 
   // Apply changes made to existing network interface.
   // This method cannot be used to instantiate new network interfaces.
diff --git a/common/libs/strings/Android.bp b/common/libs/strings/Android.bp
new file mode 100644
index 0000000..273c79e
--- /dev/null
+++ b/common/libs/strings/Android.bp
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2018 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_library_shared {
+    name: "libcuttlefish_strings",
+    srcs: [
+        "str_split.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+    defaults: ["cuttlefish_host_and_guest"],
+}
diff --git a/common/libs/strings/str_split.cpp b/common/libs/strings/str_split.cpp
new file mode 100644
index 0000000..d76acad
--- /dev/null
+++ b/common/libs/strings/str_split.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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/strings/str_split.h"
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+std::vector<std::string> cvd::StrSplit(const std::string& src, char delimiter) {
+  std::istringstream stream{src};
+  std::vector<std::string> result;
+  for (std::string s; std::getline(stream, s, delimiter); s.clear()) {
+    result.push_back(std::move(s));
+  }
+  return result;
+}
diff --git a/common/libs/strings/str_split.h b/common/libs/strings/str_split.h
new file mode 100644
index 0000000..cd18d15
--- /dev/null
+++ b/common/libs/strings/str_split.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef CUTTLEFISH_COMMON_COMMON_LIBS_STRINGS_STR_SPLIT_H_
+#define CUTTLEFISH_COMMON_COMMON_LIBS_STRINGS_STR_SPLIT_H_
+
+#include <vector>
+#include <string>
+
+namespace cvd {
+std::vector<std::string> StrSplit(const std::string& src, char delimiter);
+}  // namespace cvd
+
+#endif
diff --git a/common/libs/wifi_relay/mac80211_hwsim.cpp b/common/libs/wifi_relay/mac80211_hwsim.cpp
index 4601c78..ed72ce7 100644
--- a/common/libs/wifi_relay/mac80211_hwsim.cpp
+++ b/common/libs/wifi_relay/mac80211_hwsim.cpp
@@ -22,7 +22,6 @@
 #include <netlink/genl/ctrl.h>
 #include <netlink/genl/genl.h>
 #include <signal.h>
-#include <string>
 
 static constexpr char kWifiSimFamilyName[] = "MAC80211_HWSIM";
 static constexpr char kNl80211FamilyName[] = "nl80211";
@@ -418,24 +417,3 @@
         mRemotes.erase(it);
     }
 }
-
-// static
-bool Mac80211HwSim::ParseMACAddress(const std::string &s, MacAddress *mac) {
-    mac->resize(ETH_ALEN);
-
-    char dummy;
-    if (sscanf(s.c_str(),
-               "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx%c",
-               &(*mac)[0],
-               &(*mac)[1],
-               &(*mac)[2],
-               &(*mac)[3],
-               &(*mac)[4],
-               &(*mac)[5],
-               &dummy) != 6) {
-        LOG(ERROR) << "Failed to parse MAC address: " << s;
-        return false;
-    }
-
-    return true;
-}
diff --git a/common/libs/wifi_relay/mac80211_hwsim.h b/common/libs/wifi_relay/mac80211_hwsim.h
index 28eea6f..d9e4e0f 100644
--- a/common/libs/wifi_relay/mac80211_hwsim.h
+++ b/common/libs/wifi_relay/mac80211_hwsim.h
@@ -24,10 +24,9 @@
 #include <memory>
 #include <mutex>
 #include <netlink/netlink.h>
-#include <vector>
 
 struct Mac80211HwSim {
-    using MacAddress = std::vector<uint8_t>;
+    using MacAddress = vsoc::wifi::WifiExchangeView::MacAddress;
 
     static constexpr size_t kMessageSizeMax = 128 * 1024;
 
@@ -52,8 +51,6 @@
 
     void removeRemote(const MacAddress &mac);
 
-    static bool ParseMACAddress(const std::string &s, MacAddress *mac);
-
 private:
     struct Remote {
         explicit Remote(
diff --git a/common/vsoc/lib/wifi_exchange_view.cpp b/common/vsoc/lib/wifi_exchange_view.cpp
index 1cb3bf9..23dcd09 100644
--- a/common/vsoc/lib/wifi_exchange_view.cpp
+++ b/common/vsoc/lib/wifi_exchange_view.cpp
@@ -15,6 +15,9 @@
  */
 #include "common/vsoc/lib/wifi_exchange_view.h"
 
+#include <algorithm>
+#include <string>
+
 #include <linux/if_ether.h>
 #include "common/vsoc/lib/circqueue_impl.h"
 
@@ -41,12 +44,74 @@
 #endif
 }
 
-void WifiExchangeView::SetGuestMACAddress(const uint8_t* mac_address) {
-  memcpy(data()->mac_address, mac_address, ETH_ALEN);
+void WifiExchangeView::SetGuestMACAddress(
+    const WifiExchangeView::MacAddress& mac_address) {
+  std::copy(std::begin(mac_address),
+            std::end(mac_address),
+            std::begin(data()->guest_mac_address));
 }
 
-void WifiExchangeView::GetGuestMACAddress(uint8_t* mac_address) {
-  memcpy(mac_address, data()->mac_address, ETH_ALEN);
+WifiExchangeView::MacAddress WifiExchangeView::GetGuestMACAddress() {
+  WifiExchangeView::MacAddress ret;
+  std::copy(std::begin(data()->guest_mac_address),
+            std::end(data()->guest_mac_address),
+            std::begin(ret));
+  return ret;
+}
+
+void WifiExchangeView::SetHostMACAddress(
+    const WifiExchangeView::MacAddress& mac_address) {
+  std::copy(std::begin(mac_address),
+            std::end(mac_address),
+            std::begin(data()->host_mac_address));
+}
+
+WifiExchangeView::MacAddress WifiExchangeView::GetHostMACAddress() {
+  WifiExchangeView::MacAddress ret;
+  std::copy(std::begin(data()->host_mac_address),
+            std::end(data()->host_mac_address),
+            std::begin(ret));
+  return ret;
+}
+
+// static
+bool WifiExchangeView::ParseMACAddress(const std::string& s,
+                                       WifiExchangeView::MacAddress* mac) {
+  char dummy;
+  // This is likely to always be true, but better safe than sorry
+  static_assert(std::tuple_size<WifiExchangeView::MacAddress>::value == 6,
+                "Mac address size has changed");
+  if (sscanf(s.c_str(),
+             "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx%c",
+             &(*mac)[0],
+             &(*mac)[1],
+             &(*mac)[2],
+             &(*mac)[3],
+             &(*mac)[4],
+             &(*mac)[5],
+             &dummy) != 6) {
+    return false;
+  }
+  return true;
+}
+
+// static
+std::string WifiExchangeView::MacAddressToString(
+    const WifiExchangeView::MacAddress& mac) {
+  char buffer[3 * mac.size()];
+  // This is likely to always be true, but better safe than sorry
+  static_assert(std::tuple_size<WifiExchangeView::MacAddress>::value == 6,
+                "Mac address size has changed");
+  snprintf(buffer,
+           sizeof(buffer),
+           "%02x:%02x:%02x:%02x:%02x:%02x",
+           mac[0],
+           mac[1],
+           mac[2],
+           mac[3],
+           mac[4],
+           mac[5]);
+  return std::string(buffer);
 }
 
 }  // namespace wifi
diff --git a/common/vsoc/lib/wifi_exchange_view.h b/common/vsoc/lib/wifi_exchange_view.h
index ad0d968..5230a8e 100644
--- a/common/vsoc/lib/wifi_exchange_view.h
+++ b/common/vsoc/lib/wifi_exchange_view.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <array>
 #include <memory>
 
 #include "common/vsoc/lib/typed_region_view.h"
@@ -29,6 +30,10 @@
         WifiExchangeView,
         vsoc::layout::wifi::WifiExchangeLayout> {
  public:
+  using MacAddress = std::array<
+      uint8_t,
+      sizeof(vsoc::layout::wifi::WifiExchangeLayout::guest_mac_address)>;
+
   // Send netlink packet to peer.
   // returns true, if operation was successful.
   intptr_t Send(const void* buffer, intptr_t length);
@@ -38,11 +43,18 @@
   intptr_t Recv(void* buffer, intptr_t max_length);
 
   // Set guest MAC address.
-  void SetGuestMACAddress(const uint8_t* mac_address);
-  void GetGuestMACAddress(uint8_t* mac_address);
+  void SetGuestMACAddress(const MacAddress& mac_address);
+  MacAddress GetGuestMACAddress();
+
+  // Set host MAC address.
+  void SetHostMACAddress(const MacAddress& mac_address);
+  MacAddress GetHostMACAddress();
 
   void SetConfigReady();
   void WaitConfigReady();
+
+  static bool ParseMACAddress(const std::string &s, MacAddress *mac);
+  static std::string MacAddressToString(const MacAddress& mac);
 };
 
 }  // namespace wifi
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
index 4948de4..0efae81 100644
--- a/common/vsoc/shm/version.h
+++ b/common/vsoc/shm/version.h
@@ -126,14 +126,13 @@
 // Versioning information for wifi_layout.h
 namespace wifi {
 namespace {
-constexpr uint32_t version = 0;
+constexpr uint32_t version = 1;
 }  // namespace
 constexpr size_t WifiExchangeLayout_size =
     65548 + // sizeof(CircularPacketQueue<16, 8192>) - forward
     65548 + // sizeof(CircularPacketQueue<16, 8192>) - reverse
-    4 +     // Lock config_lock_
-    2 +     // bool config_ready_ (and even address alignment)
-    6;      // uint8_t[6] MAC address.
+    6 +     // uint8_t[6] MAC address.
+    6;     // uint8_t[6] MAC address.
 }  // namespace wifi
 
 // Versioning information for ril_layout.h
diff --git a/common/vsoc/shm/wifi_exchange_layout.h b/common/vsoc/shm/wifi_exchange_layout.h
index 2ca957c..93f1a9e 100644
--- a/common/vsoc/shm/wifi_exchange_layout.h
+++ b/common/vsoc/shm/wifi_exchange_layout.h
@@ -31,12 +31,10 @@
   // Traffic originating from guest that proceeds towards host.
   CircularPacketQueue<16, 8192> guest_egress;
 
-  // config_lock_ manages access to configuration section
-  SpinLock config_lock_;
-  // config_ready_ indicates whether config section is ready to be accessed.
-  bool config_ready_;
   // Desired MAC address for guest device.
-  uint8_t mac_address[6];
+  uint8_t guest_mac_address[6];
+  // MAC address of host device.
+  uint8_t host_mac_address[6];
 
   static const char* region_name;
 };
diff --git a/guest/commands/vport_trigger/Android.mk b/guest/commands/vport_trigger/Android.mk
new file mode 100644
index 0000000..e994ce9
--- /dev/null
+++ b/guest/commands/vport_trigger/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := vport_trigger
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := main.cpp
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MULTILIB := first
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/guest/commands/vport_trigger/main.cpp b/guest/commands/vport_trigger/main.cpp
new file mode 100644
index 0000000..9e4a5f7
--- /dev/null
+++ b/guest/commands/vport_trigger/main.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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 <cutils/properties.h>
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <climits>
+#include <sstream>
+#include <string>
+
+// Taken from android::base, which wasn't available on platform versions
+// earlier than nougat.
+
+static bool ReadFdToString(int fd, std::string* content) {
+  content->clear();
+  char buf[BUFSIZ];
+  ssize_t n;
+  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+    content->append(buf, n);
+  }
+  return (n == 0) ? true : false;
+}
+
+static bool ReadFileToString(const std::string& path, std::string* content,
+                             bool follow_symlinks) {
+  int flags = O_RDONLY | O_CLOEXEC | (follow_symlinks ? 0 : O_NOFOLLOW);
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags));
+  if (fd == -1) {
+    return false;
+  }
+  bool result = ReadFdToString(fd, content);
+  close(fd);
+  return result;
+}
+
+int main(int argc __unused, char *argv[] __unused) {
+  // QEMU seems to create on either bus 0 or bus 1.
+  for (size_t bus = 0; bus < 2U; bus++) {
+    // 'max_ports' is set to '31' upstream.
+    for (size_t port = 0; port < 31U; port++) {
+      std::ostringstream vport;
+      vport << "vport" << bus << "p" << port;
+      std::string sysfs("/sys/class/virtio-ports/" + vport.str() + "/name");
+      struct stat st;
+      if (stat(sysfs.c_str(), &st)) {
+        continue;
+      }
+      std::string content;
+      if (!ReadFileToString(sysfs, &content, true)) {
+        continue;
+      }
+      if (content.empty()) {
+        continue;
+      }
+      content.erase(content.end() - 1);
+      // Leaves 32-11=22 characters for the port name from QEMU.
+      std::string propname("sys.cf.ser." + content);
+      std::string dev("/dev/" + vport.str());
+      property_set(propname.c_str(), dev.c_str());
+    }
+  }
+  return 0;
+}
diff --git a/guest/hals/ril/vsoc_ril.cpp b/guest/hals/ril/vsoc_ril.cpp
index b60ad8d..0d33dd9 100644
--- a/guest/hals/ril/vsoc_ril.cpp
+++ b/guest/hals/ril/vsoc_ril.cpp
@@ -114,9 +114,10 @@
   std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
   std::unique_ptr<cvd::NetworkInterfaceManager> nm(
       cvd::NetworkInterfaceManager::New(factory));
-  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open("rmnet0"));
+  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open("rmnet0", "eth0"));
 
   if (ni) {
+    ni->SetName("rmnet0");
     ni->SetAddress(ipaddr);
     ni->SetBroadcastAddress(bcaddr);
     ni->SetPrefixLength(prefixlen);
@@ -132,7 +133,7 @@
 // This call returns true, if operation was successful.
 bool TearDownNetworkInterface() {
   auto nm(cvd::NetworkInterfaceManager::New(nullptr));
-  auto ni(nm->Open("rmnet0"));
+  auto ni(nm->Open("rmnet0", "eth0"));
 
   if (ni) {
     ni->SetOperational(false);
diff --git a/host/commands/launch/Android.bp b/host/commands/launch/Android.bp
index 420df07..f888d79 100644
--- a/host/commands/launch/Android.bp
+++ b/host/commands/launch/Android.bp
@@ -4,6 +4,7 @@
         "main.cc",
         "screen_region_handler.cc",
         "ril_region_handler.cc",
+        "wifi_region_handler.cc",
     ],
     header_libs: [
         "cuttlefish_glog",
@@ -11,12 +12,15 @@
     shared_libs: [
         "vsoc_lib",
         "libcuttlefish_fs",
+        "libcuttlefish_strings",
         "cuttlefish_auto_resources",
         "libicuuc",
         "libbase",
+        "libnl"
     ],
     static_libs: [
         "libcuttlefish_host_config",
+        "libcuttlefish_wifi_relay",
         "libivserver",
         "libvadb",
         "libusbip",
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index eacd5da..416ebf1 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -22,15 +22,19 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <fstream>
 #include <iomanip>
 #include <memory>
 #include <sstream>
+#include <string>
+#include <vector>
 
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
 #include "common/libs/fs/shared_select.h"
+#include "common/libs/strings/str_split.h"
 #include "host/commands/launch/pre_launch_initializers.h"
 #include "host/libs/config/file_partition.h"
 #include "host/libs/config/guest_config.h"
@@ -112,17 +116,12 @@
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
                   "/bin/vnc_server",
               "Location of the vnc server binary.");
-DEFINE_int32(vnc_server_port, vsoc::GetPerInstanceDefault(6444),
+DEFINE_int32(vnc_server_port, GetPerInstanceDefault(6444),
              "The port on which the vnc server should listen");
 DEFINE_string(socket_forward_proxy_binary,
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
                   "/bin/socket_forward_proxy",
               "Location of the socket_forward_proxy binary.");
-DEFINE_string(socket_forward_proxy_ports, "5555", "Comma-separated list of "
-              "ports on which to run the socket_forward_proxy server. These "
-              "are the port numbers of the guest-side process. The "
-              "host-side socket_forward_proxy process will bias the port "
-              "numbers.");
 
 DEFINE_bool(start_wifi_relay, true, "Whether to start the wifi_relay process.");
 DEFINE_string(wifi_relay_binary,
@@ -309,6 +308,20 @@
     "/bin/rm", "-f", file.c_str(), NULL};
   subprocess(rm_command, NULL);
 }
+
+
+// Emulators are discovered on odd numbered ports from 5555 to 5585
+constexpr int kFirstEmulatorPort = 5555;
+
+std::string GetGuestPortArg() {
+  return std::string{"--guest_ports="} + std::to_string(kFirstEmulatorPort);
+}
+
+std::string GetHostPortArg() {
+  return std::string{"--host_ports="} +
+      std::to_string(kFirstEmulatorPort + (vsoc::GetDefaultInstance() - 1) * 2);
+}
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
@@ -419,9 +432,14 @@
 
   std::string entropy_source = "/dev/urandom";
 
-  auto port_arg = std::string{"--ports="} + FLAGS_socket_forward_proxy_ports;
+  auto guest_port_arg = GetGuestPortArg();
+  auto host_port_arg = GetHostPortArg();
+
   const char* const socket_proxy[] =
-    {FLAGS_socket_forward_proxy_binary.c_str(), port_arg.c_str(), NULL};
+    {FLAGS_socket_forward_proxy_binary.c_str(),
+     guest_port_arg.c_str(),
+     host_port_arg.c_str(),
+     NULL};
   subprocess(socket_proxy, nullptr, false);
 
   config::GuestConfig cfg;
diff --git a/host/commands/launch/pre_launch_initializers.h b/host/commands/launch/pre_launch_initializers.h
index 0d3746d..d5f44ed 100644
--- a/host/commands/launch/pre_launch_initializers.h
+++ b/host/commands/launch/pre_launch_initializers.h
@@ -22,11 +22,13 @@
 // source file and call from PreLaunchInitializers::Initialize().
 void InitializeScreenRegion();
 void InitializeRilRegion();
+void InitializeWifiRegion();
 
 class PreLaunchInitializers {
  public:
   static void Initialize() {
     InitializeScreenRegion();
     InitializeRilRegion();
+    InitializeWifiRegion();
   }
 };
diff --git a/host/commands/launch/screen_region_handler.cc b/host/commands/launch/screen_region_handler.cc
index 9ad0f50..5844537 100644
--- a/host/commands/launch/screen_region_handler.cc
+++ b/host/commands/launch/screen_region_handler.cc
@@ -30,7 +30,7 @@
   auto region =
       vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str());
   if (!region) {
-    LOG(INFO) << "Framebuffer region was not found";
+    LOG(ERROR) << "Framebuffer region was not found";
     return;
   }
   auto dest = region->data();
diff --git a/host/commands/launch/wifi_region_handler.cc b/host/commands/launch/wifi_region_handler.cc
new file mode 100644
index 0000000..7f82c6a
--- /dev/null
+++ b/host/commands/launch/wifi_region_handler.cc
@@ -0,0 +1,73 @@
+/*
+ * 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 <cassert>
+#include <string>
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+#include "common/vsoc/lib/wifi_exchange_view.h"
+#include "host/commands/launch/pre_launch_initializers.h"
+#include "host/libs/config/host_config.h"
+
+using vsoc::wifi::WifiExchangeView;
+
+namespace {
+
+std::string GetPerInstanceDefaultMacAddress(const char* base_mac) {
+  WifiExchangeView::MacAddress addr;
+  if (!WifiExchangeView::ParseMACAddress(base_mac, &addr)) {
+    LOG(FATAL) << "Unable to parse MAC address: " << base_mac;
+    return "";
+  }
+  // Modify the last byte of the mac address to make it different for every cvd
+  addr.back() = static_cast<uint8_t>(vsoc::GetPerInstanceDefault(addr.back()));
+  return WifiExchangeView::MacAddressToString(addr);
+}
+
+}  // namespace
+
+DEFINE_string(guest_mac_address,
+              GetPerInstanceDefaultMacAddress("00:43:56:44:80:01"),
+              "MAC address of the wifi interface to be created on the guest.");
+
+DEFINE_string(host_mac_address,
+              "42:00:00:00:00:00",
+              "MAC address of the wifi interface running on the host.");
+
+void InitializeWifiRegion() {
+  auto region = WifiExchangeView::GetInstance(vsoc::GetDomain().c_str());
+  if (!region) {
+    LOG(FATAL) << "Wifi region not found";
+    return;
+  }
+  WifiExchangeView::MacAddress guest_mac, host_mac;
+  if (!WifiExchangeView::ParseMACAddress(FLAGS_guest_mac_address, &guest_mac)) {
+    LOG(FATAL) << "Unable to parse guest mac address: "
+               << FLAGS_guest_mac_address;
+    return;
+  }
+  LOG(INFO) << "Setting guest mac to " << FLAGS_guest_mac_address;
+  region->SetGuestMACAddress(guest_mac);
+  if (!WifiExchangeView::ParseMACAddress(FLAGS_host_mac_address, &host_mac)) {
+    LOG(FATAL) << "Unable to parse guest mac address: "
+               << FLAGS_guest_mac_address;
+    return;
+  }
+  LOG(INFO) << "Setting host mac to " << FLAGS_host_mac_address;
+  region->SetHostMACAddress(host_mac);
+}
diff --git a/host/libs/config/host_config.cpp b/host/libs/config/host_config.cpp
index cc0218d..df39bb6 100644
--- a/host/libs/config/host_config.cpp
+++ b/host/libs/config/host_config.cpp
@@ -16,21 +16,29 @@
 
 #include "host/libs/config/host_config.h"
 
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
 #include <string>
 #include <iomanip>
 #include <sstream>
 
 #include <gflags/gflags.h>
 
-const char kVsocUserPrefix[] = "vsoc-";
-const char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
+constexpr char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
 
-int GetDefaultInstance() {
-  char* user = getenv("USER");
-  if (user && !memcmp(user, kVsocUserPrefix, sizeof(kVsocUserPrefix) - 1)) {
-    int temp = atoi(user + sizeof(kVsocUserPrefix) - 1);
+DEFINE_string(domain, vsoc::GetDefaultShmClientSocketPath(),
+              "Path to the ivshmem client socket");
+DEFINE_int32(instance, vsoc::GetDefaultInstance(),
+             "Instance number. Must be unique.");
+DEFINE_string(uuid, vsoc::GetPerInstanceDefault(kDefaultUuidPrefix).c_str(),
+              "UUID to use for the device. Random if not specified");
+
+int vsoc::GetDefaultInstance() {
+  static constexpr char kVsocUserPrefix[] = "vsoc-";
+  const char* user = std::getenv("USER");
+  if (user && !std::strncmp(user, kVsocUserPrefix,
+                            sizeof(kVsocUserPrefix) - 1)) {
+    int temp = std::atoi(user + sizeof(kVsocUserPrefix) - 1);
     if (temp > 0) {
       return temp;
     }
@@ -38,13 +46,6 @@
   return 1;
 }
 
-DEFINE_string(domain, vsoc::GetDefaultShmClientSocketPath(),
-              "Path to the ivshmem client socket");
-DEFINE_int32(instance, GetDefaultInstance(),
-             "Instance number. Must be unique.");
-DEFINE_string(uuid, vsoc::GetPerInstanceDefault(kDefaultUuidPrefix).c_str(),
-              "UUID to use for the device. Random if not specified");
-
 std::string vsoc::GetPerInstanceDefault(const char* prefix) {
   std::ostringstream stream;
   stream << prefix << std::setfill('0') << std::setw(2)
diff --git a/host/libs/config/host_config.h b/host/libs/config/host_config.h
index 65ef523..15d2059 100644
--- a/host/libs/config/host_config.h
+++ b/host/libs/config/host_config.h
@@ -21,6 +21,7 @@
 #include <string>
 
 namespace vsoc {
+int GetDefaultInstance();
 std::string GetPerInstanceDefault(const char* prefix);
 int GetPerInstanceDefault(int base);
 std::string GetDefaultPerInstanceDir();