blob: 555cdfe4733b8708e0fe6694534335f2e2b770b7 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/wifi/p2p_manager.h"
#include <ios>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <base/logging.h>
#include <chromeos/dbus/shill/dbus-constants.h>
#include "shill/control_interface.h"
#include "shill/error.h"
#include "shill/manager.h"
#include "shill/store/property_accessor.h"
#include "shill/supplicant/supplicant_p2pdevice_proxy_interface.h"
#include "shill/supplicant/supplicant_process_proxy_interface.h"
#include "shill/supplicant/wpa_supplicant.h"
#include "shill/wifi/local_device.h"
#include "shill/wifi/wifi_provider.h"
namespace shill {
P2PManager::P2PManager(Manager* manager)
: manager_(manager),
allowed_(false),
next_unique_id_(0),
supplicant_primary_p2pdevice_pending_event_delegate_(nullptr) {
supplicant_primary_p2pdevice_proxy_.reset();
}
P2PManager::~P2PManager() = default;
void P2PManager::InitPropertyStore(PropertyStore* store) {
HelpRegisterDerivedBool(store, kP2PAllowedProperty, &P2PManager::GetAllowed,
&P2PManager::SetAllowed);
HelpRegisterDerivedKeyValueStore(store, kP2PCapabilitiesProperty,
&P2PManager::GetCapabilities, nullptr);
HelpRegisterDerivedKeyValueStores(store, kP2PGroupInfosProperty,
&P2PManager::GetGroupInfos, nullptr);
HelpRegisterDerivedKeyValueStores(store, kP2PClientInfosProperty,
&P2PManager::GetClientInfos, nullptr);
}
bool P2PManager::IsP2PSupported() {
auto wifi_phys = manager_->wifi_provider()->GetPhys();
if (!wifi_phys.empty()) {
return wifi_phys.front()->SupportP2PMode();
}
LOG(ERROR) << "No WiFiPhy available";
return false;
}
String P2PManager::GroupReadiness() {
// TODO(b/295050788, b/299295629): it requires P2P/STA concurrency level
// and interface combination checking to be supported by wifi phy.
return kP2PCapabilitiesGroupReadinessNotReady;
}
String P2PManager::ClientReadiness() {
// TODO(b/295050788, b/299295629): it requires P2P/STA concurrency level
// and interface combination checking to be supported by wifi phy.
return kP2PCapabilitiesClientReadinessNotReady;
}
Integers P2PManager::SupportedChannels() {
// TODO(b/295050788, b/299295629): it requires P2P/STA concurrency level
// and interface combination checking to be supported by wifi phy.
Integers channels;
return channels;
}
Integers P2PManager::PreferredChannels() {
// TODO(b/295050788, b/299295629): it requires P2P/STA concurrency level
// and interface combination checking to be supported by wifi phy.
Integers channels;
return channels;
}
KeyValueStore P2PManager::GetCapabilities(Error* /* error */) {
KeyValueStore caps;
if (IsP2PSupported()) {
caps.Set<Boolean>(kP2PCapabilitiesP2PSupportedProperty, true);
caps.Set<String>(kP2PCapabilitiesGroupReadinessProperty, GroupReadiness());
caps.Set<String>(kP2PCapabilitiesClientReadinessProperty,
ClientReadiness());
caps.Set<Integers>(kP2PCapabilitiesSupportedChannelsProperty,
SupportedChannels());
caps.Set<Integers>(kP2PCapabilitiesPreferredChannelsProperty,
PreferredChannels());
} else {
caps.Set<Boolean>(kP2PCapabilitiesP2PSupportedProperty, false);
}
return caps;
}
KeyValueStores P2PManager::GetGroupInfos(Error* /* error */) {
KeyValueStores groupInfos;
for (const auto& it : p2p_group_owners_) {
groupInfos.push_back(it.second->GetGroupInfo());
}
return groupInfos;
}
KeyValueStores P2PManager::GetClientInfos(Error* /* error */) {
KeyValueStores clientInfos;
for (const auto& it : p2p_clients_) {
clientInfos.push_back(it.second->GetClientInfo());
}
return clientInfos;
}
void P2PManager::Start() {}
void P2PManager::Stop() {
// TODO(b/308081318) Cleanup active sessions.
if (!p2p_group_owners_.empty() || !p2p_clients_.empty()) {
LOG(WARNING) << "P2PManager has been stopped while some of P2P devices "
"are still active";
}
}
void P2PManager::ActionTimerExpired(bool is_start,
LocalDevice::IfaceType iface_type) {
if (iface_type != LocalDevice::IfaceType::kP2PGO &&
iface_type != LocalDevice::IfaceType::kP2PClient) {
LOG(ERROR) << __func__ << ": invalid interface type " << iface_type;
return;
}
if (!result_callback_) {
LOG(ERROR) << __func__ << ": no available callback";
return;
}
bool is_go = iface_type == LocalDevice::IfaceType::kP2PGO;
if (is_start) {
PostResult(
is_go ? kCreateP2PGroupResultTimeout : kConnectToP2PGroupResultTimeout,
std::nullopt, std::move(result_callback_));
} else {
PostResult(is_go ? kDestroyP2PGroupResultTimeout
: kDisconnectFromP2PGroupResultTimeout,
std::nullopt, std::move(result_callback_));
}
}
void P2PManager::CancelActionTimer() {
if (!action_timer_callback_.IsCancelled()) {
action_timer_callback_.Cancel();
LOG(INFO) << __func__ << ": action timer cancelled";
}
}
void P2PManager::SetActionTimer(bool is_start,
LocalDevice::IfaceType iface_type) {
auto timeout = is_start ? kP2PStartTimeout : kP2PStopTimeout;
CancelActionTimer();
action_timer_callback_.Reset(base::BindOnce(&P2PManager::ActionTimerExpired,
weak_ptr_factory_.GetWeakPtr(),
is_start, iface_type));
manager_->dispatcher()->PostDelayedTask(
FROM_HERE, action_timer_callback_.callback(), timeout);
LOG(INFO) << __func__ << ": action timer started, timeout: " << timeout;
}
void P2PManager::CreateP2PGroup(P2PResultCallback callback,
const KeyValueStore& args) {
LOG(INFO) << __func__;
CHECK(callback) << "Callback is empty";
if (supplicant_primary_p2pdevice_pending_event_delegate_ ||
result_callback_ || !action_timer_callback_.IsCancelled()) {
LOG(WARNING) << "Failed to create P2P group, operation is already "
"in progress";
PostResult(kCreateP2PGroupResultOperationInProgress, std::nullopt,
std::move(callback));
return;
}
result_callback_ = std::move(callback);
std::optional<std::string> ssid;
if (args.Contains<std::string>(kP2PDeviceSSID)) {
ssid = args.Get<std::string>(kP2PDeviceSSID);
}
std::optional<std::string> passphrase;
if (args.Contains<std::string>(kP2PDevicePassphrase)) {
passphrase = args.Get<std::string>(kP2PDevicePassphrase);
}
std::optional<int32_t> freq;
if (args.Contains<int32_t>(kP2PDeviceFrequency)) {
freq = args.Get<int32_t>(kP2PDeviceFrequency);
}
if (!args.Contains<int32_t>(kP2PDevicePriority)) {
LOG(ERROR) << std::string(kP2PDevicePriority) + " argument is mandatory";
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
WiFiPhy::Priority priority =
WiFiPhy::Priority(args.Get<int32_t>(kP2PDevicePriority));
if (!priority.IsValid()) {
LOG(ERROR) << "invalid " << std::string(kP2PDevicePriority) + " argument "
<< priority;
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
if (!ConnectToSupplicantPrimaryP2PDeviceProxy()) {
LOG(ERROR) << "Failed to create P2P group, primary P2PDevice proxy "
"is not connected";
PostResult(kCreateP2PGroupResultOperationFailed, std::nullopt,
std::move(callback));
return;
}
// Arm the start timer before sending the device creation request.
SetActionTimer(true, LocalDevice::IfaceType::kP2PGO);
bool request_accepted = manager_->wifi_provider()->RequestP2PDeviceCreation(
LocalDevice::IfaceType::kP2PGO,
base::BindRepeating(&P2PManager::OnP2PDeviceEvent,
base::Unretained(this)),
next_unique_id_, priority,
base::BindOnce(&P2PManager::OnDeviceCreated, base::Unretained(this),
LocalDevice::IfaceType::kP2PGO, ssid, passphrase, freq),
base::BindOnce(&P2PManager::OnDeviceCreationFailed,
base::Unretained(this), LocalDevice::IfaceType::kP2PGO));
next_unique_id_++;
if (!request_accepted) {
LOG(INFO)
<< "Failed to create a WiFi P2P interface due to concurrency conflict.";
CancelActionTimerAndPostResult(kCreateP2PGroupResultConcurrencyNotSupported,
std::nullopt);
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
return;
}
}
void P2PManager::ConnectToP2PGroup(P2PResultCallback callback,
const KeyValueStore& args) {
LOG(INFO) << __func__;
CHECK(callback) << "Callback is empty";
if (supplicant_primary_p2pdevice_pending_event_delegate_ ||
result_callback_ || !action_timer_callback_.IsCancelled()) {
LOG(WARNING) << "Failed to connect to P2P group, operation is already "
"in progress";
PostResult(kConnectToP2PGroupResultOperationInProgress, std::nullopt,
std::move(callback));
return;
}
result_callback_ = std::move(callback);
if (!args.Contains<std::string>(kP2PDeviceSSID)) {
LOG(ERROR) << std::string(kP2PDeviceSSID) + " argument is mandatory";
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
std::string ssid = args.Get<std::string>(kP2PDeviceSSID);
if (!args.Contains<std::string>(kP2PDevicePassphrase)) {
LOG(ERROR) << std::string(kP2PDevicePassphrase) + " argument is mandatory";
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
std::string passphrase = args.Get<std::string>(kP2PDevicePassphrase);
std::optional<int32_t> freq;
if (args.Contains<int32_t>(kP2PDeviceFrequency)) {
freq = args.Get<int32_t>(kP2PDeviceFrequency);
}
if (!args.Contains<int32_t>(kP2PDevicePriority)) {
LOG(ERROR) << std::string(kP2PDevicePriority) + " argument is mandatory";
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
WiFiPhy::Priority priority =
WiFiPhy::Priority(args.Get<int32_t>(kP2PDevicePriority));
if (!priority.IsValid()) {
LOG(ERROR) << "invalid " << std::string(kP2PDevicePriority) + " argument "
<< priority;
PostResult(kConnectToP2PGroupResultInvalidArguments, std::nullopt,
std::move(result_callback_));
return;
}
if (!ConnectToSupplicantPrimaryP2PDeviceProxy()) {
LOG(ERROR) << "Failed to connect to P2P group, primary P2PDevice proxy "
"is not connected";
PostResult(kConnectToP2PGroupResultOperationFailed, std::nullopt,
std::move(callback));
return;
}
// Arm the start timer before sending the device creation request.
SetActionTimer(true, LocalDevice::IfaceType::kP2PClient);
bool request_accepted = manager_->wifi_provider()->RequestP2PDeviceCreation(
LocalDevice::IfaceType::kP2PClient,
base::BindRepeating(&P2PManager::OnP2PDeviceEvent,
base::Unretained(this)),
next_unique_id_, priority,
base::BindOnce(&P2PManager::OnDeviceCreated, base::Unretained(this),
LocalDevice::IfaceType::kP2PClient, ssid, passphrase,
freq),
base::BindOnce(&P2PManager::OnDeviceCreationFailed,
base::Unretained(this),
LocalDevice::IfaceType::kP2PClient));
next_unique_id_++;
if (!request_accepted) {
LOG(INFO)
<< "Failed to create a WiFi P2P interface due to concurrency conflict.";
CancelActionTimerAndPostResult(
kConnectToP2PGroupResultConcurrencyNotSupported, std::nullopt);
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
return;
}
}
void P2PManager::DestroyP2PGroup(P2PResultCallback callback, int32_t shill_id) {
LOG(INFO) << __func__;
CHECK(callback) << "Callback is empty";
if (result_callback_ || !action_timer_callback_.IsCancelled()) {
PostResult(kDestroyP2PGroupResultOperationInProgress, std::nullopt,
std::move(callback));
return;
}
result_callback_ = std::move(callback);
if (!base::Contains(p2p_group_owners_, shill_id)) {
LOG(ERROR) << "There is no P2P group at the requested shill_id: "
<< shill_id;
PostResult(kDestroyP2PGroupResultNoGroup, std::nullopt,
std::move(result_callback_));
return;
}
SetActionTimer(false, LocalDevice::IfaceType::kP2PClient);
p2p_group_owners_[shill_id]->RemoveGroup();
}
void P2PManager::DisconnectFromP2PGroup(P2PResultCallback callback,
int32_t shill_id) {
LOG(INFO) << __func__;
CHECK(callback) << "Callback is empty";
if (result_callback_ || !action_timer_callback_.IsCancelled()) {
PostResult(kDisconnectFromP2PGroupResultOperationInProgress, std::nullopt,
std::move(callback));
return;
}
result_callback_ = std::move(callback);
if (p2p_clients_.find(shill_id) == p2p_clients_.end()) {
LOG(ERROR) << "There is no P2P client at the requested shill_id: "
<< shill_id;
PostResult(kDisconnectFromP2PGroupResultNotConnected, std::nullopt,
std::move(result_callback_));
return;
}
SetActionTimer(false, LocalDevice::IfaceType::kP2PClient);
p2p_clients_[shill_id]->Disconnect();
}
void P2PManager::HelpRegisterDerivedBool(PropertyStore* store,
std::string_view name,
bool (P2PManager::*get)(Error* error),
bool (P2PManager::*set)(const bool&,
Error*)) {
store->RegisterDerivedBool(
name, BoolAccessor(new CustomAccessor<P2PManager, bool>(this, get, set)));
}
void P2PManager::HelpRegisterDerivedKeyValueStore(
PropertyStore* store,
std::string_view name,
KeyValueStore (P2PManager::*get)(Error* error),
bool (P2PManager::*set)(const KeyValueStore&, Error*)) {
store->RegisterDerivedKeyValueStore(
name, KeyValueStoreAccessor(
new CustomAccessor<P2PManager, KeyValueStore>(this, get, set)));
}
void P2PManager::HelpRegisterDerivedKeyValueStores(
PropertyStore* store,
std::string_view name,
KeyValueStores (P2PManager::*get)(Error* error),
bool (P2PManager::*set)(const KeyValueStores&, Error*)) {
store->RegisterDerivedKeyValueStores(
name,
KeyValueStoresAccessor(
new CustomAccessor<P2PManager, KeyValueStores>(this, get, set)));
}
bool P2PManager::SetAllowed(const bool& value, Error* error) {
if (allowed_ == value)
return false;
LOG(INFO) << __func__ << " Allowed set to " << std::boolalpha << value;
allowed_ = value;
Stop();
return true;
}
void P2PManager::PostResult(std::string result_code,
std::optional<int32_t> shill_id,
P2PResultCallback callback) {
if (!callback) {
LOG(ERROR) << "Callback is not set";
return;
}
KeyValueStore response_dict;
response_dict.Set<std::string>(kP2PResultCode, result_code);
if (shill_id) {
response_dict.Set<int32_t>(kP2PDeviceShillID, *shill_id);
}
manager_->dispatcher()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), response_dict));
}
void P2PManager::CancelActionTimerAndPostResult(
std::string result_code, std::optional<int32_t> shill_id) {
CancelActionTimer();
PostResult(result_code, shill_id, std::move(result_callback_));
}
void P2PManager::DeleteP2PDevice(P2PDeviceRefPtr p2p_dev) {
if (!p2p_dev)
return;
manager_->wifi_provider()->DeleteLocalDevice(p2p_dev);
if (p2p_dev->iface_type() == LocalDevice::IfaceType::kP2PGO) {
p2p_group_owners_.erase(p2p_dev->shill_id());
} else {
p2p_clients_.erase(p2p_dev->shill_id());
}
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
}
std::string P2PManager::PrimaryLinkName() const {
return manager_->wifi_provider()->GetPrimaryLinkName();
}
SupplicantProcessProxyInterface* P2PManager::SupplicantProcessProxy() const {
return manager_->supplicant_manager()->proxy();
}
ControlInterface* P2PManager::ControlInterface() const {
return manager_->control_interface();
}
bool P2PManager::ConnectToSupplicantPrimaryP2PDeviceProxy() {
if (supplicant_primary_p2pdevice_proxy_) {
LOG(INFO) << "Primary P2PDevice proxy is already connected";
return true;
}
std::string link_name = PrimaryLinkName();
if (link_name.empty()) {
LOG(ERROR) << "Failed to get the primary link name for WiFi technology";
return false;
}
// TODO(b/311161440) Centralize the primary interface proxy ownership
// in WiFiProvider so that all interfaces can access it without having to
// create their own connection.
RpcIdentifier interface_path;
if (!SupplicantProcessProxy()->GetInterface(link_name, &interface_path)) {
// Connect wpa_supplicant to the primary interface.
KeyValueStore create_interface_args;
create_interface_args.Set<std::string>(
WPASupplicant::kInterfacePropertyName, link_name);
create_interface_args.Set<std::string>(
WPASupplicant::kInterfacePropertyDriver, WPASupplicant::kDriverNL80211);
create_interface_args.Set<std::string>(
WPASupplicant::kInterfacePropertyConfigFile,
WPASupplicant::kSupplicantConfPath);
if (!SupplicantProcessProxy()->CreateInterface(create_interface_args,
&interface_path)) {
LOG(ERROR) << "Cannot connect to the primary interface " << link_name;
return false;
}
}
supplicant_primary_p2pdevice_proxy_ =
ControlInterface()->CreateSupplicantP2PDeviceProxy(this, interface_path);
if (!supplicant_primary_p2pdevice_proxy_) {
LOG(ERROR) << "Failed to connect to the primary P2PDevice proxy: "
<< interface_path.value();
return false;
}
LOG(INFO) << "Primary P2PDevice proxy connected: " << interface_path.value();
return true;
}
void P2PManager::DisconnectFromSupplicantPrimaryP2PDeviceProxy() {
if (supplicant_primary_p2pdevice_proxy_ && p2p_group_owners_.empty() &&
p2p_clients_.empty()) {
supplicant_primary_p2pdevice_proxy_.reset();
LOG(INFO) << "Primary P2PDevice proxy disconnected";
}
}
void P2PManager::GroupStarted(const KeyValueStore& properties) {
RpcIdentifier interface_path = RpcIdentifier("");
if (properties.Contains<RpcIdentifier>(
WPASupplicant::kGroupStartedPropertyInterfaceObject)) {
interface_path = properties.Get<RpcIdentifier>(
WPASupplicant::kGroupStartedPropertyInterfaceObject);
}
if (interface_path.value().empty()) {
LOG(WARNING) << "Ignored " << __func__ << " without interface";
return;
}
if (base::Contains(supplicant_primary_p2pdevice_event_delegates_,
interface_path)) {
LOG(WARNING) << "Ignored " << __func__
<< " with assigned interface: " << interface_path.value();
return;
}
auto delegate = supplicant_primary_p2pdevice_pending_event_delegate_;
if (!delegate) {
LOG(WARNING) << "Ignored " << __func__ << " while not expected, interface: "
<< interface_path.value();
return;
}
supplicant_primary_p2pdevice_pending_event_delegate_ = nullptr;
supplicant_primary_p2pdevice_event_delegates_[interface_path] = delegate;
LOG(INFO) << "Got " << __func__ << ", interface: " << interface_path.value();
delegate->GroupStarted(properties);
}
void P2PManager::GroupFinished(const KeyValueStore& properties) {
RpcIdentifier interface_path = RpcIdentifier("");
if (properties.Contains<RpcIdentifier>(
WPASupplicant::kGroupFinishedPropertyInterfaceObject)) {
interface_path = properties.Get<RpcIdentifier>(
WPASupplicant::kGroupFinishedPropertyInterfaceObject);
}
if (interface_path.value().empty()) {
LOG(WARNING) << "Ignored " << __func__ << " without interface";
return;
}
auto delegate =
base::Contains(supplicant_primary_p2pdevice_event_delegates_,
interface_path)
? supplicant_primary_p2pdevice_event_delegates_[interface_path]
: nullptr;
if (!delegate) {
LOG(ERROR) << "Ignored " << __func__
<< " while not expected, interface: " << interface_path.value();
return;
} else {
supplicant_primary_p2pdevice_event_delegates_.erase(interface_path);
}
LOG(INFO) << "Got " << __func__ << ", interface: " << interface_path.value();
delegate->GroupFinished(properties);
}
void P2PManager::GroupFormationFailure(const std::string& reason) {
auto delegate = supplicant_primary_p2pdevice_pending_event_delegate_;
if (!delegate) {
LOG(WARNING) << "Ignored " << __func__
<< " while not expected, reason: " << reason;
return;
}
supplicant_primary_p2pdevice_pending_event_delegate_ = nullptr;
LOG(INFO) << "Got " << __func__ << ", reason: " << reason;
delegate->GroupFormationFailure(reason);
}
void P2PManager::OnP2PDeviceEvent(LocalDevice::DeviceEvent event,
const LocalDevice* device) {
if (device->iface_type() != LocalDevice::IfaceType::kP2PGO &&
device->iface_type() != LocalDevice::IfaceType::kP2PClient) {
LOG(ERROR) << "Received P2P event from device "
<< device->link_name().value_or("(no link name)")
<< " with invalid type " << device->iface_type();
return;
}
bool is_go = device->iface_type() == LocalDevice::IfaceType::kP2PGO;
// Get the P2PDevice typed reference for the LocalDevice object.
P2PDeviceRefPtr p2p_dev;
auto devs = is_go ? p2p_group_owners_ : p2p_clients_;
for (auto& it : devs) {
if (it.second == device) {
p2p_dev = it.second;
}
}
if (!p2p_dev) {
LOG(ERROR) << "Received event from unmatched P2P device: "
<< device->link_name().value_or("(no link name)");
return;
}
LOG(INFO) << "P2PManager received P2P device "
<< p2p_dev->link_name().value_or("(no link name)")
<< " event: " << event;
switch (event) {
case LocalDevice::DeviceEvent::kLinkDown: {
DeleteP2PDevice(p2p_dev);
if (!result_callback_ || action_timer_callback_.IsCancelled()) {
// kLinkDown should only occur in response to an explicit stop request,
// so we should always have an active callback and timer
LOG(ERROR) << "No available callback or action timer for event: "
<< event;
return;
}
CancelActionTimerAndPostResult(is_go
? kDestroyP2PGroupResultSuccess
: kDisconnectFromP2PGroupResultSuccess,
std::nullopt);
return;
}
case LocalDevice::DeviceEvent::kLinkFailure:
DeleteP2PDevice(p2p_dev);
supplicant_primary_p2pdevice_pending_event_delegate_ = nullptr;
if (!result_callback_) {
return;
}
CancelActionTimerAndPostResult(
is_go ? kCreateP2PGroupResultOperationFailed
: kConnectToP2PGroupResultOperationFailed,
std::nullopt);
return;
case LocalDevice::DeviceEvent::kInterfaceEnabled:
OnP2PDeviceEnabled(p2p_dev);
break;
case LocalDevice::DeviceEvent::kLinkUp:
// P2PDevice handles network creation so no action is needed here.
break;
case LocalDevice::DeviceEvent::kPeerConnected:
if (!is_go) {
LOG(ERROR) << "Received " << event << " event for a P2P Client device.";
return;
}
OnPeerAssoc(p2p_dev);
break;
case LocalDevice::DeviceEvent::kPeerDisconnected:
if (!is_go) {
LOG(ERROR) << "Received " << event << " event for a P2P Client device.";
return;
}
OnPeerDisassoc(p2p_dev);
break;
case LocalDevice::DeviceEvent::kNetworkUp:
P2PNetworkStarted(p2p_dev);
break;
case LocalDevice::DeviceEvent::kInterfaceDisabled:
case LocalDevice::DeviceEvent::kNetworkDown:
case LocalDevice::DeviceEvent::kNetworkFailure:
// TODO(b/295056306): Implement kNetworkDown and kNetworkFailure handling.
LOG(ERROR) << "Recieved unexpected " << event
<< " event which has not been implemented.";
break;
}
}
void P2PManager::OnDeviceCreated(LocalDevice::IfaceType iface_type,
std::optional<std::string> ssid,
std::optional<std::string> passphrase,
std::optional<int32_t> freq,
P2PDeviceRefPtr device) {
if (!result_callback_) {
LOG(ERROR) << "P2PDevice was created with no pending callback.";
return;
}
if (iface_type != device->iface_type()) {
LOG(ERROR) << "P2PDevice created with type " << device->iface_type()
<< " which does not match requested type " << iface_type;
return;
}
if (device->iface_type() != LocalDevice::IfaceType::kP2PGO &&
device->iface_type() != LocalDevice::IfaceType::kP2PClient) {
LOG(ERROR) << "P2PDevice created "
<< device->link_name().value_or("(no link name)")
<< " with invalid type " << device->iface_type();
return;
}
bool is_go = device->iface_type() == LocalDevice::IfaceType::kP2PGO;
if (!device) {
LOG(ERROR) << "Failed to create a WiFi P2P interface.";
CancelActionTimerAndPostResult(
is_go ? kCreateP2PGroupResultOperationFailed
: kConnectToP2PGroupResultOperationFailed,
std::nullopt);
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
return;
}
if (!device->SetEnabled(true)) {
LOG(ERROR) << "Failed to enable a WiFi P2P interface.";
CancelActionTimerAndPostResult(
is_go ? kCreateP2PGroupResultOperationFailed
: kConnectToP2PGroupResultOperationFailed,
std::nullopt);
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
return;
}
std::unique_ptr<P2PService> service =
std::make_unique<P2PService>(device, ssid, passphrase, freq);
if (is_go) {
p2p_group_owners_[device->shill_id()] = device;
if (!device->CreateGroup(std::move(service))) {
LOG(ERROR) << "Failed to initiate group creation";
CancelActionTimerAndPostResult(kCreateP2PGroupResultOperationFailed,
std::nullopt);
DeleteP2PDevice(device);
return;
}
} else {
p2p_clients_[device->shill_id()] = device;
if (!device->Connect(std::move(service))) {
LOG(ERROR) << "Failed to initiate connection";
CancelActionTimerAndPostResult(kConnectToP2PGroupResultOperationFailed,
std::nullopt);
DeleteP2PDevice(device);
return;
}
}
supplicant_primary_p2pdevice_pending_event_delegate_ = device.get();
}
void P2PManager::OnDeviceCreationFailed(LocalDevice::IfaceType iface_type) {
if (!result_callback_) {
LOG(ERROR) << "P2PDevice was created with no pending callback.";
return;
}
if (iface_type != LocalDevice::IfaceType::kP2PGO &&
iface_type != LocalDevice::IfaceType::kP2PClient) {
LOG(ERROR) << "Received DeviceCreationFailed event for invalid type "
<< iface_type;
}
bool is_go = iface_type == LocalDevice::IfaceType::kP2PGO;
LOG(ERROR) << "Failed create P2PDevice.";
CancelActionTimerAndPostResult(is_go
? kCreateP2PGroupResultOperationFailed
: kConnectToP2PGroupResultOperationFailed,
std::nullopt);
DisconnectFromSupplicantPrimaryP2PDeviceProxy();
}
void P2PManager::P2PNetworkStarted(P2PDeviceRefPtr device) {
if (device->iface_type() != LocalDevice::IfaceType::kP2PGO &&
device->iface_type() != LocalDevice::IfaceType::kP2PClient) {
LOG(ERROR) << "Received network started on device "
<< device->link_name().value_or("(no link name)")
<< " with invalid type " << device->iface_type();
}
manager_->wifi_provider()->RegisterLocalDevice(device);
std::string result_code =
device->iface_type() == LocalDevice::IfaceType::kP2PGO
? kCreateP2PGroupResultSuccess
: kConnectToP2PGroupResultSuccess;
CancelActionTimerAndPostResult(result_code, device->shill_id());
return;
}
} // namespace shill