Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement WifiAccessPointSetPhyType #139

Merged
merged 18 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions protocol/protos/NetRemoteService.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ service NetRemote
rpc WifiEnumerateAccessPoints (Microsoft.Net.Remote.Wifi.WifiEnumerateAccessPointsRequest) returns (Microsoft.Net.Remote.Wifi.WifiEnumerateAccessPointsResult);
rpc WifiAccessPointEnable (Microsoft.Net.Remote.Wifi.WifiAccessPointEnableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointEnableResult);
rpc WifiAccessPointDisable (Microsoft.Net.Remote.Wifi.WifiAccessPointDisableRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointDisableResult);
rpc WifiAccessPointSetPhyType (Microsoft.Net.Remote.Wifi.WifiAccessPointSetPhyTypeRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetPhyTypeResult);
}
12 changes: 12 additions & 0 deletions protocol/protos/NetRemoteWifi.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,15 @@ message WifiAccessPointDisableResult
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}

message WifiAccessPointSetPhyTypeRequest
{
string AccessPointId = 1;
Microsoft.Net.Wifi.Dot11PhyType PhyType = 2;
}

message WifiAccessPointSetPhyTypeResult
{
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}
107 changes: 106 additions & 1 deletion src/common/service/NetRemoteService.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,33 @@ IeeeProtocolToNetRemotePhyType(Ieee80211Protocol ieeeProtocol)
return Dot11PhyType::Dot11PhyTypeUnknown;
}

using Microsoft::Net::Wifi::Ieee80211FrequencyBand;
Ieee80211Protocol
NetRemotePhyTypeToIeeeProtocol(Dot11PhyType phyType)
{
switch (phyType) {
case Dot11PhyType::Dot11PhyTypeB:
return Ieee80211Protocol::B;
case Dot11PhyType::Dot11PhyTypeG:
return Ieee80211Protocol::G;
case Dot11PhyType::Dot11PhyTypeN:
return Ieee80211Protocol::N;
case Dot11PhyType::Dot11PhyTypeA:
return Ieee80211Protocol::A;
case Dot11PhyType::Dot11PhyTypeAC:
return Ieee80211Protocol::AC;
case Dot11PhyType::Dot11PhyTypeAD:
return Ieee80211Protocol::AD;
case Dot11PhyType::Dot11PhyTypeAX:
return Ieee80211Protocol::AX;
case Dot11PhyType::Dot11PhyTypeBE:
return Ieee80211Protocol::BE;
default:
return Ieee80211Protocol::Unknown;
}
}

using Microsoft::Net::Wifi::Dot11FrequencyBand;
using Microsoft::Net::Wifi::Ieee80211FrequencyBand;

Dot11FrequencyBand
IeeeDot11FrequencyBandToNetRemoteDot11FrequencyBand(Ieee80211FrequencyBand ieeeDot11FrequencyBand)
Expand Down Expand Up @@ -316,6 +341,19 @@ IAccessPointWeakToNetRemoteAccessPointResultItem(std::weak_ptr<Microsoft::Net::W
return item;
}

std::unique_ptr<Microsoft::Net::Wifi::IAccessPointController>
IAccessPointWeakToAccessPointController(std::weak_ptr<Microsoft::Net::Wifi::IAccessPoint>& accessPointWeak)
{
auto accessPoint = accessPointWeak.lock();
if (accessPoint != nullptr) {
return accessPoint->CreateController();
} else {
LOGE << "Failed to retrieve access point as it is no longer valid";
}

return nullptr;
}

bool
NetRemoteAccessPointResultItemIsInvalid(const Microsoft::Net::Remote::Wifi::WifiEnumerateAccessPointsResultItem& item)
{
Expand Down Expand Up @@ -389,6 +427,73 @@ NetRemoteService::WifiAccessPointDisable([[maybe_unused]] ::grpc::ServerContext*
return grpc::Status::OK;
}

using Microsoft::Net::Wifi::Dot11PhyType;

::grpc::Status
NetRemoteService::WifiAccessPointSetPhyType([[maybe_unused]] ::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeResult* response)
{
using Microsoft::Net::Wifi::Ieee80211AccessPointCapabilities;

LOGD << std::format("Received WifiAccessPointSetPhyType request for access point id {}", request->accesspointid());

WifiAccessPointOperationStatus status{};

auto handleFailure = [&](WifiAccessPointOperationStatusCode statusCode, std::string statusMessage) {
LOGE << statusMessage;

status.set_code(statusCode);
status.set_message(statusMessage);

response->set_accesspointid(request->accesspointid());
*response->mutable_status() = std::move(status);

return grpc::Status::OK;
};

// Check if PHY type is provided.
if (request->phytype() == Dot11PhyType::Dot11PhyTypeUnknown) {
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter, "No PHY type provided");
}

// Create an AP controller for the requested AP.
auto accessPointWeak = m_accessPointManager->GetAccessPoint(request->accesspointid());
auto accessPointController = detail::IAccessPointWeakToAccessPointController(accessPointWeak);
if (!accessPointController) {
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeAccessPointInvalid, std::format("Failed to create controller for access point {}", request->accesspointid()));
}

// Convert PHY type to Ieee80211 protocol.
auto ieeeProtocol = detail::NetRemotePhyTypeToIeeeProtocol(request->phytype());

// Check if Ieee80211 protocol is supported by AP.
try {
auto accessPointCapabilities = accessPointController->GetCapabilities();
const auto& supportedIeeeProtocols = accessPointCapabilities.Protocols;
if (std::ranges::find(supportedIeeeProtocols, ieeeProtocol) == std::cend(supportedIeeeProtocols)) {
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported, std::format("PHY type not supported by access point {}", request->accesspointid()));
}
} catch (const AccessPointControllerException& apce) {
LOGE << std::format("Failed to get capabilities for access point {} ({})", request->accesspointid(), apce.what());
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported, std::format("Failed to get capabilities for access point {}", request->accesspointid()));
}

// Set the Ieee80211 protocol.
try {
if (!accessPointController->SetProtocol(ieeeProtocol)) {
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported, std::format("Failed to set PHY type for access point {}", request->accesspointid()));
}
} catch (const AccessPointControllerException& apce) {
LOGE << std::format("Failed to set Ieee80211 protocol for access point {} ({})", request->accesspointid(), apce.what());
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported, std::format("Failed to set PHY type for access point {}", request->accesspointid()));
}

status.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);
response->set_accesspointid(request->accesspointid());
*response->mutable_status() = std::move(status);

return grpc::Status::OK;
}

bool
NetRemoteService::ValidateWifiAccessPointEnableRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointEnableRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus& status)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ private:
virtual ::grpc::Status
WifiAccessPointDisable(::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointDisableRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointDisableResult* response) override;

virtual ::grpc::Status
WifiAccessPointSetPhyType(::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeResult* response) override;

protected:
bool
ValidateWifiAccessPointEnableRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointEnableRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus& status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include <exception>
#include <memory>
#include <string_view>
#include <string>
#include <string_view>

#include <microsoft/net/wifi/Ieee80211.hxx>
#include <microsoft/net/wifi/Ieee80211AccessPointCapabilities.hxx>

namespace Microsoft::Net::Wifi
Expand Down Expand Up @@ -46,9 +47,9 @@ struct IAccessPointController

/**
* @brief Get whether the access point is enabled.
*
* @return true
* @return false
*
* @return true
* @return false
*/
virtual bool
GetIsEnabled() = 0;
Expand All @@ -60,6 +61,17 @@ struct IAccessPointController
*/
virtual Ieee80211AccessPointCapabilities
GetCapabilities() = 0;

/**
* @brief Set the Ieee80211 protocol of the access point.
*
* @param ieeeProtocol The Ieee80211 protocol to be set.
* @return true
* @return false
*
*/
virtual bool
SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol ieeeProtocol) = 0;
};

/**
Expand Down
77 changes: 77 additions & 0 deletions src/linux/wifi/core/AccessPointControllerLinux.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <Wpa/ProtocolHostapd.hxx>
#include <Wpa/WpaCommandStatus.hxx>
#include <Wpa/WpaResponseStatus.hxx>
#include <magic_enum.hpp>
#include <microsoft/net/netlink/nl80211/Netlink80211Wiphy.hxx>
#include <microsoft/net/wifi/AccessPointControllerLinux.hxx>

Expand Down Expand Up @@ -74,6 +75,50 @@ Nl80211WiphyToIeee80211Protocols(const Nl80211Wiphy& nl80211Wiphy)

return protocols;
}

Wpa::HostapdHwMode
IeeeProtocolToHostapdHwMode(Ieee80211Protocol ieeeProtocol)
{
switch (ieeeProtocol) {
case Ieee80211Protocol::B:
return Wpa::HostapdHwMode::Ieee80211b;
case Ieee80211Protocol::G:
return Wpa::HostapdHwMode::Ieee80211g;
case Ieee80211Protocol::N:
return Wpa::HostapdHwMode::Ieee80211a; // TODO: Could be a or g depending on band
case Ieee80211Protocol::A:
return Wpa::HostapdHwMode::Ieee80211a;
case Ieee80211Protocol::AC:
return Wpa::HostapdHwMode::Ieee80211a;
case Ieee80211Protocol::AD:
return Wpa::HostapdHwMode::Ieee80211ad;
case Ieee80211Protocol::AX:
return Wpa::HostapdHwMode::Ieee80211a;
case Ieee80211Protocol::BE:
return Wpa::HostapdHwMode::Ieee80211a; // TODO: Assuming a, although hostapd docs don't mention it
default:
return Wpa::HostapdHwMode::Unknown;
}
}

std::string
HostapdHwModeToPropertyValue(Wpa::HostapdHwMode hwMode)
{
switch (hwMode) {
case Wpa::HostapdHwMode::Ieee80211b:
return Wpa::ProtocolHostapd::PropertyHwModeValueB;
case Wpa::HostapdHwMode::Ieee80211g:
return Wpa::ProtocolHostapd::PropertyHwModeValueG;
case Wpa::HostapdHwMode::Ieee80211a:
return Wpa::ProtocolHostapd::PropertyHwModeValueA;
case Wpa::HostapdHwMode::Ieee80211ad:
return Wpa::ProtocolHostapd::PropertyHwModeValueAD;
case Wpa::HostapdHwMode::Ieee80211any:
return Wpa::ProtocolHostapd::PropertyHwModeValueAny;
default: // case Wpa::HostapdHwMode::Unknown
throw AccessPointControllerException(std::format("Invalid hostapd hw_mode value {}", magic_enum::enum_name(hwMode)));
}
}
} // namespace detail

Ieee80211AccessPointCapabilities
Expand Down Expand Up @@ -119,6 +164,38 @@ AccessPointControllerLinux::GetIsEnabled()
return isEnabled;
}

bool
AccessPointControllerLinux::SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol ieeeProtocol)
{
bool isOk = false;
Wpa::HostapdHwMode hwMode = detail::IeeeProtocolToHostapdHwMode(ieeeProtocol);

try {
// Set the hostapd hw_mode property.
isOk = m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameHwMode, detail::HostapdHwModeToPropertyValue(hwMode));
corbin-phipps marked this conversation as resolved.
Show resolved Hide resolved

// Additively set other hostapd properties based on the protocol.
if (ieeeProtocol == Ieee80211Protocol::N || ieeeProtocol == Ieee80211Protocol::AC || ieeeProtocol == Ieee80211Protocol::AX) {
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameWmmEnabled, Wpa::ProtocolHostapd::PropertyEnabled);
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameIeee80211N, Wpa::ProtocolHostapd::PropertyEnabled);
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameDisable11N, Wpa::ProtocolHostapd::PropertyDisabled);
}
if (ieeeProtocol == Ieee80211Protocol::AC || ieeeProtocol == Ieee80211Protocol::AX) {
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameIeee80211AC, Wpa::ProtocolHostapd::PropertyEnabled);
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameDisable11AC, Wpa::ProtocolHostapd::PropertyDisabled);
}
if (ieeeProtocol == Ieee80211Protocol::AX) {
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameIeee80211AX, Wpa::ProtocolHostapd::PropertyEnabled);
isOk = isOk && m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameDisable11AX, Wpa::ProtocolHostapd::PropertyDisabled);
}
corbin-phipps marked this conversation as resolved.
Show resolved Hide resolved

corbin-phipps marked this conversation as resolved.
Show resolved Hide resolved
} catch (const Wpa::HostapdException& ex) {
throw AccessPointControllerException(std::format("Failed to set Ieee80211 protocol for interface {} ({})", GetInterfaceName(), ex.what()));
}

return isOk;
}

std::unique_ptr<IAccessPointController>
AccessPointControllerLinuxFactory::Create(std::string_view interfaceName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string_view>

#include <Wpa/Hostapd.hxx>
#include <microsoft/net/wifi/Ieee80211.hxx>
#include <microsoft/net/wifi/AccessPointController.hxx>

namespace Microsoft::Net::Wifi
Expand All @@ -28,9 +29,9 @@ struct AccessPointControllerLinux :

/**
* @brief Get whether the access point is enabled.
*
* @return true
* @return false
*
* @return true
* @return false
*/
virtual bool
GetIsEnabled() override;
Expand All @@ -43,6 +44,16 @@ struct AccessPointControllerLinux :
virtual Ieee80211AccessPointCapabilities
GetCapabilities() override;

/**
* @brief Set the Ieee80211 protocol.
*
* @param ieeeProtocol The Ieee80211 protocol to be set.
* @return true
* @return false
*/
virtual bool
SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol ieeeProtocol) override;

private:
Wpa::Hostapd m_hostapd;
};
Expand Down
18 changes: 18 additions & 0 deletions src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,30 @@ struct ProtocolHostapd :
static constexpr auto PropertyVersionValue = "2.10-hostap_2_10";

// Property names for "SET" commands.
static constexpr auto PropertyEnabled = "1";
static constexpr auto PropertyDisabled = "0";

static constexpr auto PropertyNameSetBand = "setband";
static constexpr auto PropertySetBandValueAuto = "AUTO";
static constexpr auto PropertySetBandValue2G = "2G";
static constexpr auto PropertySetBandValue5G = "5G";
static constexpr auto PropertySetBandValue6G = "6G";

static constexpr auto PropertyNameHwMode = "hw_mode";
static constexpr auto PropertyHwModeValueB = "b";
static constexpr auto PropertyHwModeValueG = "g";
static constexpr auto PropertyHwModeValueA = "a";
static constexpr auto PropertyHwModeValueAD = "ad";
static constexpr auto PropertyHwModeValueAny = "any";

static constexpr auto PropertyNameIeee80211N = "ieee80211n";
static constexpr auto PropertyNameDisable11N = "disable_11n";
static constexpr auto PropertyNameIeee80211AC = "ieee80211ac";
static constexpr auto PropertyNameDisable11AC = "disable_11ac";
static constexpr auto PropertyNameIeee80211AX = "ieee80211ax";
static constexpr auto PropertyNameDisable11AX = "disable_11ax";
static constexpr auto PropertyNameWmmEnabled = "wmm_enabled";
corbin-phipps marked this conversation as resolved.
Show resolved Hide resolved

// Response properties for the "STATUS" command.
// Note: all properties must be terminated with the key-value delimeter (=).
static constexpr auto ResponseStatusPropertyKeyState = "state=";
Expand Down
Loading