diff --git a/CMakeLists.txt b/CMakeLists.txt index 5791bbb7..e1d8c3b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,12 +125,12 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GN endif() endif() elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - # TODO + # Nothing special needed for MSVC at the moment. endif() -if (CMAKE_BUILD_TYPE MATCHES "(Release|RelWithDebInfo|MinSizeRel)") - add_compile_definitions(_FORTIFY_SOURCE=2) -endif() +# Add conditional compile definitions based on build type. +add_compile_definitions("$<$:DEBUG>") +add_compile_definitions("$<$:_FORTIFY_SOURCE=2>") # Common source directories set(NETREMOTE_DIR_SRC ${CMAKE_CURRENT_LIST_DIR}/src) diff --git a/src/linux/libnl-helpers/CMakeLists.txt b/src/linux/libnl-helpers/CMakeLists.txt index 3bdf79f4..94ec9494 100644 --- a/src/linux/libnl-helpers/CMakeLists.txt +++ b/src/linux/libnl-helpers/CMakeLists.txt @@ -7,6 +7,7 @@ set(LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX ${LIBNL_HELPERS_PUBLIC_INCLUDE}/${LIBNL_ target_sources(libnl-helpers PRIVATE + Netlink80211.cxx NetlinkSocket.cxx NetlinkMessage.cxx PUBLIC @@ -15,6 +16,7 @@ target_sources(libnl-helpers FILES ${LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX}/NetlinkMessage.hxx ${LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX}/NetlinkSocket.hxx + ${LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX}/nl80211/Netlink80211.hxx ) target_link_libraries(libnl-helpers diff --git a/src/linux/libnl-helpers/Netlink80211.cxx b/src/linux/libnl-helpers/Netlink80211.cxx new file mode 100644 index 00000000..16dcfaf9 --- /dev/null +++ b/src/linux/libnl-helpers/Netlink80211.cxx @@ -0,0 +1,450 @@ + +#include + +namespace Microsoft::Net::Netlink::Nl80211 +{ +std::string_view +Nl80211CommandToString(nl80211_commands command) noexcept +{ + switch (command) { + case NL80211_CMD_UNSPEC: + return "NL80211_CMD_UNSPEC"; + + case NL80211_CMD_GET_WIPHY: + return "NL80211_CMD_GET_WIPHY"; + case NL80211_CMD_SET_WIPHY: + return "NL80211_CMD_SET_WIPHY"; + case NL80211_CMD_NEW_WIPHY: + return "NL80211_CMD_NEW_WIPHY"; + case NL80211_CMD_DEL_WIPHY: + return "NL80211_CMD_DEL_WIPHY"; + + case NL80211_CMD_GET_INTERFACE: + return "NL80211_CMD_GET_INTERFACE"; + case NL80211_CMD_SET_INTERFACE: + return "NL80211_CMD_SET_INTERFACE"; + case NL80211_CMD_NEW_INTERFACE: + return "NL80211_CMD_NEW_INTERFACE"; + case NL80211_CMD_DEL_INTERFACE: + return "NL80211_CMD_DEL_INTERFACE"; + + case NL80211_CMD_GET_KEY: + return "NL80211_CMD_GET_KEY"; + case NL80211_CMD_SET_KEY: + return "NL80211_CMD_SET_KEY"; + case NL80211_CMD_NEW_KEY: + return "NL80211_CMD_NEW_KEY"; + case NL80211_CMD_DEL_KEY: + return "NL80211_CMD_DEL_KEY"; + + case NL80211_CMD_GET_BEACON: + return "NL80211_CMD_GET_BEACON"; + case NL80211_CMD_SET_BEACON: + return "NL80211_CMD_SET_BEACON"; + case NL80211_CMD_NEW_BEACON: + return "NL80211_CMD_NEW_BEACON"; // NL80211_CMD_START_AP + case NL80211_CMD_DEL_BEACON: + return "NL80211_CMD_DEL_BEACON"; // NL80211_CMD_STOP_AP + + case NL80211_CMD_GET_STATION: + return "NL80211_CMD_GET_STATION"; + case NL80211_CMD_SET_STATION: + return "NL80211_CMD_SET_STATION"; + case NL80211_CMD_NEW_STATION: + return "NL80211_CMD_NEW_STATION"; + case NL80211_CMD_DEL_STATION: + return "NL80211_CMD_DEL_STATION"; + + case NL80211_CMD_GET_MPATH: + return "NL80211_CMD_GET_MPATH"; + case NL80211_CMD_SET_MPATH: + return "NL80211_CMD_SET_MPATH"; + case NL80211_CMD_NEW_MPATH: + return "NL80211_CMD_NEW_MPATH"; + case NL80211_CMD_DEL_MPATH: + return "NL80211_CMD_DEL_MPATH"; + + case NL80211_CMD_SET_BSS: + return "NL80211_CMD_SET_BSS"; + + case NL80211_CMD_SET_REG: + return "NL80211_CMD_SET_REG"; + case NL80211_CMD_REQ_SET_REG: + return "NL80211_CMD_REQ_SET_REG"; + + case NL80211_CMD_GET_MESH_CONFIG: + return "NL80211_CMD_GET_MESH_CONFIG"; + case NL80211_CMD_SET_MESH_CONFIG: + return "NL80211_CMD_SET_MESH_CONFIG"; + + case NL80211_CMD_SET_MGMT_EXTRA_IE: + return "NL80211_CMD_SET_MGMT_EXTRA_IE"; + + case NL80211_CMD_GET_REG: + return "NL80211_CMD_GET_REG"; + + case NL80211_CMD_GET_SCAN: + return "NL80211_CMD_GET_SCAN"; + case NL80211_CMD_TRIGGER_SCAN: + return "NL80211_CMD_TRIGGER_SCAN"; + case NL80211_CMD_NEW_SCAN_RESULTS: + return "NL80211_CMD_NEW_SCAN_RESULTS"; + case NL80211_CMD_SCAN_ABORTED: + return "NL80211_CMD_SCAN_ABORTED"; + + case NL80211_CMD_REG_CHANGE: + return "NL80211_CMD_REG_CHANGE"; + + case NL80211_CMD_AUTHENTICATE: + return "NL80211_CMD_AUTHENTICATE"; + case NL80211_CMD_ASSOCIATE: + return "NL80211_CMD_ASSOCIATE"; + case NL80211_CMD_DEAUTHENTICATE: + return "NL80211_CMD_DEAUTHENTICATE"; + case NL80211_CMD_DISASSOCIATE: + return "NL80211_CMD_DISASSOCIATE"; + + case NL80211_CMD_MICHAEL_MIC_FAILURE: + return "NL80211_CMD_MICHAEL_MIC_FAILURE"; + + case NL80211_CMD_REG_BEACON_HINT: + return "NL80211_CMD_REG_BEACON_HINT"; + + case NL80211_CMD_JOIN_IBSS: + return "NL80211_CMD_JOIN_IBSS"; + case NL80211_CMD_LEAVE_IBSS: + return "NL80211_CMD_LEAVE_IBSS"; + + case NL80211_CMD_TESTMODE: + return "NL80211_CMD_TESTMODE"; + + case NL80211_CMD_CONNECT: + return "NL80211_CMD_CONNECT"; + case NL80211_CMD_ROAM: + return "NL80211_CMD_ROAM"; + case NL80211_CMD_DISCONNECT: + return "NL80211_CMD_DISCONNECT"; + + case NL80211_CMD_SET_WIPHY_NETNS: + return "NL80211_CMD_SET_WIPHY_NETNS"; + + case NL80211_CMD_GET_SURVEY: + return "NL80211_CMD_GET_SURVEY"; + case NL80211_CMD_NEW_SURVEY_RESULTS: + return "NL80211_CMD_NEW_SURVEY_RESULTS"; + + case NL80211_CMD_SET_PMKSA: + return "NL80211_CMD_SET_PMKSA"; + case NL80211_CMD_DEL_PMKSA: + return "NL80211_CMD_DEL_PMKSA"; + case NL80211_CMD_FLUSH_PMKSA: + return "NL80211_CMD_FLUSH_PMKSA"; + + case NL80211_CMD_REMAIN_ON_CHANNEL: + return "NL80211_CMD_REMAIN_ON_CHANNEL"; + case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: + return "NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL"; + + case NL80211_CMD_SET_TX_BITRATE_MASK: + return "NL80211_CMD_SET_TX_BITRATE_MASK"; + + case NL80211_CMD_REGISTER_ACTION: + return "NL80211_CMD_REGISTER_ACTION"; // NL80211_CMD_REGISTER_FRAME + case NL80211_CMD_ACTION: + return "NL80211_CMD_ACTION"; // NL80211_CMD_FRAME + case NL80211_CMD_ACTION_TX_STATUS: + return "NL80211_CMD_ACTION_TX_STATUS"; // NL80211_CMD_FRAME_TX_STATUS + + case NL80211_CMD_SET_POWER_SAVE: + return "NL80211_CMD_SET_POWER_SAVE"; + case NL80211_CMD_GET_POWER_SAVE: + return "NL80211_CMD_GET_POWER_SAVE"; + + case NL80211_CMD_SET_CQM: + return "NL80211_CMD_SET_CQM"; + case NL80211_CMD_NOTIFY_CQM: + return "NL80211_CMD_NOTIFY_CQM"; + + case NL80211_CMD_SET_CHANNEL: + return "NL80211_CMD_SET_CHANNEL"; + case NL80211_CMD_SET_WDS_PEER: + return "NL80211_CMD_SET_WDS_PEER"; + + case NL80211_CMD_FRAME_WAIT_CANCEL: + return "NL80211_CMD_FRAME_WAIT_CANCEL"; + + case NL80211_CMD_JOIN_MESH: + return "NL80211_CMD_JOIN_MESH"; + case NL80211_CMD_LEAVE_MESH: + return "NL80211_CMD_LEAVE_MESH"; + + case NL80211_CMD_UNPROT_DEAUTHENTICATE: + return "NL80211_CMD_UNPROT_DEAUTHENTICATE"; + case NL80211_CMD_UNPROT_DISASSOCIATE: + return "NL80211_CMD_UNPROT_DISASSOCIATE"; + + case NL80211_CMD_NEW_PEER_CANDIDATE: + return "NL80211_CMD_NEW_PEER_CANDIDATE"; + + case NL80211_CMD_GET_WOWLAN: + return "NL80211_CMD_GET_WOWLAN"; + case NL80211_CMD_SET_WOWLAN: + return "NL80211_CMD_SET_WOWLAN"; + + case NL80211_CMD_START_SCHED_SCAN: + return "NL80211_CMD_START_SCHED_SCAN"; + case NL80211_CMD_STOP_SCHED_SCAN: + return "NL80211_CMD_STOP_SCHED_SCAN"; + case NL80211_CMD_SCHED_SCAN_RESULTS: + return "NL80211_CMD_SCHED_SCAN_RESULTS"; + case NL80211_CMD_SCHED_SCAN_STOPPED: + return "NL80211_CMD_SCHED_SCAN_STOPPED"; + + case NL80211_CMD_SET_REKEY_OFFLOAD: + return "NL80211_CMD_SET_REKEY_OFFLOAD"; + + case NL80211_CMD_PMKSA_CANDIDATE: + return "NL80211_CMD_PMKSA_CANDIDATE"; + + case NL80211_CMD_TDLS_OPER: + return "NL80211_CMD_TDLS_OPER"; + case NL80211_CMD_TDLS_MGMT: + return "NL80211_CMD_TDLS_MGMT"; + + case NL80211_CMD_UNEXPECTED_FRAME: + return "NL80211_CMD_UNEXPECTED_FRAME"; + + case NL80211_CMD_PROBE_CLIENT: + return "NL80211_CMD_PROBE_CLIENT"; + + case NL80211_CMD_REGISTER_BEACONS: + return "NL80211_CMD_REGISTER_BEACONS"; + + case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: + return "NL80211_CMD_UNEXPECTED_4ADDR_FRAME"; + + case NL80211_CMD_SET_NOACK_MAP: + return "NL80211_CMD_SET_NOACK_MAP"; + + case NL80211_CMD_CH_SWITCH_NOTIFY: + return "NL80211_CMD_CH_SWITCH_NOTIFY"; + + case NL80211_CMD_START_P2P_DEVICE: + return "NL80211_CMD_START_P2P_DEVICE"; + case NL80211_CMD_STOP_P2P_DEVICE: + return "NL80211_CMD_STOP_P2P_DEVICE"; + + case NL80211_CMD_CONN_FAILED: + return "NL80211_CMD_CONN_FAILED"; + + case NL80211_CMD_SET_MCAST_RATE: + return "NL80211_CMD_SET_MCAST_RATE"; + + case NL80211_CMD_SET_MAC_ACL: + return "NL80211_CMD_SET_MAC_ACL"; + + case NL80211_CMD_RADAR_DETECT: + return "NL80211_CMD_RADAR_DETECT"; + + case NL80211_CMD_GET_PROTOCOL_FEATURES: + return "NL80211_CMD_GET_PROTOCOL_FEATURES"; + + case NL80211_CMD_UPDATE_FT_IES: + return "NL80211_CMD_UPDATE_FT_IES"; + case NL80211_CMD_FT_EVENT: + return "NL80211_CMD_FT_EVENT"; + + case NL80211_CMD_CRIT_PROTOCOL_START: + return "NL80211_CMD_CRIT_PROTOCOL_START"; + case NL80211_CMD_CRIT_PROTOCOL_STOP: + return "NL80211_CMD_CRIT_PROTOCOL_STOP"; + + case NL80211_CMD_GET_COALESCE: + return "NL80211_CMD_GET_COALESCE"; + case NL80211_CMD_SET_COALESCE: + return "NL80211_CMD_SET_COALESCE"; + + case NL80211_CMD_CHANNEL_SWITCH: + return "NL80211_CMD_CHANNEL_SWITCH"; + + case NL80211_CMD_VENDOR: + return "NL80211_CMD_VENDOR"; + + case NL80211_CMD_SET_QOS_MAP: + return "NL80211_CMD_SET_QOS_MAP"; + + case NL80211_CMD_ADD_TX_TS: + return "NL80211_CMD_ADD_TX_TS"; + case NL80211_CMD_DEL_TX_TS: + return "NL80211_CMD_DEL_TX_TS"; + + case NL80211_CMD_GET_MPP: + return "NL80211_CMD_GET_MPP"; + + case NL80211_CMD_JOIN_OCB: + return "NL80211_CMD_JOIN_OCB"; + case NL80211_CMD_LEAVE_OCB: + return "NL80211_CMD_LEAVE_OCB"; + + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + return "NL80211_CMD_CH_SWITCH_STARTED_NOTIFY"; + + case NL80211_CMD_TDLS_CHANNEL_SWITCH: + return "NL80211_CMD_TDLS_CHANNEL_SWITCH"; + case NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: + return "NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH"; + + case NL80211_CMD_WIPHY_REG_CHANGE: + return "NL80211_CMD_WIPHY_REG_CHANGE"; + + case NL80211_CMD_ABORT_SCAN: + return "NL80211_CMD_ABORT_SCAN"; + + case NL80211_CMD_START_NAN: + return "NL80211_CMD_START_NAN"; + case NL80211_CMD_STOP_NAN: + return "NL80211_CMD_STOP_NAN"; + case NL80211_CMD_ADD_NAN_FUNCTION: + return "NL80211_CMD_ADD_NAN_FUNCTION"; + case NL80211_CMD_DEL_NAN_FUNCTION: + return "NL80211_CMD_DEL_NAN_FUNCTION"; + case NL80211_CMD_CHANGE_NAN_CONFIG: + return "NL80211_CMD_CHANGE_NAN_CONFIG"; + case NL80211_CMD_NAN_MATCH: + return "NL80211_CMD_NAN_MATCH"; + + case NL80211_CMD_SET_MULTICAST_TO_UNICAST: + return "NL80211_CMD_SET_MULTICAST_TO_UNICAST"; + + case NL80211_CMD_UPDATE_CONNECT_PARAMS: + return "NL80211_CMD_UPDATE_CONNECT_PARAMS"; + + case NL80211_CMD_SET_PMK: + return "NL80211_CMD_SET_PMK"; + case NL80211_CMD_DEL_PMK: + return "NL80211_CMD_DEL_PMK"; + + case NL80211_CMD_PORT_AUTHORIZED: + return "NL80211_CMD_PORT_AUTHORIZED"; + + case NL80211_CMD_RELOAD_REGDB: + return "NL80211_CMD_RELOAD_REGDB"; + + case NL80211_CMD_EXTERNAL_AUTH: + return "NL80211_CMD_EXTERNAL_AUTH"; + + case NL80211_CMD_STA_OPMODE_CHANGED: + return "NL80211_CMD_STA_OPMODE_CHANGED"; + + case NL80211_CMD_CONTROL_PORT_FRAME: + return "NL80211_CMD_CONTROL_PORT_FRAME"; + + case NL80211_CMD_GET_FTM_RESPONDER_STATS: + return "NL80211_CMD_GET_FTM_RESPONDER_STATS"; + + case NL80211_CMD_PEER_MEASUREMENT_START: + return "NL80211_CMD_PEER_MEASUREMENT_START"; + case NL80211_CMD_PEER_MEASUREMENT_RESULT: + return "NL80211_CMD_PEER_MEASUREMENT_RESULT"; + case NL80211_CMD_PEER_MEASUREMENT_COMPLETE: + return "NL80211_CMD_PEER_MEASUREMENT_COMPLETE"; + + case NL80211_CMD_NOTIFY_RADAR: + return "NL80211_CMD_NOTIFY_RADAR"; + + case NL80211_CMD_UPDATE_OWE_INFO: + return "NL80211_CMD_UPDATE_OWE_INFO"; + + case NL80211_CMD_PROBE_MESH_LINK: + return "NL80211_CMD_PROBE_MESH_LINK"; + + case NL80211_CMD_SET_TID_CONFIG: + return "NL80211_CMD_SET_TID_CONFIG"; + + case NL80211_CMD_UNPROT_BEACON: + return "NL80211_CMD_UNPROT_BEACON"; + + case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: + return "NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS"; + + case NL80211_CMD_SET_SAR_SPECS: + return "NL80211_CMD_SET_SAR_SPECS"; + + case NL80211_CMD_OBSS_COLOR_COLLISION: + return "NL80211_CMD_OBSS_COLOR_COLLISION"; + + case NL80211_CMD_COLOR_CHANGE_REQUEST: + return "NL80211_CMD_COLOR_CHANGE_REQUEST"; + + case NL80211_CMD_COLOR_CHANGE_STARTED: + return "NL80211_CMD_COLOR_CHANGE_STARTED"; + case NL80211_CMD_COLOR_CHANGE_ABORTED: + return "NL80211_CMD_COLOR_CHANGE_ABORTED"; + case NL80211_CMD_COLOR_CHANGE_COMPLETED: + return "NL80211_CMD_COLOR_CHANGE_COMPLETED"; + + case NL80211_CMD_SET_FILS_AAD: + return "NL80211_CMD_SET_FILS_AAD"; + + case NL80211_CMD_ASSOC_COMEBACK: + return "NL80211_CMD_ASSOC_COMEBACK"; + + case NL80211_CMD_ADD_LINK: + return "NL80211_CMD_ADD_LINK"; + case NL80211_CMD_REMOVE_LINK: + return "NL80211_CMD_REMOVE_LINK"; + + case NL80211_CMD_ADD_LINK_STA: + return "NL80211_CMD_ADD_LINK_STA"; + case NL80211_CMD_MODIFY_LINK_STA: + return "NL80211_CMD_MODIFY_LINK_STA"; + case NL80211_CMD_REMOVE_LINK_STA: + return "NL80211_CMD_REMOVE_LINK_STA"; + + case NL80211_CMD_SET_HW_TIMESTAMP: + return "NL80211_CMD_SET_HW_TIMESTAMP"; + + case NL80211_CMD_LINKS_REMOVED: + return "NL80211_CMD_LINKS_REMOVED"; + + default: + return "NL80211_CMD_UNKNOWN"; // this name does not correspond to a real command + } +} + +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"; + } +} + +} // namespace Microsoft::Net::Netlink::Nl80211 diff --git a/src/linux/libnl-helpers/include/microsoft/net/netlink/nl80211/Netlink80211.hxx b/src/linux/libnl-helpers/include/microsoft/net/netlink/nl80211/Netlink80211.hxx new file mode 100644 index 00000000..b47f7451 --- /dev/null +++ b/src/linux/libnl-helpers/include/microsoft/net/netlink/nl80211/Netlink80211.hxx @@ -0,0 +1,31 @@ + +#ifndef NETLINK_82011_HXX +#define NETLINK_82011_HXX + +#include + +#include + +namespace Microsoft::Net::Netlink::Nl80211 +{ +/** + * @brief Convert an nl80211_commands enum value to a string. + * + * @param command The nl80211_commands enum value to convert. + * @return std::string_view The string representation of the enum value. + */ +std::string_view +Nl80211CommandToString(nl80211_commands command) noexcept; + +/** + * @brief Convert an nl80211_iftype enum value to a string. + * + * @param type The nl80211_iftype enum value to convert. + * @return std::string_view The string representation of the enum value. + */ +std::string_view +nL80211InterfaceTypeToString(nl80211_iftype type) noexcept; + +} // namespace Microsoft::Net::Netlink::80211 + +#endif // NETLINK_82011_HXX diff --git a/src/linux/tools/apmonitor/Main.cxx b/src/linux/tools/apmonitor/Main.cxx index eedee271..a27359e2 100644 --- a/src/linux/tools/apmonitor/Main.cxx +++ b/src/linux/tools/apmonitor/Main.cxx @@ -26,7 +26,7 @@ main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) auto accessPointDiscoveryAgentOperationsNetlink{ std::make_unique() }; auto accessPointDiscoveryAgent{ AccessPointDiscoveryAgent::Create(std::move(accessPointDiscoveryAgentOperationsNetlink)) }; accessPointDiscoveryAgent->RegisterDiscoveryEventCallback([](auto&& presence, auto&& accessPointChanged) { - PLOG_INFO << std::format("{} {}", magic_enum::enum_name(presence), accessPointChanged != nullptr ? accessPointChanged->GetInterface() : ""); + PLOG_INFO << std::format("{} -> {}", accessPointChanged != nullptr ? accessPointChanged->GetInterface() : "", magic_enum::enum_name(presence)); }); LOG_INFO << "starting access point discovery agent"; diff --git a/src/linux/wifi/apmanager/AccessPointDiscoveryAgentOperationsNetlink.cxx b/src/linux/wifi/apmanager/AccessPointDiscoveryAgentOperationsNetlink.cxx index b8842bfa..b1c277a1 100644 --- a/src/linux/wifi/apmanager/AccessPointDiscoveryAgentOperationsNetlink.cxx +++ b/src/linux/wifi/apmanager/AccessPointDiscoveryAgentOperationsNetlink.cxx @@ -1,13 +1,16 @@ +#include #include #include #include +#include #include #include -#include #include #include +#include +#include #include #include #include @@ -21,6 +24,7 @@ #include using namespace Microsoft::Net::Wifi; +using namespace Microsoft::Net::Netlink::Nl80211; using Microsoft::Net::Netlink::NetlinkMessage; using Microsoft::Net::Netlink::NetlinkSocket; @@ -94,7 +98,7 @@ AccessPointDiscoveryAgentOperationsNetlink::Start(AccessPointPresenceEventCallba if (nl80211NetlinkId == -1) { nl80211NetlinkId = genl_ctrl_resolve(netlinkSocket, NL80211_GENL_NAME); if (nl80211NetlinkId < 0) { - LOG_ERROR << std::format("Failed to resolve nl80211 netlink id with error {}", nl80211NetlinkId); + LOG_ERROR << std::format("Failed to resolve nl80211 netlink id with error {} ({})", nl80211NetlinkId, nl_geterror(nl80211NetlinkId)); return; } m_nl80211NetlinkId = nl80211NetlinkId; @@ -103,11 +107,9 @@ AccessPointDiscoveryAgentOperationsNetlink::Start(AccessPointPresenceEventCallba // Lookup the membership id for the "config" multicast group if not already done. int nl80211MulticastGroupIdConfig = m_nl80211MulticastGroupIdConfig; if (nl80211MulticastGroupIdConfig == -1) { - static constexpr auto NetlinkGenlControlFamilyName = "nlctrl"; - - nl80211MulticastGroupIdConfig = genl_ctrl_resolve_grp(netlinkSocket, NetlinkGenlControlFamilyName, NL80211_MULTICAST_GROUP_CONFIG); + nl80211MulticastGroupIdConfig = genl_ctrl_resolve_grp(netlinkSocket, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG); if (nl80211MulticastGroupIdConfig < 0) { - LOG_ERROR << std::format("Failed to resolve nl80211 multicast group id for config with error {}", nl80211MulticastGroupIdConfig); + LOG_ERROR << std::format("Failed to resolve nl80211 multicast group id for config with error {} ({})", nl80211MulticastGroupIdConfig, nl_geterror(nl80211MulticastGroupIdConfig)); return; } m_nl80211MulticastGroupIdConfig = nl80211MulticastGroupIdConfig; @@ -156,41 +158,83 @@ AccessPointDiscoveryAgentOperationsNetlink::ProbeAsync() int AccessPointDiscoveryAgentOperationsNetlink::ProcessNetlinkMessage(struct nl_msg *netlinkMessage, AccessPointPresenceEventCallback &accessPointPresenceEventCallback) { - std::shared_ptr accessPoint{ nullptr }; - AccessPointPresenceEvent accessPointPresenceEvent; - auto netlinkMessageHeader{ nlmsg_hdr(netlinkMessage) }; - - if (netlinkMessageHeader == nullptr) { - LOG_ERROR << "Netlink message header is null, ignoring message"; + // Ensure the message has a genl header. + auto *netlinkMessageHeader{ static_cast(nlmsg_hdr(netlinkMessage)) }; + if (genlmsg_valid_hdr(netlinkMessageHeader, 1) == 0) { + LOG_ERROR << "Netlink genl message header is invalid, ignoring message"; return NL_SKIP; } - auto interfaceNameAttribute = nlmsg_find_attr(netlinkMessageHeader, sizeof *netlinkMessageHeader, IFLA_IFNAME); - if (interfaceNameAttribute == nullptr) { - LOG_ERROR << "Netlink message does not contain interface name attribute, ignoring message"; + // Extract the nl80211 (genl) message header. + const auto *genlMessageHeader{ static_cast(nlmsg_data(netlinkMessageHeader)) }; + const auto nl80211CommandName{ Nl80211CommandToString(static_cast(genlMessageHeader->cmd)) }; + + // Parse the message attributes. + std::array netlinkMessageAttributes{}; + int ret = nla_parse(std::data(netlinkMessageAttributes), std::size(netlinkMessageAttributes), genlmsg_attrdata(genlMessageHeader, 0), genlmsg_attrlen(genlMessageHeader, 0), nullptr); + if (ret < 0) { + LOG_ERROR << std::format("Failed to parse netlink message attributes with error {} ({})", ret, strerror(-ret)); return NL_SKIP; } - const auto *interfaceName = static_cast(RTA_DATA(interfaceNameAttribute)); - const auto *interfaceInfoMessage{ static_cast(NLMSG_DATA(netlinkMessageHeader)) }; - LOG_VERBOSE << std::format("Received netlink message with type {}, interface {}, index {}", netlinkMessageHeader->nlmsg_type, interfaceName, interfaceInfoMessage->ifi_index); + int interfaceIndex{ -1 }; + const char *interfaceName{ nullptr }; + nl80211_iftype interfaceType{ NL80211_IFTYPE_UNSPECIFIED }; + AccessPointPresenceEvent accessPointPresenceEvent; - switch (netlinkMessageHeader->nlmsg_type) { - case RTM_NEWLINK: - accessPointPresenceEvent = AccessPointPresenceEvent::Arrived; - // TODO: process message + LOG_VERBOSE << std::format("Received {} nl80211 command message", nl80211CommandName); + + switch (genlMessageHeader->cmd) { + case NL80211_CMD_NEW_INTERFACE: + case NL80211_CMD_DEL_INTERFACE: { + interfaceIndex = static_cast(nla_get_u32(netlinkMessageAttributes[NL80211_ATTR_IFINDEX])); + interfaceName = static_cast(nla_data(netlinkMessageAttributes[NL80211_ATTR_IFNAME])); + interfaceType = static_cast(nla_get_u32(netlinkMessageAttributes[NL80211_ATTR_IFTYPE])); + if (interfaceType != NL80211_IFTYPE_AP) { + LOG_VERBOSE << std::format("Ignoring interface presence change nl80211 message for non-ap wi-fi interface (type={})", nL80211InterfaceTypeToString(interfaceType)); + return NL_SKIP; + } + accessPointPresenceEvent = (genlMessageHeader->cmd == NL80211_CMD_NEW_INTERFACE) ? AccessPointPresenceEvent::Arrived : AccessPointPresenceEvent::Departed; break; - case RTM_DELLINK: - accessPointPresenceEvent = AccessPointPresenceEvent::Departed; - // TODO: process message + } + case NL80211_CMD_SET_INTERFACE: { + interfaceIndex = static_cast(nla_get_u32(netlinkMessageAttributes[NL80211_ATTR_IFINDEX])); + interfaceName = static_cast(nla_data(netlinkMessageAttributes[NL80211_ATTR_IFNAME])); + interfaceType = static_cast(nla_get_u32(netlinkMessageAttributes[NL80211_ATTR_IFTYPE])); + accessPointPresenceEvent = (interfaceType == NL80211_IFTYPE_AP) ? AccessPointPresenceEvent::Arrived : AccessPointPresenceEvent::Departed; break; - default: - PLOG_VERBOSE << std::format("Ignoring netlink message with type {}", netlinkMessageHeader->nlmsg_type); + } + // case NL80211_CMD_NEW_BEACON: { + // break; + // } + // case NL80211_CMD_DEL_BEACON: { + // interfaceIndex = static_cast(nla_get_u32(netlinkMessageAttributes[NL80211_ATTR_IFINDEX])); + // break; + // } + default: { + PLOG_VERBOSE << std::format("Ignoring {} nl80211 command message", nl80211CommandName); return NL_SKIP; } + } + + // Update map tracking interface information. Handle the case where the + // interface is already present. This happens for NL80211_CMD_SET_INTERFACE + // when the interface type did not change. + auto interfaceInfo = m_interfaceInfo.find(interfaceIndex); + if (interfaceInfo == std::cend(m_interfaceInfo)) { + if (accessPointPresenceEvent == AccessPointPresenceEvent::Arrived) { + m_interfaceInfo[interfaceIndex] = { interfaceName, interfaceType }; + } + } else { + if (accessPointPresenceEvent == AccessPointPresenceEvent::Departed) { + m_interfaceInfo.erase(interfaceInfo); + } + } + // Invoke presence event callback if present. if (accessPointPresenceEventCallback != nullptr) { - LOG_VERBOSE << std::format("Invoking access point presence event callback with event args 'presence={}, accessPointChanged={}'", magic_enum::enum_name(accessPointPresenceEvent), accessPoint != nullptr ? accessPoint->GetInterface() : ""); + auto accessPoint{ std::make_shared(interfaceName) }; + LOG_VERBOSE << std::format("Invoking access point presence event callback with event args 'interface={}, presence={}'", accessPoint->GetInterface(), magic_enum::enum_name(accessPointPresenceEvent)); accessPointPresenceEventCallback(accessPointPresenceEvent, std::move(accessPoint)); } diff --git a/src/linux/wifi/apmanager/include/microsoft/net/wifi/AccessPointDiscoveryAgentOperationsNetlink.hxx b/src/linux/wifi/apmanager/include/microsoft/net/wifi/AccessPointDiscoveryAgentOperationsNetlink.hxx index 3d3d1d39..b77f208c 100644 --- a/src/linux/wifi/apmanager/include/microsoft/net/wifi/AccessPointDiscoveryAgentOperationsNetlink.hxx +++ b/src/linux/wifi/apmanager/include/microsoft/net/wifi/AccessPointDiscoveryAgentOperationsNetlink.hxx @@ -4,8 +4,11 @@ #include #include +#include #include +#include +#include #include #include #include @@ -94,6 +97,14 @@ private: int m_eventLoopStopFd{ -1 }; std::jthread m_netlinkMessageProcessingThread; + + struct WifiInterfaceInfo + { + std::string Name; + nl80211_iftype Type; + }; + + std::unordered_map m_interfaceInfo; }; } // namespace Microsoft::Net::Wifi