blob: 5118f25aed5df3aa335fef795e715fe6b862ee32 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::subsystems::prelude::*;
use crate::util;
use anyhow::bail;
use assembly_config_capabilities::{Config, ConfigValueType};
use assembly_config_schema::platform_config::connectivity_config::{
NetstackVersion, NetworkingConfig, PlatformConnectivityConfig, WlanPolicyLayer,
WlanRecoveryProfile,
};
use assembly_util::{FileEntry, PackageDestination, PackageSetDestination};
pub(crate) struct ConnectivitySubsystemConfig;
impl DefineSubsystemConfiguration<PlatformConnectivityConfig> for ConnectivitySubsystemConfig {
fn define_configuration(
context: &ConfigurationContext<'_>,
connectivity_config: &PlatformConnectivityConfig,
builder: &mut dyn ConfigurationBuilder,
) -> anyhow::Result<()> {
let publish_fuchsia_dev_wired_service = match (
context.feature_set_level,
context.build_type,
connectivity_config.mdns.publish_fuchsia_dev_wired_service,
) {
// FFX discovery is not enabled on bootstrap, therefore we do not need the wired
// udp service.
(FeatureSupportLevel::Bootstrap, _, _) => false,
// User builds cannot have this service enabled.
(_, BuildType::User, None) => false,
(_, BuildType::User, Some(true)) => {
bail!("A MDNS wired udp service cannot be enabled on user builds")
}
// Userdebug and eng builds have this service enabled by default.
(_, _, None) => true,
// The product can override the default only on userdebug and eng builds.
(_, _, Some(b)) => b,
};
if publish_fuchsia_dev_wired_service {
builder.platform_bundle("mdns_fuchsia_device_wired_service");
}
if let Some(mdns_config) = &connectivity_config.mdns.config {
builder.package("mdns").config_data(FileEntry {
source: mdns_config.clone(),
destination: "assembly.config".into(),
})?;
}
// The configuration of networking is dependent on all three of:
// - the feature_set_level
// - the build_type
// - the requested configuration type
let networking = match (
context.feature_set_level,
context.build_type,
&connectivity_config.network.networking,
) {
// bootstrap must not attempt to configure it, it's always None
(FeatureSupportLevel::Bootstrap, _, Some(_)) => {
bail!("The configuration of networking is not an option for `bootstrap`")
}
(FeatureSupportLevel::Bootstrap, _, None) => None,
// utility, in user mode, only gets networking if requested.
(FeatureSupportLevel::Utility, BuildType::User, networking) => networking.as_ref(),
// all other combinations get the network package that they request
(_, _, Some(networking)) => Some(networking),
// otherwise, the 'standard' networking package is used
(_, _, None) => Some(&NetworkingConfig::Standard),
};
if let Some(networking) = networking {
let maybe_gub_bundle = |bundle| {
if connectivity_config.network.use_unified_binary {
format!("{bundle}_gub").into()
} else {
std::borrow::Cow::Borrowed(bundle)
}
};
// The 'core_realm_networking' and 'network_realm' bundles are
// required if networking is enabled.
builder.platform_bundle("core_realm_networking");
builder.platform_bundle("network_realm");
builder.platform_bundle(maybe_gub_bundle("network_realm_packages").as_ref());
// Which specific network package is selectable by the product.
match networking {
NetworkingConfig::Standard => {
builder.platform_bundle("networking_with_virtualization");
}
NetworkingConfig::Basic => {
builder.platform_bundle("networking_basic");
builder.platform_bundle(maybe_gub_bundle("networking_basic_packages").as_ref());
}
}
let config_src = connectivity_config
.network
.netcfg_config_path
.clone()
.unwrap_or(context.get_resource("netcfg_default.json"));
let config_dir = builder
.add_domain_config(PackageSetDestination::Blob(PackageDestination::NetcfgConfig))
.directory("netcfg-config");
config_dir.entry(FileEntry {
source: config_src,
destination: "netcfg_default.json".into(),
})?;
if let Some(netstack_config_path) = &connectivity_config.network.netstack_config_path {
builder.package("netstack").config_data(FileEntry {
source: netstack_config_path.clone(),
destination: "default.json".into(),
})?;
}
if let Some(google_maps_api_key_path) =
&connectivity_config.network.google_maps_api_key_path
{
builder.package("emergency").config_data(FileEntry {
source: google_maps_api_key_path.clone(),
destination: "google_maps_api_key.txt".into(),
})?;
}
if let Some(timeout) =
connectivity_config.network.http_client_stop_on_idle_timeout_millis
{
builder.set_config_capability(
"fuchsia.http-client.StopOnIdleTimeoutMillis",
Config::new(ConfigValueType::Int64, timeout.into()),
)?;
}
// The use of netstack3 can be forcibly required by the board,
// otherwise it's selectable by the product.
match (
context.board_info.provides_feature("fuchsia::network_require_netstack3"),
connectivity_config.network.netstack_version,
) {
(true, _) | (false, NetstackVersion::Netstack3) => {
builder.platform_bundle("netstack3");
builder.platform_bundle(maybe_gub_bundle("netstack3_packages").as_ref());
}
(false, NetstackVersion::Netstack2) => builder.platform_bundle("netstack2"),
(false, NetstackVersion::NetstackMigration) => {
builder.platform_bundle("netstack_migration");
builder
.platform_bundle(maybe_gub_bundle("netstack_migration_packages").as_ref());
}
}
// Add the networking test collection on all eng builds. The test
// collection allows components to be launched inside the network
// realm with access to all networking related capabilities.
match context.build_type {
BuildType::Eng => builder.platform_bundle("networking_test_collection"),
_ => {}
}
let has_fullmac = context.board_info.provides_feature("fuchsia::wlan_fullmac");
let has_softmac = context.board_info.provides_feature("fuchsia::wlan_softmac");
if has_fullmac || has_softmac {
// Select the policy layer
match connectivity_config.wlan.policy_layer {
WlanPolicyLayer::ViaWlanix => {
builder.platform_bundle("wlan_wlanix");
// Ensure we don't have invalid recovery settings
if connectivity_config.wlan.recovery_profile.is_some() {
bail!(
"wlan.recovery_profile is invalid with wlan.policy_layer ViaWlanix"
)
}
if connectivity_config.wlan.recovery_enabled {
bail!(
"wlan.recovery_enabled is invalid with wlan.policy_layer ViaWlanix"
)
}
}
WlanPolicyLayer::Platform => {
builder.platform_bundle("wlan_policy");
// Add in the recovery characteristics specified by the product config.
let recovery_profile = match connectivity_config.wlan.recovery_profile {
None => String::from(""),
Some(WlanRecoveryProfile::ThresholdedRecovery) => {
String::from("thresholded_recovery")
}
};
builder.set_config_capability(
"fuchsia.wlan.RecoveryEnabled",
Config::new(
ConfigValueType::Bool,
connectivity_config.wlan.recovery_enabled.clone().into(),
),
)?;
builder.set_config_capability(
"fuchsia.wlan.RecoveryProfile",
Config::new(
ConfigValueType::String { max_size: 512 },
recovery_profile.into(),
),
)?;
}
}
// Add development support on eng and userdebug systems if we have wlan.
match context.build_type {
BuildType::Eng | BuildType::UserDebug => {
builder.platform_bundle("wlan_development")
}
_ => {}
}
// Some products require legacy security types to be supported.
// Otherwise, they are disabled by default.
if connectivity_config.wlan.legacy_privacy_support {
builder.platform_bundle("wlan_legacy_privacy_support");
} else {
builder.platform_bundle("wlan_contemporary_privacy_only_support");
}
if has_fullmac {
builder.platform_bundle("wlan_fullmac_support");
}
if has_softmac {
builder.platform_bundle("wlan_softmac_support");
}
}
if connectivity_config.network.include_tun {
builder.platform_bundle("network_tun");
}
if connectivity_config.thread.include_lowpan {
builder.platform_bundle("thread_lowpan");
}
}
// Add the weave core shard if necessary.
if let Some(url) = &connectivity_config.weave.component_url {
util::add_platform_declared_product_provided_component(
url,
"weavestack.core_shard.cml.template",
context,
builder,
)?;
}
if let Some(netsvc_interface) =
&context.board_info.platform.connectivity.network.netsvc_interface
{
let arg = format!("netsvc.interface={}", netsvc_interface);
builder.kernel_arg(arg);
}
Ok(())
}
}