Merge "launch_cvd launches wmediumd"
diff --git a/build/Android.bp b/build/Android.bp
index b824a2b..d2c5e00 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -88,6 +88,8 @@
     "vnc_server",
     "webRTC",
     "webrtc_operator",
+    "wmediumd",
+    "wmediumd_gen_config",
 ]
 
 cvd_bluetooth_config_files = [
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 268062d..1e8a991 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -278,8 +278,14 @@
 
 DEFINE_bool(vhost_net, false, "Enable vhost acceleration of networking");
 
-DEFINE_string(vhost_user_mac80211_hwsim, "",
-              "Unix socket path for vhost-user of mac80211_hwsim");
+DEFINE_string(
+    vhost_user_mac80211_hwsim, "",
+    "Unix socket path for vhost-user of mac80211_hwsim, typically served by "
+    "wmediumd. You can set this when using an external wmediumd instance.");
+DEFINE_string(wmediumd_config, "",
+              "Path to the wmediumd config file. When missing, the default "
+              "configuration is used which adds MAC addresses for up to 16 "
+              "cuttlefish instances including AP.");
 DEFINE_string(ap_rootfs_image, "", "rootfs image for AP instance");
 DEFINE_string(ap_kernel_image, "", "kernel image for AP instance");
 
@@ -716,15 +722,13 @@
   if ((FLAGS_ap_rootfs_image.empty()) != (FLAGS_ap_kernel_image.empty())) {
     LOG(FATAL) << "Either both ap_rootfs_image and ap_kernel_image should be "
                   "set or neither should be set.";
-  } else if (FLAGS_vhost_user_mac80211_hwsim.empty() &&
-             !FLAGS_ap_rootfs_image.empty() && !FLAGS_ap_kernel_image.empty()) {
-    LOG(FATAL) << "To use external AP instance, vhost_user_mac80211_hwsim must "
-                  "be set.";
   }
 
   tmp_config_obj.set_ap_rootfs_image(FLAGS_ap_rootfs_image);
   tmp_config_obj.set_ap_kernel_image(FLAGS_ap_kernel_image);
 
+  tmp_config_obj.set_wmediumd_config(FLAGS_wmediumd_config);
+
   tmp_config_obj.set_record_screen(FLAGS_record_screen);
 
   tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth);
@@ -854,6 +858,21 @@
     } else {
       instance.set_start_webrtc_signaling_server(false);
     }
+
+    // Start wmediumd process for the first instance if
+    // vhost_user_mac80211_hwsim is not specified.
+    const bool start_wmediumd =
+        FLAGS_vhost_user_mac80211_hwsim.empty() && is_first_instance;
+    if (start_wmediumd) {
+      // TODO(b/199020470) move this to the directory for shared resources
+      auto socket_path =
+          const_instance.PerInstanceInternalPath("vhost_user_mac80211");
+      tmp_config_obj.set_vhost_user_mac80211_hwsim(socket_path);
+      instance.set_start_wmediumd(true);
+    } else {
+      instance.set_start_wmediumd(false);
+    }
+
     is_first_instance = false;
 
     // instance.modem_simulator_ports := "" or "[port,]*port"
diff --git a/host/commands/run_cvd/launch.cc b/host/commands/run_cvd/launch.cc
index 5c27fcb..93de92c 100644
--- a/host/commands/run_cvd/launch.cc
+++ b/host/commands/run_cvd/launch.cc
@@ -631,6 +631,54 @@
   SharedFD console_forwarder_out_rd_;
 };
 
+class WmediumdServer : public CommandSource {
+ public:
+  INJECT(WmediumdServer(const CuttlefishConfig& config,
+                        const CuttlefishConfig::InstanceSpecific& instance))
+      : config_(config), instance_(instance) {}
+
+  // CommandSource
+  std::vector<Command> Commands() override {
+    Command cmd(WmediumdBinary());
+    cmd.AddParameter("-u", config_.vhost_user_mac80211_hwsim());
+    cmd.AddParameter("-c", config_path_);
+    return single_element_emplace(std::move(cmd));
+  }
+
+  // Feature
+  bool Enabled() const override { return instance_.start_wmediumd(); }
+  std::string Name() const override { return "WmediumdServer"; }
+  std::unordered_set<Feature*> Dependencies() const override { return {}; }
+
+ protected:
+  bool Setup() override {
+    // If wmediumd configuration is given, use it
+    if (!config_.wmediumd_config().empty()) {
+      config_path_ = config_.wmediumd_config();
+      return true;
+    }
+    // Otherwise, generate wmediumd configuration using the current wifi mac
+    // prefix before start
+    config_path_ = instance_.PerInstanceInternalPath("wmediumd.cfg");
+    Command gen_config_cmd(WmediumdGenConfigBinary());
+    gen_config_cmd.AddParameter("-o", config_path_);
+    gen_config_cmd.AddParameter("-p", instance_.wifi_mac_prefix());
+
+    int success = gen_config_cmd.Start().Wait();
+    if (success != 0) {
+      LOG(ERROR) << "Unable to run " << gen_config_cmd.Executable()
+                 << ". Exited with status " << success;
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  const CuttlefishConfig& config_;
+  const CuttlefishConfig::InstanceSpecific& instance_;
+  std::string config_path_;
+};
+
 using PublicDeps = fruit::Required<const CuttlefishConfig,
                                    const CuttlefishConfig::InstanceSpecific>;
 fruit::Component<PublicDeps, KernelLogPipeProvider> launchComponent() {
@@ -651,7 +699,8 @@
       .install(Bases::Impls<RootCanal>)
       .install(Bases::Impls<SecureEnvironment>)
       .install(Bases::Impls<TombstoneReceiver>)
-      .install(Bases::Impls<VehicleHalServer>);
+      .install(Bases::Impls<VehicleHalServer>)
+      .install(Bases::Impls<WmediumdServer>);
 }
 
 } // namespace cuttlefish
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 4a1a142..8012eda 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -694,6 +694,14 @@
   (*dictionary_)[kApKernelImage] = ap_kernel_image;
 }
 
+static constexpr char kWmediumdConfig[] = "wmediumd_config";
+void CuttlefishConfig::set_wmediumd_config(const std::string& config) {
+  (*dictionary_)[kWmediumdConfig] = config;
+}
+std::string CuttlefishConfig::wmediumd_config() const {
+  return (*dictionary_)[kWmediumdConfig].asString();
+}
+
 static constexpr char kRecordScreen[] = "record_screen";
 void CuttlefishConfig::set_record_screen(bool record_screen) {
   (*dictionary_)[kRecordScreen] = record_screen;
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index a6a640c..3d73718 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -289,6 +289,9 @@
   void set_ap_kernel_image(const std::string& path);
   std::string ap_kernel_image() const;
 
+  void set_wmediumd_config(const std::string& path);
+  std::string wmediumd_config() const;
+
   void set_record_screen(bool record_screen);
   bool record_screen() const;
 
@@ -444,6 +447,9 @@
     // Whether this instance should start the webrtc signaling server
     bool start_webrtc_sig_server() const;
 
+    // Whether this instance should start the wmediumd process
+    bool start_wmediumd() const;
+
     // Wifi MAC address inside the guest
     int wifi_mac_prefix() const;
 
@@ -500,6 +506,7 @@
     void set_virtual_disk_paths(const std::vector<std::string>& disk_paths);
     void set_webrtc_device_id(const std::string& id);
     void set_start_webrtc_signaling_server(bool start);
+    void set_start_wmediumd(bool start);
     // Wifi MAC address inside the guest
     void set_wifi_mac_prefix(const int wifi_mac_prefix);
     // Gnss grpc proxy server port inside the host
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index 81cf7db..1016b6f 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -444,6 +444,14 @@
   return (*Dictionary())[kStartSigServer].asBool();
 }
 
+static constexpr char kStartWmediumd[] = "start_wmediumd";
+void CuttlefishConfig::MutableInstanceSpecific::set_start_wmediumd(bool start) {
+  (*Dictionary())[kStartWmediumd] = start;
+}
+bool CuttlefishConfig::InstanceSpecific::start_wmediumd() const {
+  return (*Dictionary())[kStartWmediumd].asBool();
+}
+
 std::string CuttlefishConfig::InstanceSpecific::touch_socket_path(
     int screen_idx) const {
   return PerInstanceInternalPath(
diff --git a/host/libs/config/known_paths.cpp b/host/libs/config/known_paths.cpp
index bd95799..8cf96ed 100644
--- a/host/libs/config/known_paths.cpp
+++ b/host/libs/config/known_paths.cpp
@@ -79,4 +79,10 @@
   return HostBinaryPath("webrtc_operator");
 }
 
+std::string WmediumdBinary() { return HostBinaryPath("wmediumd"); }
+
+std::string WmediumdGenConfigBinary() {
+  return HostBinaryPath("wmediumd_gen_config");
+}
+
 } // namespace cuttlefish
diff --git a/host/libs/config/known_paths.h b/host/libs/config/known_paths.h
index 635f1a8..cdf93f9 100644
--- a/host/libs/config/known_paths.h
+++ b/host/libs/config/known_paths.h
@@ -34,5 +34,7 @@
 std::string VncServerBinary();
 std::string WebRtcBinary();
 std::string WebRtcSigServerBinary();
+std::string WmediumdBinary();
+std::string WmediumdGenConfigBinary();
 
 } // namespace cuttlefish
diff --git a/host/libs/vm_manager/Android.bp b/host/libs/vm_manager/Android.bp
index 20c9027..0699409 100644
--- a/host/libs/vm_manager/Android.bp
+++ b/host/libs/vm_manager/Android.bp
@@ -17,6 +17,28 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+soong_config_module_type {
+    name: "cf_cc_defaults",
+    module_type: "cc_defaults",
+    config_namespace: "cvd_host",
+    bool_variables: ["enforce_mac80211_hwsim"],
+    properties: ["cflags"],
+}
+
+// This is the customization layer driven by soong config variables.
+cf_cc_defaults {
+    name: "cvd_cc_defaults",
+    soong_config_variables: {
+        // PRODUCT_ENFORCE_MAC80211_HWSIM sets this
+        enforce_mac80211_hwsim: {
+            cflags: ["-DENFORCE_MAC80211_HWSIM=true"],
+            conditions_default: {
+                cflags: [],
+            }
+        },
+    }
+}
+
 cc_library_static {
     name: "libcuttlefish_vm_manager",
     srcs: [
@@ -37,5 +59,9 @@
     static_libs: [
         "libcuttlefish_host_config",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: [
+        "cuttlefish_host",
+        "cuttlefish_libicuuc",
+        "cvd_cc_defaults",
+    ],
 }
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index b4360a5..cb9c662 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -297,11 +297,15 @@
   AddTapFdParameter(&crosvm_cmd, instance.ethernet_tap_name());
 
   SharedFD wifi_tap;
-  if (config.vhost_user_mac80211_hwsim().empty()) {
-    wifi_tap = AddTapFdParameter(&crosvm_cmd, instance.wifi_tap_name());
-  } else if (use_ap_instance) {
+  // TODO(b/199103204): remove this as well when PRODUCT_ENFORCE_MAC80211_HWSIM
+  // is removed
+#ifdef ENFORCE_MAC80211_HWSIM
+  if (use_ap_instance) {
     wifi_tap = AddTapFdParameter(&ap_cmd, instance.wifi_tap_name());
   }
+#else
+  wifi_tap = AddTapFdParameter(&crosvm_cmd, instance.wifi_tap_name());
+#endif
 
   if (FileExists(instance.access_kregistry_path())) {
     crosvm_cmd.AddParameter("--rw-pmem-device=",
@@ -434,7 +438,7 @@
   // bridge architecture - in that case, we have a wider DHCP address
   // space and stale leases should be much less of an issue
   if (!FileExists("/var/run/cuttlefish-dnsmasq-cvd-wbr.leases") &&
-      (config.vhost_user_mac80211_hwsim().empty() || use_ap_instance)) {
+      wifi_tap->IsOpen()) {
     // TODO(schuffelen): QEMU also needs this and this is not the best place for
     // this code. Find a better place to put it.
     auto lease_file =
diff --git a/shared/device.mk b/shared/device.mk
index 3b0f901..0e63ff6 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -632,6 +632,11 @@
     device/google/cuttlefish/guest/services/wifi/init.wifi.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.wifi.sh \
 
 PRODUCT_VENDOR_PROPERTIES += ro.vendor.wifi_impl=mac8011_hwsim_virtio
+
+SOONG_CONFIG_NAMESPACES += cvd_host
+SOONG_CONFIG_cvd_host += enforce_mac80211_hwsim
+SOONG_CONFIG_cvd_host_enforce_mac80211_hwsim += true
+
 else
 PRODUCT_PACKAGES += setup_wifi
 PRODUCT_VENDOR_PROPERTIES += ro.vendor.wifi_impl=virt_wifi