Skip to content

Commit

Permalink
Merge pull request #307 from microsoft/user/corbinphipps/add-get_conf…
Browse files Browse the repository at this point in the history
…ig-command

Add GET_CONFIG command
  • Loading branch information
abeltrano authored Jul 3, 2024
2 parents 5b8a329 + 577bd1e commit 30999e8
Show file tree
Hide file tree
Showing 11 changed files with 371 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/linux/wpa-controller/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ target_sources(wpa-controller
ProtocolWpa.cxx
WpaCommand.cxx
WpaCommandGet.cxx
WpaCommandGetConfig.cxx
WpaCommandSet.cxx
WpaCommandStatus.cxx
WpaController.cxx
Expand All @@ -38,6 +39,7 @@ target_sources(wpa-controller
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/ProtocolWpaConfig.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaCommand.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaCommandGet.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaCommandGetConfig.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaCommandSet.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaCommandStatus.hxx
${WPA_CONTROLLER_PUBLIC_INCLUDE_PREFIX}/WpaController.hxx
Expand Down
15 changes: 15 additions & 0 deletions src/linux/wpa-controller/Hostapd.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
#include <Wpa/ProtocolHostapd.hxx>
#include <Wpa/WpaCommand.hxx>
#include <Wpa/WpaCommandGet.hxx>
#include <Wpa/WpaCommandGetConfig.hxx>
#include <Wpa/WpaCommandSet.hxx>
#include <Wpa/WpaCommandStatus.hxx>
#include <Wpa/WpaControlSocket.hxx>
#include <Wpa/WpaControlSocketConnection.hxx>
#include <Wpa/WpaCore.hxx>
#include <Wpa/WpaResponseGetConfig.hxx>
#include <Wpa/WpaResponseStatus.hxx>
#include <magic_enum.hpp>
#include <microsoft/net/wifi/Ieee80211.hxx>
Expand Down Expand Up @@ -135,6 +137,19 @@ Hostapd::GetProperty(std::string_view propertyName)
return propertyValue;
}

HostapdBssConfiguration
Hostapd::GetConfiguration()
{
static constexpr WpaCommandGetConfig GetConfigCommand{};

auto response = m_controller.SendCommand<WpaResponseGetConfig>(GetConfigCommand);
if (!response) {
throw HostapdException("Failed to send hostapd 'get_config' command");
}

return response->Configuration;
}

void
Hostapd::SetProperty(std::string_view propertyName, std::string_view propertyValue, EnforceConfigurationChange enforceConfigurationChange)
{
Expand Down
53 changes: 53 additions & 0 deletions src/linux/wpa-controller/ProtocolHostapd.cxx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

#include <sstream>
#include <string>
#include <string_view>
#include <utility>
Expand Down Expand Up @@ -85,3 +86,55 @@ Wpa::WpaPreSharedKeyPropertyKeyAndValue(const WpaPreSharedKey& wpaPreSharedKey)
auto propertyValue = WpaPreSharedKeyPropertyValue(wpaPreSharedKey);
return std::make_pair(propertyName, std::move(propertyValue));
}

std::vector<WpaKeyManagement>
Wpa::WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept
{
std::string wpaKeyManagementString(wpaKeyManagementProperty);
std::istringstream wpaKeyManagementStream(wpaKeyManagementString);
std::vector<WpaKeyManagement> wpaKeyManagements{};

for (std::string wpaKeyManagement; wpaKeyManagementStream >> wpaKeyManagement;) {
if (wpaKeyManagement == "WPA-EAP") {
wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021x);
} else if (wpaKeyManagement == "WPA-PSK") {
wpaKeyManagements.push_back(WpaKeyManagement::Psk);
} else if (wpaKeyManagement == "FT-EAP") {
wpaKeyManagements.push_back(WpaKeyManagement::FtIeee8021x);
} else if (wpaKeyManagement == "FT-PSK") {
wpaKeyManagements.push_back(WpaKeyManagement::FtPsk);
} else if (wpaKeyManagement == "WPA-EAP-SHA256") {
wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSha256);
} else if (wpaKeyManagement == "WPA-PSK-SHA256") {
wpaKeyManagements.push_back(WpaKeyManagement::PskSha256);
} else if (wpaKeyManagement == "SAE") {
wpaKeyManagements.push_back(WpaKeyManagement::Sae);
} else if (wpaKeyManagement == "FT-SAE") {
wpaKeyManagements.push_back(WpaKeyManagement::FtSae);
} else if (wpaKeyManagement == "OSEN") {
wpaKeyManagements.push_back(WpaKeyManagement::Osen);
} else if (wpaKeyManagement == "WPA-EAP-SUITE-B") {
wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSuiteB);
} else if (wpaKeyManagement == "WPA-EAP-SUITE-B-192") {
wpaKeyManagements.push_back(WpaKeyManagement::Ieee8021xSuiteB192);
} else if (wpaKeyManagement == "FILS-SHA256") {
wpaKeyManagements.push_back(WpaKeyManagement::FilsSha256);
} else if (wpaKeyManagement == "FILS-SHA384") {
wpaKeyManagements.push_back(WpaKeyManagement::FilsSha384);
} else if (wpaKeyManagement == "FT-FILS-SHA256") {
wpaKeyManagements.push_back(WpaKeyManagement::FtFilsSha256);
} else if (wpaKeyManagement == "FT-FILS-SHA384") {
wpaKeyManagements.push_back(WpaKeyManagement::FtFilsSha384);
} else if (wpaKeyManagement == "OWE") {
wpaKeyManagements.push_back(WpaKeyManagement::Owe);
} else if (wpaKeyManagement == "DPP") {
wpaKeyManagements.push_back(WpaKeyManagement::Dpp);
} else if (wpaKeyManagement == "FT-EAP-SHA384") {
wpaKeyManagements.push_back(WpaKeyManagement::FtIeee8021xSha384);
} else if (wpaKeyManagement == "PASN") {
wpaKeyManagements.push_back(WpaKeyManagement::Pasn);
}
}

return wpaKeyManagements;
}
71 changes: 71 additions & 0 deletions src/linux/wpa-controller/WpaCommandGetConfig.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

#include <memory>
#include <string_view>
#include <utility>

#include <Wpa/ProtocolHostapd.hxx>
#include <Wpa/ProtocolWpa.hxx>
#include <Wpa/WpaCommandGetConfig.hxx>
#include <Wpa/WpaKeyValuePair.hxx>
#include <Wpa/WpaResponse.hxx>
#include <Wpa/WpaResponseGetConfig.hxx>
#include <Wpa/WpaResponseParser.hxx>
#include <plog/Log.h>

#include "WpaParsingUtilities.hxx"

using namespace Wpa;

std::unique_ptr<WpaResponseParser>
WpaCommandGetConfig::CreateResponseParser(const WpaCommand* command, std::string_view responsePayload) const
{
return std::make_unique<WpaGetConfigResponseParser>(command, responsePayload);
}

// clang-format off
WpaGetConfigResponseParser::WpaGetConfigResponseParser(const WpaCommand* command, std::string_view responsePayload) :
WpaResponseParser(command, responsePayload, {
{ ProtocolHostapd::ResponseGetConfigPropertyKeyBssid, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeySsid, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeyWpa, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeyWpaKeyMgmt, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeyGroupCipher, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeyRsnPairwiseCipher, WpaValuePresence::Required },
{ ProtocolHostapd::ResponseGetConfigPropertyKeyWpaPairwiseCipher, WpaValuePresence::Required },
})
// clang-format on
{
}

std::shared_ptr<WpaResponse>
WpaGetConfigResponseParser::ParsePayload()
{
using namespace Wpa::Parsing;

const auto& properties = GetProperties();
const auto response = std::make_shared<WpaResponseGetConfig>();
auto& configuration = response->Configuration;

for (const auto& [key, mapped] : properties) {
const auto& [value, index] = mapped;
if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyBssid) {
configuration.Bssid = value;
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeySsid) {
configuration.Ssid = value;
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyWpa) {
int wpa;
ParseInt(value, wpa);
configuration.Wpa = static_cast<Wpa::WpaSecurityProtocol>(wpa);
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyWpaKeyMgmt) {
configuration.WpaKeyMgmt = WpaKeyManagementFromPropertyValue(value);
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyGroupCipher) {
configuration.GroupCipher = WpaCipherFromPropertyValue(value);
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyRsnPairwiseCipher) {
configuration.RsnPairwiseCipher = WpaCipherFromPropertyValue(value);
} else if (key == ProtocolHostapd::ResponseGetConfigPropertyKeyWpaPairwiseCipher) {
configuration.WpaPairwiseCipher = WpaCipherFromPropertyValue(value);
}
}

return response;
}
8 changes: 8 additions & 0 deletions src/linux/wpa-controller/include/Wpa/Hostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ struct Hostapd :
std::string
GetProperty(std::string_view propertyName) override;

/**
* @brief Get the configuration for the interface.
*
* @return HostapdBssConfiguration The configuration string value.
*/
HostapdBssConfiguration
GetConfiguration() override;

/**
* @brief Set a property on the interface.
*
Expand Down
8 changes: 8 additions & 0 deletions src/linux/wpa-controller/include/Wpa/IHostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ struct IHostapd
virtual std::string
GetProperty(std::string_view propertyName) = 0;

/**
* @brief Get the configuration for the interface.
*
* @return HostapdBssConfiguration The configuration string value.
*/
virtual HostapdBssConfiguration
GetConfiguration() = 0;

/**
* @brief Set a property on the interface.
*
Expand Down
114 changes: 114 additions & 0 deletions src/linux/wpa-controller/include/Wpa/ProtocolHostapd.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,54 @@ struct HostapdStatus
// unsigned ChannelUtilitzationAverage;
};

struct HostapdBssConfiguration
{
// TODO: All types used below are direct translations of the types used in
// the hostapd code; there may be better representations of them.

std::string Bssid;
std::string Ssid;

// Note: The following fields do not yet have parsing code so they are
// commented out for the time being. Many of them may not be kept if they
// have no use in the implementation, but for now, this is a complete list
// of all fields that are returned from the 'GET_CONFIG' message.

// // Present with:
// // - CONFIG_WPS compilation option
// std::optional<int> WpsState;

// // Present with:
// // - Value for current 'wps_state" is set.
// // - Value for current 'wpa' is set.
// std::optional<WpaPreSharedKey> WpaPassphrase;
// std::optional<WpaPreSharedKey> WpaPsk;

// // Present with:
// // - 'multi_ap=1' OR 'multi_ap=3' configuration file option
// std::optional<int> MultiApMode;
// std::optional<std::string> MultiApBackhaulSsid;

// // Present with:
// // - 'multi_ap=1' OR 'multi_ap=3' configuration file option
// // - Value for current 'wps_state' is set.
// // - Value for current 'wpa' is set.
// std::optional<WpaPreSharedKey> MultiApBackhaulWpaPassphrase;
// std::optional<WpaPreSharedKey> MultiApBackhaulWpaPsk;

WpaSecurityProtocol Wpa;
std::vector<WpaKeyManagement> WpaKeyMgmt;
WpaCipher GroupCipher;
WpaCipher RsnPairwiseCipher;
WpaCipher WpaPairwiseCipher;

// // Present only if 'wpa' and a current 'wpa_deny_ptk0_rekey' value is set.
// std::optional<int> WpaDenyPtk0Rekey;

// // Present only if driver supports it and if RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
// std::optional<int> ExtendedKeyId;
};

struct ProtocolHostapd :
public ProtocolWpa
{
Expand Down Expand Up @@ -608,6 +656,12 @@ struct ProtocolHostapd :
static constexpr auto PropertyValueSaePasswordClearAll = "";
static constexpr auto PropertyValueSaeKeyValueSeparator = "|";

// Property names for "GET_CONFIG" command.
static constexpr auto PropertyNameKeyManagement = "key_mgmt";
static constexpr auto PropertyNameGroupCipher = "group_cipher";
static constexpr auto PropertyNameRsnPairwiseCipher = "rsn_pairwise_cipher";
static constexpr auto PropertyNameWpaPairwiseCipher = "wpa_pairwise_cipher";

// Response properties for the "STATUS" command.
// Note: all properties must be terminated with the key-value delimeter (=).
static constexpr auto ResponseStatusPropertyKeyState = PropertyNameState;
Expand All @@ -617,6 +671,16 @@ struct ProtocolHostapd :
static constexpr auto ResponseStatusPropertyKeyDisableAC = PropertyNameDisable11AC;
static constexpr auto ResponseStatusPropertyKeyIeee80211AX = PropertyNameIeee80211AX;
static constexpr auto ResponseStatusPropertyKeyDisableAX = PropertyNameDisable11AX;

// Response properties for the "GET_CONFIG" command.
// Note: all properties must be terminated with the key-value delimeter (=).
static constexpr auto ResponseGetConfigPropertyKeyBssid = PropertyNameBssBssid;
static constexpr auto ResponseGetConfigPropertyKeySsid = PropertyNameBssSsid;
static constexpr auto ResponseGetConfigPropertyKeyWpa = PropertyNameWpaSecurityProtocol;
static constexpr auto ResponseGetConfigPropertyKeyWpaKeyMgmt = PropertyNameKeyManagement;
static constexpr auto ResponseGetConfigPropertyKeyGroupCipher = PropertyNameGroupCipher;
static constexpr auto ResponseGetConfigPropertyKeyRsnPairwiseCipher = PropertyNameRsnPairwiseCipher;
static constexpr auto ResponseGetConfigPropertyKeyWpaPairwiseCipher = PropertyNameWpaPairwiseCipher;
};

/**
Expand Down Expand Up @@ -766,6 +830,16 @@ WpaKeyManagementPropertyValue(WpaKeyManagement wpaKeyManagement) noexcept
}
}

/**
* @brief Convert a hostapd 'wpa_key_mgmt' property value string to the corresponding WpaKeyManagement value.
* This string may have several whitespace-separated values, such as "WPA-PSK SAE".
*
* @param wpaKeyManagementProperty The hostapd property value string to convert.
* @return std::vector<WpaKeyManagement> The corresponding WpaKeyManagement values.
*/
std::vector<WpaKeyManagement>
WpaKeyManagementFromPropertyValue(std::string_view wpaKeyManagementProperty) noexcept;

/**
* @brief WpaCipher sentinel for an invalid value.
*/
Expand Down Expand Up @@ -815,6 +889,46 @@ WpaCipherPropertyValue(WpaCipher wpaCipher) noexcept
}
}

/**
* @brief Convert a hostapd cipher property string such as 'wpa_pairwise' and 'rsn_pairwise' to the corresponding WpaCipher value.
*
* @param wpaCipher The hostapd property value string to convert.
* @return constexpr WpaCipher The corresponding WpaCipher value.
*/
constexpr WpaCipher
WpaCipherFromPropertyValue(std::string_view wpaCipherProperty) noexcept
{
if (wpaCipherProperty == "NONE") {
return WpaCipher::None;
} else if (wpaCipherProperty == "WEP40") {
return WpaCipher::Wep40;
} else if (wpaCipherProperty == "WEP104") {
return WpaCipher::Wep104;
} else if (wpaCipherProperty == "TKIP") {
return WpaCipher::Tkip;
} else if (wpaCipherProperty == "CCMP") {
return WpaCipher::Ccmp;
} else if (wpaCipherProperty == "AES-128-CMAC") {
return WpaCipher::Aes128Cmac;
} else if (wpaCipherProperty == "GCMP") {
return WpaCipher::Gcmp;
} else if (wpaCipherProperty == "GCMP-256") {
return WpaCipher::Gcmp256;
} else if (wpaCipherProperty == "CCMP-256") {
return WpaCipher::Ccmp256;
} else if (wpaCipherProperty == "BIP-GMAC-128") {
return WpaCipher::BipGmac128;
} else if (wpaCipherProperty == "BIP-GMAC-256") {
return WpaCipher::BipGmac256;
} else if (wpaCipherProperty == "BIP-CMAC-256") {
return WpaCipher::BipCmac256;
} else if (wpaCipherProperty == "GTK_NOT_USED") {
return WpaCipher::GtkNotUsed;
} else {
return WpaCipher::Unknown;
}
}

/**
* @brief Get the hostapd property name to use to set the cipher for the specified WPA protocol.
*
Expand Down
1 change: 1 addition & 0 deletions src/linux/wpa-controller/include/Wpa/ProtocolWpa.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct ProtocolWpa
static constexpr auto CommandPayloadTerminate = "TERMINATE";
static constexpr auto CommandPayloadRelog = "RELOG";
static constexpr auto CommandPayloadGet = "GET";
static constexpr auto CommandPayloadGetConfig = "GET_CONFIG";
static constexpr auto CommandPayloadSet = "SET";
static constexpr auto CommandPayloadNote = "NOTE";
static constexpr auto CommandPayloadMib = "MIB";
Expand Down
Loading

0 comments on commit 30999e8

Please sign in to comment.