Skip to content

Commit

Permalink
Merge pull request #163 from microsoft/apdisable
Browse files Browse the repository at this point in the history
Implement WifiAccessPointDisable API
  • Loading branch information
abeltrano authored Feb 23, 2024
2 parents c397daa + e6a5b24 commit 65b8b0f
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 47 deletions.
67 changes: 56 additions & 11 deletions src/common/service/NetRemoteService.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <microsoft/net/remote/protocol/NetRemoteWifi.pb.h>
#include <microsoft/net/remote/protocol/WifiCore.pb.h>
#include <microsoft/net/wifi/AccessPointManager.hxx>
#include <microsoft/net/wifi/AccessPointOperationStatus.hxx>
#include <microsoft/net/wifi/IAccessPoint.hxx>
#include <microsoft/net/wifi/IAccessPointController.hxx>
#include <microsoft/net/wifi/Ieee80211AccessPointCapabilities.hxx>
Expand Down Expand Up @@ -63,6 +64,28 @@ HandleFailure(RequestT& request, ResultT& result, WifiAccessPointOperationStatus
return returnValue;
}

/**
* @brief Wrapper for HandleFailure that converts a AccessPointOperationStatusCode to a WifiAccessPointOperationStatusCode.
*
* @tparam RequestT The request type. This must contain an access point id (trait).
* @tparam ResultT The result type. This must contain an access point id and a status (traits).
* @return ReturnT The type of the return value. Defaults to grpc::Status with a value of grpc::OK.
* @param request A reference to the request.
* @param result A reference to the result.
* @param code The error code to set in the result message.
* @param message The error message to set in the result message.
* @param returnValue The value to return from the function.
*/
template <
typename RequestT,
typename ResultT,
typename ReturnT = grpc::Status>
ReturnT
HandleFailure(RequestT& request, ResultT& result, AccessPointOperationStatusCode code, std::string_view message, ReturnT returnValue = {})
{
return HandleFailure(request, result, ToDot11AccessPointOperationStatusCode(code), message, returnValue);
}

/**
* @brief Attempt to obtain an IAccessPoint instance for the access point in the specified request message.
*
Expand Down Expand Up @@ -148,12 +171,7 @@ MakeInvalidAccessPointResultItem()
WifiEnumerateAccessPointsResultItem
IAccessPointToNetRemoteAccessPointResultItem(IAccessPoint& accessPoint)
{
WifiEnumerateAccessPointsResultItem item{};

bool isEnabled{ false };
std::string id{};
Dot11AccessPointCapabilities dot11AccessPointCapabilities{};

auto interfaceName = accessPoint.GetInterfaceName();
id.assign(std::cbegin(interfaceName), std::cend(interfaceName));

Expand All @@ -163,13 +181,14 @@ IAccessPointToNetRemoteAccessPointResultItem(IAccessPoint& accessPoint)
return MakeInvalidAccessPointResultItem();
}

try {
isEnabled = accessPointController->GetIsEnabled();
} catch (const AccessPointControllerException& apce) {
LOGE << std::format("Failed to get enabled state for access point {} ({})", interfaceName, apce.what());
AccessPointOperationalState operationalState{};
auto operationStatus = accessPointController->GetOperationalState(operationalState);
if (!operationStatus) {
LOGE << std::format("Failed to get operational state for access point {} ({})", interfaceName, magic_enum::enum_name(operationStatus.Code));
return MakeInvalidAccessPointResultItem();
}

Dot11AccessPointCapabilities dot11AccessPointCapabilities{};
try {
auto ieee80211AccessPointCapabilities = accessPointController->GetCapabilities();
dot11AccessPointCapabilities = ToDot11AccessPointCapabilities(ieee80211AccessPointCapabilities);
Expand All @@ -178,7 +197,10 @@ IAccessPointToNetRemoteAccessPointResultItem(IAccessPoint& accessPoint)
return MakeInvalidAccessPointResultItem();
}

const bool isEnabled{ operationalState == AccessPointOperationalState::Enabled };

// Populate the result item.
WifiEnumerateAccessPointsResultItem item{};
item.set_accesspointid(std::move(id));
item.set_isenabled(isEnabled);
*item.mutable_capabilities() = std::move(dot11AccessPointCapabilities);
Expand All @@ -193,7 +215,7 @@ IAccessPointWeakToNetRemoteAccessPointResultItem(std::weak_ptr<IAccessPoint>& ac

auto accessPoint = accessPointWeak.lock();
if (accessPoint != nullptr) {
item = IAccessPointToNetRemoteAccessPointResultItem(*accessPoint.get());
item = IAccessPointToNetRemoteAccessPointResultItem(*accessPoint);
} else {
item = detail::MakeInvalidAccessPointResultItem();
}
Expand Down Expand Up @@ -269,8 +291,31 @@ NetRemoteService::WifiAccessPointDisable([[maybe_unused]] grpc::ServerContext* c
{
const NetRemoteWifiApiTrace traceMe{ request->accesspointid(), result->mutable_status() };

// Create an AP controller for the requested AP.
auto accessPointController = detail::TryGetAccessPointController(request, result, m_accessPointManager);
if (accessPointController == nullptr) {
return grpc::Status::OK;
}

// Obtain current operational state.
AccessPointOperationalState operationalState{};
auto operationStatus = accessPointController->GetOperationalState(operationalState);
if (!operationStatus) {
return HandleFailure(request, result, operationStatus.Code, std::format("Failed to get operational state for access point {}", request->accesspointid()));
}

// Disable the access point if it's not already disabled.
if (operationalState != AccessPointOperationalState::Disabled) {
// Disable the access point.
operationStatus = accessPointController->SetOperationalState(AccessPointOperationalState::Disabled);
if (!operationStatus) {
return HandleFailure(request, result, operationStatus.Code, std::format("Failed to set operational state to 'disabled' for access point {}", request->accesspointid()));
}
} else {
LOGI << std::format("Access point {} is in 'disabled' operational state", request->accesspointid());
}

WifiAccessPointOperationStatus status{};
// TODO: Disable the access point.
status.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);

result->set_accesspointid(request->accesspointid());
Expand Down
13 changes: 13 additions & 0 deletions src/common/wifi/core/AccessPointOperationStatus.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,20 @@ AccessPointOperationStatus::MakeSucceeded() noexcept
return AccessPointOperationStatus{ AccessPointOperationStatusCode::Succeeded };
}

bool
AccessPointOperationStatus::Succeeded() const noexcept
{
return (Code == AccessPointOperationStatusCode::Succeeded);
}

bool
AccessPointOperationStatus::Failed() const noexcept
{
return !Succeeded();
}

AccessPointOperationStatus::operator bool() const noexcept
{
return Succeeded();
return (Code == AccessPointOperationStatusCode::Succeeded);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

namespace Microsoft::Net::Wifi
{
/**
* @brief Operational state of an access point.
*/
enum class AccessPointOperationalState : bool {
Disabled = false,
Enabled = true,
};

/**
* @brief High-level status reported by various access point operations.
*/
Expand Down Expand Up @@ -52,6 +60,24 @@ struct AccessPointOperationStatus
static AccessPointOperationStatus
MakeSucceeded() noexcept;

/**
* @brief Determine whether the operation succeeded.
*
* @return true
* @return false
*/
bool
Succeeded() const noexcept;

/**
* @brief Determine whether the operation failed.
*
* @return true
* @return false
*/
bool
Failed() const noexcept;

/**
* @brief Implicit bool operator allowing AccessPointOperationStatus to be used directly in condition statements
* (eg. if (status) // ...).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ struct IAccessPointController
GetInterfaceName() const = 0;

/**
* @brief Get whether the access point is enabled.
* @brief Get the access point operational state.
*
* @return true
* @return false
* @param operationalState The value to store the operational state.
* @return AccessPointOperationStatus
*/
virtual bool
GetIsEnabled() = 0;
virtual AccessPointOperationStatus
GetOperationalState(AccessPointOperationalState& operationalState) = 0;

/**
* @brief Get the capabilities of the access point.
Expand All @@ -76,6 +76,15 @@ struct IAccessPointController
virtual Ieee80211AccessPointCapabilities
GetCapabilities() = 0;

/**
* @brief Set the operational state of the access point.
*
* @param operationalState The desired operational state.
* @return AccessPointOperationStatus
*/
virtual AccessPointOperationStatus
SetOperationalState(AccessPointOperationalState operationalState) = 0;

/**
* @brief Set the Ieee80211 protocol of the access point.
*
Expand Down
50 changes: 44 additions & 6 deletions src/linux/wifi/core/AccessPointControllerLinux.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,57 @@ AccessPointControllerLinux::GetCapabilities()
return capabilities;
}

bool
AccessPointControllerLinux::GetIsEnabled()
AccessPointOperationStatus
AccessPointControllerLinux::GetOperationalState(AccessPointOperationalState& operationalState)
{
bool isEnabled{ false };
AccessPointOperationStatus status{};

try {
auto hostapdStatus = m_hostapd.GetStatus();
isEnabled = (hostapdStatus.State == Wpa::HostapdInterfaceState::Enabled);
operationalState = (hostapdStatus.State == Wpa::HostapdInterfaceState::Enabled)
? AccessPointOperationalState::Enabled
: AccessPointOperationalState::Disabled;
status = AccessPointOperationStatus::MakeSucceeded();
} catch (const Wpa::HostapdException& ex) {
throw AccessPointControllerException(std::format("Failed to get status for interface {} ({})", GetInterfaceName(), ex.what()));
status.Code = AccessPointOperationStatusCode::InternalError;
status.Message = std::format("Failed to get operational state for interface {} ({})", GetInterfaceName(), ex.what());
}

return status;
}

AccessPointOperationStatus
AccessPointControllerLinux::SetOperationalState(AccessPointOperationalState operationalState)
{
AccessPointOperationStatus status{};

switch (operationalState) {
case AccessPointOperationalState::Enabled: {
try {
m_hostapd.Enable();
} catch (const Wpa::HostapdException& ex) {
status.Code = AccessPointOperationStatusCode::InternalError;
status.Message = std::format("Failed to set operational state to 'enabled' for {} (unknown error)", GetInterfaceName());
}
break;
}
case AccessPointOperationalState::Disabled: {
try {
m_hostapd.Disable();
} catch (const Wpa::HostapdException& ex) {
status.Code = AccessPointOperationStatusCode::InternalError;
status.Message = std::format("Failed to set operational state to 'disabled' for {} (unknown error)", GetInterfaceName());
}
break;
}
default: {
status.Code = AccessPointOperationStatusCode::InvalidParameter;
status.Message = std::format("Invalid operational state value '{}' for {}", magic_enum::enum_name(operationalState), GetInterfaceName());
break;
}
}

return isEnabled;
return status;
}

bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ struct AccessPointControllerLinux :
operator=(AccessPointControllerLinux&&) = delete;

/**
* @brief Get whether the access point is enabled.
* @brief Get the access point operational state.
*
* @return true
* @return false
* @param operationalState The value to store the operational state.
* @return AccessPointOperationStatus
*/
bool
GetIsEnabled() override;
AccessPointOperationStatus
GetOperationalState(AccessPointOperationalState& operationalState) override;

/**
* @brief Get the Capabilities object
Expand All @@ -59,6 +59,15 @@ struct AccessPointControllerLinux :
Ieee80211AccessPointCapabilities
GetCapabilities() override;

/**
* @brief Set the operational state of the access point.
*
* @param operationalState The desired operational state.
* @return AccessPointOperationStatus
*/
AccessPointOperationStatus
SetOperationalState(AccessPointOperationalState operationalState) override;

/**
* @brief Set the Ieee80211 protocol.
*
Expand Down
Loading

0 comments on commit 65b8b0f

Please sign in to comment.