Skip to content

Commit

Permalink
Merge pull request #149 from microsoft/freqbandapi
Browse files Browse the repository at this point in the history
Add API to set Wi-Fi frequency bands
  • Loading branch information
abeltrano authored Feb 7, 2024
2 parents 571ab5e + 11ce824 commit f58704c
Show file tree
Hide file tree
Showing 12 changed files with 414 additions and 40 deletions.
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"ms-vscode-remote.vscode-remote-extensionpack",
"coolbear.systemd-unit-file",
"redhat.vscode-yaml",
"vadimcn.vscode-lldb"
"vadimcn.vscode-lldb",
"zxh404.vscode-proto3"
]
}
1 change: 1 addition & 0 deletions protocol/protos/NetRemoteService.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ service NetRemote
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);
rpc WifiAccessPointSetFrequencyBands (Microsoft.Net.Remote.Wifi.WifiAccessPointSetFrequencyBandsRequest) returns (Microsoft.Net.Remote.Wifi.WifiAccessPointSetFrequencyBandsResult);
}
12 changes: 12 additions & 0 deletions protocol/protos/NetRemoteWifi.proto
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,15 @@ message WifiAccessPointSetPhyTypeResult
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}

message WifiAccessPointSetFrequencyBandsRequest
{
string AccessPointId = 1;
repeated Microsoft.Net.Wifi.Dot11FrequencyBand FrequencyBands = 2;
}

message WifiAccessPointSetFrequencyBandsResult
{
string AccessPointId = 1;
WifiAccessPointOperationStatus Status = 2;
}
126 changes: 119 additions & 7 deletions src/common/service/NetRemoteService.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <vector>

#include <magic_enum.hpp>
#include <microsoft/net/remote/NetRemoteService.hxx>
#include <microsoft/net/wifi/IAccessPoint.hxx>
#include <microsoft/net/wifi/IAccessPointController.hxx>
Expand Down Expand Up @@ -195,17 +196,31 @@ Dot11FrequencyBand
IeeeDot11FrequencyBandToNetRemoteDot11FrequencyBand(Ieee80211FrequencyBand ieeeDot11FrequencyBand)
{
switch (ieeeDot11FrequencyBand) {
case Ieee80211FrequencyBand::Unknown:
return Dot11FrequencyBand::Dot11FrequencyBandUnknown;
case Ieee80211FrequencyBand::TwoPointFourGHz:
return Dot11FrequencyBand::Dot11FrequencyBandTwoPoint4GHz;
case Ieee80211FrequencyBand::FiveGHz:
return Dot11FrequencyBand::Dot11FrequencyBandFiveGHz;
case Ieee80211FrequencyBand::SixGHz:
return Dot11FrequencyBand::Dot11FrequencyBandSixGHz;
default:
return Dot11FrequencyBand::Dot11FrequencyBandUnknown;
}
}

return Dot11FrequencyBand::Dot11FrequencyBandUnknown;
Ieee80211FrequencyBand
NetRemoteDot11FrequencyBandToIeee80211FrequencyBand(Dot11FrequencyBand dot11FrequencyBand)
{
switch (dot11FrequencyBand) {
case Dot11FrequencyBand::Dot11FrequencyBand2_4GHz:
return Ieee80211FrequencyBand::TwoPointFourGHz;
case Dot11FrequencyBand::Dot11FrequencyBand5_0GHz:
return Ieee80211FrequencyBand::FiveGHz;
case Dot11FrequencyBand::Dot11FrequencyBand6_0GHz:
return Ieee80211FrequencyBand::SixGHz;
case Dot11FrequencyBand::Dot11FrequencyBandUnknown:
default:
return Ieee80211FrequencyBand::Unknown;
}
}

using Microsoft::Net::Wifi::Dot11AuthenticationAlgorithm;
Expand Down Expand Up @@ -563,7 +578,7 @@ NetRemoteService::WifiAccessPointSetPhyType([[maybe_unused]] ::grpc::ServerConte
}
} 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()));
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInternalError, std::format("Failed to get capabilities for access point {}", request->accesspointid()));
}

// Set the Ieee80211 protocol.
Expand All @@ -572,8 +587,7 @@ NetRemoteService::WifiAccessPointSetPhyType([[maybe_unused]] ::grpc::ServerConte
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()));
return handleFailure(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInternalError, std::format("Failed to set PHY type for access point {} ({})", request->accesspointid(), apce.what()));
}

status.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);
Expand All @@ -583,8 +597,106 @@ NetRemoteService::WifiAccessPointSetPhyType([[maybe_unused]] ::grpc::ServerConte
return grpc::Status::OK;
}

using Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsRequest;
using Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsResult;
using Microsoft::Net::Wifi::Dot11FrequencyBand;

namespace detail
{
std::vector<Dot11FrequencyBand>
GetFrequencyBands(const WifiAccessPointSetFrequencyBandsRequest& request)
{
const auto& frequencyBands = request.frequencybands();

std::vector<Dot11FrequencyBand> bands(static_cast<std::size_t>(std::size(frequencyBands)));
std::ranges::transform(frequencyBands, std::begin(bands), [](const auto& frequencyBand) {
return static_cast<Dot11FrequencyBand>(frequencyBand);
});

return bands;
}


} // namespace detail

/* static */
bool
NetRemoteService::ValidateWifiSetFrequencyBandsRequest(const WifiAccessPointSetFrequencyBandsRequest* request, WifiAccessPointSetFrequencyBandsResult* result)
{
const auto& frequencyBands = request->frequencybands();

if (std::empty(frequencyBands)) {
detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter, "No frequency band provided");
return false;
} else if (std::ranges::find(frequencyBands, Dot11FrequencyBand::Dot11FrequencyBandUnknown) != std::cend(frequencyBands)) {
detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInvalidParameter, "Invalid frequency band provided");
return false;
}

return true;
}

using Microsoft::Net::Wifi::Ieee80211AccessPointCapabilities;

::grpc::Status
NetRemoteService::WifiAccessPointSetFrequencyBands([[maybe_unused]] ::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsResult* result)
{
LOGD << std::format("Received WifiAccessPointSetFrequencyBands request for access point id {}", request->accesspointid());

// Validate basic parameters in the request.
if (!ValidateWifiSetFrequencyBandsRequest(request, result)) {
return grpc::Status::OK;
}

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

// Convert dot11 bands to ieee80211 bands.
const auto& frequencyBands = detail::GetFrequencyBands(*request);
std::vector<Microsoft::Net::Wifi::Ieee80211FrequencyBand> ieeeFrequencyBands(static_cast<std::size_t>(std::size(frequencyBands)));
std::ranges::transform(frequencyBands, std::begin(ieeeFrequencyBands), detail::NetRemoteDot11FrequencyBandToIeee80211FrequencyBand);

// Obtain capabilities of the access point.
Ieee80211AccessPointCapabilities accessPointCapabilities{};
try {
accessPointCapabilities = accessPointController->GetCapabilities();
} catch (const AccessPointControllerException& apce) {
return detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInternalError, std::format("Failed to get capabilities for access point {} ({})", request->accesspointid(), apce.what()));
}

// Check if requested bands are supported by the AP.
for (const auto& requestedFrequencyBand : ieeeFrequencyBands) {
if (std::ranges::find(accessPointCapabilities.FrequencyBands, requestedFrequencyBand) == std::cend(accessPointCapabilities.FrequencyBands)) {
return detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeOperationNotSupported, std::format("Frequency band {} not supported by access point {}", magic_enum::enum_name(requestedFrequencyBand), request->accesspointid()));
}
}

// Attempt to set the frequency bands.
try {
const auto setBandsSucceeded = accessPointController->SetFrequencyBands(std::move(ieeeFrequencyBands));
if (!setBandsSucceeded) {
return detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInternalError, std::format("Failed to set frequency bands for access point {}", request->accesspointid()));
}
} catch (const AccessPointControllerException& apce) {
return detail::HandleFailure(request, result, WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeInternalError, std::format("Failed to set frequency bands for access point {} ({})", request->accesspointid(), apce.what()));
}

// Prepare result with success indication.
WifiAccessPointOperationStatus status{};
status.set_code(WifiAccessPointOperationStatusCode::WifiAccessPointOperationStatusCodeSucceeded);

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

return grpc::Status::OK;
}

/* static */
bool
NetRemoteService::ValidateWifiAccessPointEnableRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointEnableRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus& status)
NetRemoteService::ValidateWifiAccessPointEnableRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointEnableRequest* request, WifiAccessPointOperationStatus& status)
{
// Validate required arguments are present. Detailed argument validation is left to the implementation.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,16 @@ private:
virtual ::grpc::Status
WifiAccessPointSetPhyType(::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetPhyTypeResult* response) override;

virtual ::grpc::Status
WifiAccessPointSetFrequencyBands(::grpc::ServerContext* context, const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsResult* response) override;

protected:
bool
static bool
ValidateWifiAccessPointEnableRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointEnableRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointOperationStatus& status);

static bool
ValidateWifiSetFrequencyBandsRequest(const ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsRequest* request, ::Microsoft::Net::Remote::Wifi::WifiAccessPointSetFrequencyBandsResult* result);

private:
std::shared_ptr<Microsoft::Net::Wifi::AccessPointManager> m_accessPointManager;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ struct IAccessPointController
*/
virtual bool
SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol ieeeProtocol) = 0;

/**
* @brief Set the frquency bands the access point should enable.
*
* @param frequencyBands The frequency bands to be set.
* @return true
* @return false
*/
virtual bool
SetFrequencyBands(std::vector<Microsoft::Net::Wifi::Ieee80211FrequencyBand> frequencyBands) = 0;
};

/**
Expand Down
69 changes: 67 additions & 2 deletions src/linux/wifi/core/AccessPointControllerLinux.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <algorithm>
#include <format>
#include <ranges>
#include <sstream>

#include <Wpa/IHostapd.hxx>
#include <Wpa/ProtocolHostapd.hxx>
Expand All @@ -10,6 +11,7 @@
#include <magic_enum.hpp>
#include <microsoft/net/netlink/nl80211/Netlink80211Wiphy.hxx>
#include <microsoft/net/wifi/AccessPointControllerLinux.hxx>
#include <plog/Log.h>

using namespace Microsoft::Net::Wifi;

Expand Down Expand Up @@ -119,6 +121,21 @@ HostapdHwModeToPropertyValue(Wpa::HostapdHwMode hwMode)
throw AccessPointControllerException(std::format("Invalid hostapd hw_mode value {}", magic_enum::enum_name(hwMode)));
}
}

std::string_view
IeeeFrequencyBandToHostapdBand(Ieee80211FrequencyBand ieeeFrequencyBand)
{
switch (ieeeFrequencyBand) {
case Ieee80211FrequencyBand::TwoPointFourGHz:
return Wpa::ProtocolHostapd::PropertySetBandValue2G;
case Ieee80211FrequencyBand::FiveGHz:
return Wpa::ProtocolHostapd::PropertySetBandValue5G;
case Ieee80211FrequencyBand::SixGHz:
return Wpa::ProtocolHostapd::PropertySetBandValue6G;
default:
throw AccessPointControllerException(std::format("Invalid ieee80211 frequency band value {}", magic_enum::enum_name(ieeeFrequencyBand)));
}
}
} // namespace detail

Ieee80211AccessPointCapabilities
Expand Down Expand Up @@ -196,8 +213,56 @@ AccessPointControllerLinux::SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol
throw AccessPointControllerException(std::format("Failed to set Ieee80211 protocol for interface {} ({})", GetInterfaceName(), ex.what()));
}

// Reload hostapd conf file.
return isOk && m_hostapd.Reload();
if (isOk) {
// Reload hostapd configuration.
isOk = m_hostapd.Reload();
if (!isOk) {
LOGE << std::format("Failed to reload hostapd configuration for interface {}", GetInterfaceName());
return false;
}
}

return isOk;
}

bool
AccessPointControllerLinux::SetFrequencyBands(std::vector<Ieee80211FrequencyBand> frequencyBands)
{
// Ensure at least one band is requested.
if (std::empty(frequencyBands)) {
LOGW << std::format("No frequency bands specified for interface {}", GetInterfaceName());
return false;
}

// Generate the argument for the hostapd "setband" command, which accepts a comma separated list of bands.
std::ostringstream setBandArgumentBuilder;
for (const auto& band : frequencyBands) {
setBandArgumentBuilder << detail::IeeeFrequencyBandToHostapdBand(band) << ',';
}

std::string setBandArgumentAll = setBandArgumentBuilder.str();
std::string_view setBandArgument(std::data(setBandArgumentAll), std::size(setBandArgumentAll) - 1); // Remove trailing comma

bool isOk = false;
try {
// Set the hostapd "setband" property.
isOk = m_hostapd.SetProperty(Wpa::ProtocolHostapd::PropertyNameSetBand, setBandArgument);
if (!isOk) {
LOGE << std::format("Failed to set frequency bands for interface {}", GetInterfaceName());
return false;
}

// Reload hostapd configuration to pick up the changes.
isOk = m_hostapd.Reload();
if (!isOk) {
LOGE << std::format("Failed to reload hostapd configuration for interface {}", GetInterfaceName());
return false;
}
} catch (const Wpa::HostapdException& ex) {
throw AccessPointControllerException(std::format("Failed to set frequency bands for interface {} ({})", GetInterfaceName(), ex.what()));
}

return true;
}

std::unique_ptr<IAccessPointController>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
#define ACCESS_POINT_CONTROLLER_LINUX_HXX

#include <string_view>
#include <vector>

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

namespace Microsoft::Net::Wifi
{
Expand Down Expand Up @@ -54,6 +55,16 @@ struct AccessPointControllerLinux :
virtual bool
SetProtocol(Microsoft::Net::Wifi::Ieee80211Protocol ieeeProtocol) override;

/**
* @brief Set the frquency bands the access point should enable.
*
* @param frequencyBands The frequency bands to be set.
* @return true
* @return false
*/
virtual bool
SetFrequencyBands(std::vector<Microsoft::Net::Wifi::Ieee80211FrequencyBand> frequencyBands) override;

private:
Wpa::Hostapd m_hostapd;
};
Expand Down
Loading

0 comments on commit f58704c

Please sign in to comment.