blob: b89bdfee39ff5d2fc2dbaac3ee60c7d4a6a6b1c3 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_TETHERING_MANAGER_H_
#define SHILL_TETHERING_MANAGER_H_
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <vector>
#include <base/cancelable_callback.h>
#include <base/files/scoped_file.h>
#include "base/functional/callback_forward.h"
#include <base/memory/weak_ptr.h>
#include <chromeos/patchpanel/dbus/client.h>
#include "shill/mac_address.h"
#include "shill/network/network.h"
#include "shill/network/network_monitor.h"
#include "shill/refptr_types.h"
#include "shill/store/property_store.h"
#include "shill/technology.h"
#include "shill/wifi/local_device.h"
#include "shill/wifi/wifi_phy.h"
#include "shill/wifi/wifi_rf.h"
#include "shill/wifi/wifi_security.h"
namespace shill {
class Manager;
class StoreInterface;
// TetheringManager handles tethering related logics. It is created by the
// Manager class.
//
// It reuses the Profile class to persist the tethering parameters for each
// user. Without user's input, it uses the default tethering configuration with
// a random SSID and a random passphrase. It saves the current tethering
// configuration to user profile when the user sets tethering config, or user
// enables tethering.
//
// It interacts with HotspotDevice,
// CellularServiceProvider and EthernetProvider classes to prepare upstream and
// downstream technologies. It interacts with patchpanel via dbus to set up the
// tethering network.
class TetheringManager : public Network::EventHandler {
public:
enum class EntitlementStatus {
kReady,
kNotAllowed,
kNotAllowedByCarrier,
kNotAllowedOnFw,
kNotAllowedOnVariant,
kNotAllowedUserNotEntitled,
kUpstreamNetworkNotAvailable,
};
enum class CellularUpstreamEvent {
kUserNoLongerEntitled, // The user is no longer entitled to tether.
};
static const char* EntitlementStatusName(EntitlementStatus status);
enum class SetEnabledResult {
// Successfully start/stop tethering session
kSuccess,
// Tethering is not allowed
kNotAllowed,
// Tethering config has invalid property
kInvalidProperties,
// Start/stop tethering when it is in a wrong state
kWrongState,
// Upstream network was not created or was not connected.
kUpstreamNetworkNotAvailable,
// Upstream network operation failure
kUpstreamFailure,
// Downstream WiFi operation failure
kDownstreamWiFiFailure,
// Failed to setup/tear down network layer for tethering
kNetworkSetupFailure,
// Starting action is aborted by user
kAbort,
// Start/stop tethering when previous action is ongoing
kBusy,
// Cannot start tethering because the tethering interface cannot be
// operated concurrently with existing interfaces.
kConcurrencyNotSupported,
// Other unknown failures
kFailure,
};
static const std::string SetEnabledResultName(SetEnabledResult result);
enum class TetheringState {
kTetheringIdle,
kTetheringStarting,
kTetheringActive,
kTetheringStopping,
kTetheringRestarting,
};
using AcquireNetworkCallback = base::OnceCallback<void(
TetheringManager::SetEnabledResult, Network*, ServiceRefPtr)>;
using UpdateTimeoutCallback =
base::RepeatingCallback<void(base::TimeDelta timeout)>;
using CellularUpstreamEventCallback =
base::RepeatingCallback<void(TetheringManager::CellularUpstreamEvent)>;
// Storage group for tethering configs.
static constexpr char kStorageId[] = "tethering";
explicit TetheringManager(Manager* manager);
TetheringManager(const TetheringManager&) = delete;
TetheringManager& operator=(const TetheringManager&) = delete;
virtual ~TetheringManager();
// Initialize DBus properties related to tethering.
void InitPropertyStore(PropertyStore* store);
// Start and initialize TetheringManager.
void Start();
// Stop TetheringManager.
void Stop();
// DEPRECATED. Clients should use Enable/Disable instead.
// Enable or disable a tethering session with existing tethering config.
// TODO(b/331632285): Delete this API once clients have transition over to
// using Enable/Disable.
void SetEnabled(bool enabled,
base::OnceCallback<void(SetEnabledResult result)> callback);
// Enable a tethering session with existing tethering config and |priority|.
void Enable(uint32_t priority,
base::OnceCallback<void(SetEnabledResult result)> callback);
// Disable the active tethering session.
void Disable(base::OnceCallback<void(SetEnabledResult result)> callback);
// Check if upstream network is ready for tethering.
void CheckReadiness(
base::OnceCallback<void(EntitlementStatus result)> callback);
// Load the tethering config available in |profile| if there was any tethering
// config saved for this |profile|.
virtual void LoadConfigFromProfile(const ProfileRefPtr& profile);
// Unload the tethering config related to |profile| and reset the tethering
// config with default values.
virtual void UnloadConfigFromProfile();
static const char* TetheringStateName(const TetheringState& state);
// Get the current TetheringStatus dictionary.
KeyValueStore GetStatus();
// DBus property getters
// This property is temporary and will be removed when the feature is mature.
bool allowed() { return allowed_; }
KeyValueStore GetCapabilities(Error* error);
// Refresh the list of tethering capabilities
void RefreshCapabilities();
// Indicates that a HotspotDevice has been created by WiFiProvider.
mockable void OnDeviceCreated(HotspotDeviceRefPtr hotspot_dev);
// Indicates that HotspotDevice creation has failed.
void OnDeviceCreationFailed();
private:
friend class TetheringManagerTest;
FRIEND_TEST(TetheringManagerTest, TetheringConfigLoadAndUnload);
FRIEND_TEST(TetheringManagerTest, GetTetheringCapabilities);
FRIEND_TEST(TetheringManagerTest, MARWithSSIDChange);
FRIEND_TEST(TetheringManagerTest, MARWithTetheringRestart);
FRIEND_TEST(TetheringManagerTest, CheckMACStored);
enum class StopReason {
kInitial, // Initial idle state.
kClientStop, // Client explicitly stops tethering.
kUserExit, // User logs out or shuts down device.
kSuspend, // Device suspend.
kUpstreamNotAvailable, // Upstream network not available.
kUpstreamDisconnect, // Upstream network disconnects.
kUpstreamNoInternet, // Upstream has no Internet connectivity.
kInactive, // Inactive timer fires.
kError, // Unexpected internal error.
kConfigChange, // Config is changed.
kDownstreamLinkDisconnect, // Downstream link disconnects.
kDownstreamNetDisconnect, // Downstream network disconnects.
kStartTimeout, // Failed to start tethering within given time.
kResourceBusy, // Device resources are busy with other tasks.
};
// Convert stop reason enum to string.
static const char* StopReasonToString(StopReason reason);
using SetEnabledResultCallback =
base::OnceCallback<void(SetEnabledResult result)>;
void HelpRegisterDerivedBool(PropertyStore* store,
std::string_view name,
bool (TetheringManager::*get)(Error* error),
bool (TetheringManager::*set)(const bool&,
Error*));
// DBUS accessors
bool SetAllowed(const bool& value, Error* error);
bool GetAllowed(Error* /*error*/) { return allowed_; }
bool SetExperimentalTetheringFunctionality(const bool& value, Error* error);
bool GetExperimentalTetheringFunctionality(Error* /*error*/) {
return experimental_tethering_functionality_;
}
// Tethering properties get handlers.
KeyValueStore GetConfig(Error* error);
KeyValueStore GetStatus(Error* error) { return GetStatus(); }
void SetCapabilities(const KeyValueStore& value);
// Overrides for Network::EventHandler. See the comments for
// Network::EventHandler for more details. TetheringManager only cares about
// NetworkValidationResult NetworkDestroyed and Networkstopped event.
void OnNetworkValidationResult(int interface_index,
const NetworkMonitor::Result& result) override;
void OnNetworkStopped(int interface_index, bool is_failure) override;
void OnNetworkDestroyed(int network_id, int interface_index) override;
void OnNetworkValidationStart(int interface_index, bool is_failure) override;
void OnNetworkValidationStop(int interface_index, bool is_failure) override;
bool SetAndPersistConfig(const KeyValueStore& config, Error* error);
// Populate the shill D-Bus parameter map |properties| with the
// parameters contained in |this| and return true if successful.
bool ToProperties(KeyValueStore* properties) const;
// Populate tethering config from a dictionary.
// Return nullopt if properties are invalid. If a restart is needed to make
// the new config take effect, return true. Otherwise, return false.
std::optional<bool> FromProperties(const KeyValueStore& properties);
// Reset tethering config with default value and a random WiFi SSID and
// a random passphrase.
void ResetConfiguration();
// Save the current tethering config to user's profile.
bool Save(StoreInterface* storage);
// Load the current tethering config from user's profile.
bool Load(const StoreInterface* storage);
// Set tethering state and emit dbus property changed signal.
void SetState(TetheringState state);
// Downstream device enabled event handler.
void OnDownstreamDeviceEnabled();
// Peer assoc event handler.
void OnPeerAssoc();
// Peer disassoc event handler.
void OnPeerDisassoc();
// Downstream device event handler.
void OnDownstreamDeviceEvent(LocalDevice::DeviceEvent event,
const LocalDevice* device);
// patchpanel DownstreamNetwork callback handler.
void OnDownstreamNetworkReady(
base::ScopedFD downstream_network_fd,
const patchpanel::Client::DownstreamNetwork& downstream_network);
// Upstream network fetch callback handler.
void OnUpstreamNetworkAcquired(SetEnabledResult result,
Network* network,
ServiceRefPtr service);
// Upstream network release callback handler.
void OnUpstreamNetworkReleased(bool is_success);
// Cellular Upstream event callback handler.
void OnCellularUpstreamEvent(TetheringManager::CellularUpstreamEvent event);
// Trigger callback function asynchronously to post SetTetheringEnabled dbus
// result.
void PostSetEnabledResult(SetEnabledResult result);
// Check if the downstream and upstream network interfaces are ready and if
// the downstream network can be tethered to the upstream network.
void CheckAndStartDownstreamTetheredNetwork();
// Check if all the tethering resources are ready. If so post the
// SetTetheringEnabled(true) dbus result.
void CheckAndPostTetheringStartResult();
// Check if all the tethering resources are freed. If so post the
// SetTetheringEnabled(false) dbus result.
void CheckAndPostTetheringStopResult();
// Handler function to be called when a new start timeout is requested.
void OnStartingTetheringUpdateTimeout(base::TimeDelta timeout);
// Handler function to be called when starting tethering session times out.
void OnStartingTetheringTimeout();
// Handler function to be called when stopping tethering session times out.
void OnStoppingTetheringTimeout();
// Prepare tethering resources to start a tethering session with |priority|.
void StartTetheringSession(WiFiPhy::Priority priority);
// Stop and free tethering resources due to reason |reason|.
// Keep upstream network untouched if |bypass_upstream| is true.
void StopTetheringSession(StopReason reason, bool bypass_upstream = false);
// Kick off the tethering inactive timer when auto_disable_ is true and
// TetheringState is kTetheringActive. Will not rearm the timer if it is
// already running. It will tear down tethering session after timer fires.
void StartInactiveTimer();
// Cancel the tethering inactive timer due to station associates or
// auto_disable_ is changed to false.
void StopInactiveTimer();
// Start the tethering upstream Network validation timer when TetheringState
// is kTetheringActive, unless the timer is already counting down. If the
// timer is not cancelled, the tethering session is town down when the
// timer fires.
void StartUpstreamNetworkValidationTimer();
// Cancel the tethering upstream Network validation timer after verifying
// the connectivity state of the upstream Network.
void StopUpstreamNetworkValidationTimer();
// Get the number of active clients.
size_t GetClientCount();
// Deregister upstream network listener and free the network.
void FreeUpstreamNetwork();
// Returns true if the upstream network is defined, is connected, and is in a
// validation state compatible with tethering.
bool IsUpstreamNetworkReady();
// TetheringManager is created and owned by Manager.
Manager* manager_;
// Tethering feature flag.
bool allowed_;
// Flag to enable tethering on untested carriers/modems and modem FWs.
bool experimental_tethering_functionality_;
// Tethering state as listed in enum TetheringState.
TetheringState state_;
// Executes when the tethering start timer expires. Calls
// OnStartingTetheringTimeout.
base::CancelableOnceClosure start_timer_callback_;
// Executes when the tethering stop timer expires. Calls
// OnStopTetheringTimeout.
base::CancelableOnceClosure stop_timer_callback_;
// Executes when the inactive timer expires. Calls StopTetheringSession.
base::CancelableOnceClosure inactive_timer_callback_;
// Executes when the upstream network validation timer expires. Calls
// StopTetheringSession.
base::CancelableOnceClosure upstream_network_validation_timer_callback_;
// Automatically disable tethering if no devices have been associated for
// |kAutoDisableMinute| minutes.
bool auto_disable_;
// MAC address randomization. When it is true, AP will use a randomized MAC
// each time it is started. If false, it will use the persisted MAC address.
bool mar_;
// MAC address to be used when |mar_| is false (otherwise address will be
// randomized each time tethering session starts).
MACAddress stable_mac_addr_;
// The hex-encoded tethering SSID name to be used in WiFi downstream.
std::string hex_ssid_;
// The passphrase to be used in WiFi downstream.
std::string passphrase_;
// The security mode to be used in WiFi downstream.
WiFiSecurity security_;
// The preferred band to be used in WiFi downstream.
WiFiBand band_;
// Preferred upstream technology to use.
Technology upstream_technology_;
// The supported tethering capabilities.
KeyValueStore capabilities_;
// The assigned downstream device, only used for testing. This property is
// never persisted.
std::optional<std::string> downstream_device_for_test_;
// The phy index of the assigned downstream device, only used for testing.
// This property is never persisted.
std::optional<uint32_t> downstream_phy_index_for_test_;
// Pointer to upstream network. This pointer is valid when state_ is not
// kTetheringIdle.
Network* upstream_network_;
// Pointer to upstream service. This pointer is valid when |upstream_network_|
// is not nullptr.
ServiceRefPtr upstream_service_;
// File descriptor representing the downstream network setup managed by
// patchpanel. Closing this file descriptor tears down the downstream network.
// TODO(b/275645124) Handle DownstreamNetwork errors raised by patchpanel
// during a tethering session and stop the tethering session.
base::ScopedFD downstream_network_fd_;
// True if the request to start a downstream network has been sent to
// patchpanel for the current tethering session.
bool downstream_network_started_;
// Member to hold the result callback function. This callback function gets
// set when dbus method SetTetheringEnabled is called and runs when the async
// method call is done.
SetEnabledResultCallback result_callback_;
// Downlink hotspot device.
HotspotDeviceRefPtr hotspot_dev_;
// If downstream hotspot device event kLinkUp has been received or not.
bool hotspot_service_up_;
// The reason why tethering is stopped.
StopReason stop_reason_;
};
inline std::ostream& operator<<(std::ostream& stream,
TetheringManager::TetheringState state) {
return stream << TetheringManager::TetheringStateName(state);
}
} // namespace shill
#endif // SHILL_TETHERING_MANAGER_H_