Skip to content

Commit

Permalink
Merge pull request #234 from microsoft/apenableargs
Browse files Browse the repository at this point in the history
Wi-Fi AccessPoint[Enable|Disable] Improvements
  • Loading branch information
abeltrano authored Mar 20, 2024
2 parents df64923 + 5695fe5 commit 879a12f
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 118 deletions.
40 changes: 31 additions & 9 deletions src/common/tools/cli/NetRemoteCli.cxx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@

#include <format>
#include <map>
#include <memory>
#include <string>
#include <utility>

#include <CLI/App.hpp>
#include <CLI/Error.hpp>
#include <CLI/Validators.hpp>
#include <microsoft/net/remote/NetRemoteCli.hxx>
#include <microsoft/net/remote/NetRemoteCliData.hxx>
#include <microsoft/net/remote/NetRemoteCliHandler.hxx>
Expand Down Expand Up @@ -98,7 +100,7 @@ NetRemoteCli::AddSubcommandWifiAccessPointsEnumerate(CLI::App* parent)
{
auto* cliAppWifiAccessPointsEnumerate = parent->add_subcommand("enumerate-access-points", "Enumerate available Wi-Fi access points");
cliAppWifiAccessPointsEnumerate->add_flag("--detailed", m_cliData->DetailedOutput, "Show detailed information about each access point");
cliAppWifiAccessPointsEnumerate->alias("enumaps");
cliAppWifiAccessPointsEnumerate->alias("enumaps")->alias("enum")->alias("aps");
cliAppWifiAccessPointsEnumerate->callback([this] {
OnWifiAccessPointsEnumerate(m_cliData->DetailedOutput.value_or(false));
});
Expand All @@ -109,13 +111,33 @@ NetRemoteCli::AddSubcommandWifiAccessPointsEnumerate(CLI::App* parent)
CLI::App*
NetRemoteCli::AddSubcommandWifiAccessPointEnable(CLI::App* parent)
{
const std::map<std::string, Ieee80211PhyType> Ieee80211PhyTypeNames{
{ "a", Ieee80211PhyType::A },
{ "b", Ieee80211PhyType::B },
{ "g", Ieee80211PhyType::G },
{ "n", Ieee80211PhyType::N },
{ "ac", Ieee80211PhyType::AC },
{ "ax", Ieee80211PhyType::AX },
};

auto* cliAppWifiAccessPointEnable = parent->add_subcommand("access-point-enable", "Enable a Wi-Fi access point");
cliAppWifiAccessPointEnable->alias("ap-enable");
cliAppWifiAccessPointEnable->alias("ap-enable")->alias("enable")->alias("ap-en");
cliAppWifiAccessPointEnable->callback([this] {
OnWifiAccessPointEnable();
Ieee80211AccessPointConfiguration ieee80211AccessPointConfiguration{};
if (!std::empty(m_cliData->WifiAccessPointSsid)) {
ieee80211AccessPointConfiguration.Ssid = m_cliData->WifiAccessPointSsid;
}
if (m_cliData->WifiAccessPointPhyType != Ieee80211PhyType::Unknown) {
ieee80211AccessPointConfiguration.PhyType = m_cliData->WifiAccessPointPhyType;
}

OnWifiAccessPointEnable(m_cliData->WifiAccessPointId, &ieee80211AccessPointConfiguration);
});

cliAppWifiAccessPointEnable->add_option("id", m_cliData->WifiAccessPointId, "The identifier of the access point to enable")->required();
cliAppWifiAccessPointEnable->add_option("--ssid", m_cliData->WifiAccessPointSsid, "The SSID of the access point to enable");
cliAppWifiAccessPointEnable->add_option("--phy,--phyType,", m_cliData->WifiAccessPointPhyType, "The PHY type of the access point to enable")
->transform(CLI::CheckedTransformer(Ieee80211PhyTypeNames, CLI::ignore_case));

return cliAppWifiAccessPointEnable;
}
Expand All @@ -124,9 +146,9 @@ CLI::App*
NetRemoteCli::AddSubcommandWifiAccessPointDisable(CLI::App* parent)
{
auto* cliAppWifiAccessPointDisable = parent->add_subcommand("access-point-disable", "Disable a Wi-Fi access point");
cliAppWifiAccessPointDisable->alias("ap-disable");
cliAppWifiAccessPointDisable->alias("ap-disable")->alias("disable")->alias("ap-dis");
cliAppWifiAccessPointDisable->callback([this] {
OnWifiAccessPointEnable();
OnWifiAccessPointDisable(m_cliData->WifiAccessPointId);
});

cliAppWifiAccessPointDisable->add_option("id", m_cliData->WifiAccessPointId, "The identifier of the access point to disable")->required();
Expand Down Expand Up @@ -163,13 +185,13 @@ NetRemoteCli::OnWifiAccessPointsEnumerate(bool detailedOutput)
}

void
NetRemoteCli::OnWifiAccessPointEnable(const Ieee80211AccessPointConfiguration* ieee80211AccessPointConfiguration)
NetRemoteCli::OnWifiAccessPointEnable(std::string_view accessPointId, const Ieee80211AccessPointConfiguration* ieee80211AccessPointConfiguration)
{
m_cliHandler->HandleCommandWifiAccessPointEnable(m_cliData->WifiAccessPointId, ieee80211AccessPointConfiguration);
m_cliHandler->HandleCommandWifiAccessPointEnable(accessPointId, ieee80211AccessPointConfiguration);
}

void
NetRemoteCli::OnWifiAccessPointDisable()
NetRemoteCli::OnWifiAccessPointDisable(std::string_view accessPointId)
{
m_cliHandler->HandleCommandWifiAccessPointDisable(m_cliData->WifiAccessPointId);
m_cliHandler->HandleCommandWifiAccessPointDisable(accessPointId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,19 @@ private:
/**
* @brief Handle the 'wifi ap-enable' command.
*
* @param accessPointId The identifier of the access point to enable.
* @param ieee80211AccessPointConfiguration Optional configuration for the access point to enable.
*/
void
OnWifiAccessPointEnable(const Microsoft::Net::Wifi::Ieee80211AccessPointConfiguration* ieee80211AccessPointConfiguration = nullptr);
OnWifiAccessPointEnable(std::string_view accessPointId, const Microsoft::Net::Wifi::Ieee80211AccessPointConfiguration* ieee80211AccessPointConfiguration = nullptr);

/**
* @brief Handle the 'wifi ap-disable' command.
*
* @param accessPointId The identifier of the access point to disable.
*/
void
OnWifiAccessPointDisable();
OnWifiAccessPointDisable(std::string_view accessPointId);

private:
std::shared_ptr<NetRemoteCliData> m_cliData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>

#include <microsoft/net/remote/protocol/NetRemoteProtocol.hxx>
#include <microsoft/net/wifi/Ieee80211.hxx>

namespace Microsoft::Net::Remote
{
Expand All @@ -21,6 +22,8 @@ struct NetRemoteCliData
std::optional<bool> DetailedOutput;

std::string WifiAccessPointId{};
std::string WifiAccessPointSsid{};
Microsoft::Net::Wifi::Ieee80211PhyType WifiAccessPointPhyType{ Microsoft::Net::Wifi::Ieee80211PhyType::Unknown };
};
} // namespace Microsoft::Net::Remote

Expand Down
37 changes: 7 additions & 30 deletions src/linux/libnl-helpers/Netlink80211.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <system_error>

#include <linux/nl80211.h>
#include <magic_enum.hpp>
#include <microsoft/net/netlink/NetlinkErrorCategory.hxx>
#include <microsoft/net/netlink/NetlinkSocket.hxx>
#include <microsoft/net/netlink/nl80211/Netlink80211.hxx>
Expand Down Expand Up @@ -425,36 +426,12 @@ Nl80211CommandToString(nl80211_commands command) noexcept
std::string_view
Nl80211InterfaceTypeToString(nl80211_iftype interfaceType) noexcept
{
switch (interfaceType) {
case NL80211_IFTYPE_UNSPECIFIED:
return "NL80211_IFTYPE_UNSPECIFIED";
case NL80211_IFTYPE_ADHOC:
return "NL80211_IFTYPE_ADHOC";
case NL80211_IFTYPE_STATION:
return "NL80211_IFTYPE_STATION";
case NL80211_IFTYPE_AP:
return "NL80211_IFTYPE_AP";
case NL80211_IFTYPE_AP_VLAN:
return "NL80211_IFTYPE_AP_VLAN";
case NL80211_IFTYPE_WDS:
return "NL80211_IFTYPE_WDS";
case NL80211_IFTYPE_MONITOR:
return "NL80211_IFTYPE_MONITOR";
case NL80211_IFTYPE_MESH_POINT:
return "NL80211_IFTYPE_MESH_POINT";
case NL80211_IFTYPE_P2P_CLIENT:
return "NL80211_IFTYPE_P2P_CLIENT";
case NL80211_IFTYPE_P2P_GO:
return "NL80211_IFTYPE_P2P_GO";
case NL80211_IFTYPE_P2P_DEVICE:
return "NL80211_IFTYPE_P2P_DEVICE";
case NL80211_IFTYPE_OCB:
return "NL80211_IFTYPE_OCB";
case NL80211_IFTYPE_NAN:
return "NL80211_IFTYPE_NAN";
default:
return "NL80211_IFTYPE_UNKNOWN";
}
static constexpr auto InterfaceTypePrefixLength{ std::size(std::string_view("NL80211_IFTYPE_")) };

auto interfaceTypeName{ magic_enum::enum_name(interfaceType) };
interfaceTypeName.remove_prefix(InterfaceTypePrefixLength);

return interfaceTypeName;
}

std::string_view
Expand Down
34 changes: 26 additions & 8 deletions src/linux/libnl-helpers/Netlink80211Interface.cxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@

#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <format>
#include <initializer_list>
#include <optional>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -41,7 +44,12 @@ Nl80211Interface::Nl80211Interface(std::string_view name, nl80211_iftype type, u
std::string
Nl80211Interface::ToString() const
{
return std::format("[{}/{}] {} {}", Index, WiphyIndex, Name, magic_enum::enum_name(Type));
static constexpr auto InterfaceTypePrefixLength{ std::size(std::string_view("NL80211_IFTYPE_")) };

auto interfaceType = std::string_view{ magic_enum::enum_name(Type) };
interfaceType.remove_prefix(InterfaceTypePrefixLength);

return std::format("[{}/{}] {} {}", Index, WiphyIndex, Name, interfaceType);
}

/* static */
Expand All @@ -65,18 +73,18 @@ Nl80211Interface::Parse(struct nl_msg *nl80211Message) noexcept
const auto *genl80211MessageHeader{ static_cast<struct genlmsghdr *>(nlmsg_data(nl80211MessageHeader)) };

// Parse the message.
std::array<struct nlattr *, NL80211_ATTR_MAX + 1> newInterfaceMessageAttributes{};
int ret = nla_parse(std::data(newInterfaceMessageAttributes), std::size(newInterfaceMessageAttributes) - 1, genlmsg_attrdata(genl80211MessageHeader, 0), genlmsg_attrlen(genl80211MessageHeader, 0), nullptr);
std::array<struct nlattr *, NL80211_ATTR_MAX + 1> interfaceMessageAttributes{};
int ret = nla_parse(std::data(interfaceMessageAttributes), std::size(interfaceMessageAttributes) - 1, genlmsg_attrdata(genl80211MessageHeader, 0), genlmsg_attrlen(genl80211MessageHeader, 0), nullptr);
if (ret < 0) {
LOGE << std::format("Failed to parse netlink message attributes with error {} ({})", ret, strerror(-ret));
return std::nullopt;
}

// Tease out parameters to populate the Nl80211Interface instance.
const auto *interfaceName = static_cast<const char *>(nla_data(newInterfaceMessageAttributes[NL80211_ATTR_IFNAME]));
auto interfaceType = static_cast<nl80211_iftype>(nla_get_u32(newInterfaceMessageAttributes[NL80211_ATTR_IFTYPE]));
auto interfaceIndex = static_cast<uint32_t>(nla_get_u32(newInterfaceMessageAttributes[NL80211_ATTR_IFINDEX]));
auto wiphyIndex = static_cast<uint32_t>(nla_get_u32(newInterfaceMessageAttributes[NL80211_ATTR_WIPHY]));
const auto *interfaceName = static_cast<const char *>(nla_data(interfaceMessageAttributes[NL80211_ATTR_IFNAME]));
auto interfaceType = static_cast<nl80211_iftype>(nla_get_u32(interfaceMessageAttributes[NL80211_ATTR_IFTYPE]));
auto interfaceIndex = static_cast<uint32_t>(nla_get_u32(interfaceMessageAttributes[NL80211_ATTR_IFINDEX]));
auto wiphyIndex = static_cast<uint32_t>(nla_get_u32(interfaceMessageAttributes[NL80211_ATTR_WIPHY]));

return Nl80211Interface(interfaceName, interfaceType, interfaceIndex, wiphyIndex);
}
Expand Down Expand Up @@ -169,7 +177,17 @@ Nl80211Interface::GetWiphy() const
bool
Nl80211Interface::IsAccessPoint() const noexcept
{
return (Type == nl80211_iftype::NL80211_IFTYPE_AP);
return std::ranges::contains(Nl80211AccessPointInterfaceTypes, Type);
}

bool
Nl80211Interface::SupportsAccessPointMode() const noexcept
{
// clang-format off
return GetWiphy().transform([](const Nl80211Wiphy &wiphy) {
return std::ranges::find_first_of(wiphy.SupportedInterfaceTypes, Nl80211AccessPointInterfaceTypes) != std::cend(wiphy.SupportedInterfaceTypes);
}).value_or(false);
// clang-format on
}

// NOLINTEND(concurrency-mt-unsafe)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define NETLINK_82011_HXX

#include <cstdint>
#include <initializer_list>
#include <string_view>
#include <unordered_map>

Expand Down Expand Up @@ -32,6 +33,14 @@ static const std::unordered_map<Nl80211MulticastGroup, std::string_view> Nl80211
};
// NOLINTEND(cert-err58-cpp)

/**
* @brief List of interface types that indicate support for access point operation.
*/
constexpr std::initializer_list<nl80211_iftype> Nl80211AccessPointInterfaceTypes = {
nl80211_iftype::NL80211_IFTYPE_AP,
nl80211_iftype::NL80211_IFTYPE_AP_VLAN,
};

/**
* @brief Convert an nl80211_commands enum value to a string.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ struct Nl80211Interface
*/
bool
IsAccessPoint() const noexcept;

/**
* @brief Indicates if the interface supports operating as an access point.
*
* @return true The interface can be used as an access point.
* @return false The interface cannot be used as an access point.
*/
bool
SupportsAccessPointMode() const noexcept;
};

} // namespace Microsoft::Net::Netlink::Nl80211
Expand Down
Loading

0 comments on commit 879a12f

Please sign in to comment.