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 access point discovery operations for Linux using netlink #85

Merged
merged 34 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b343a57
Add scaffolding for netlink-based ap discovery operations.
abeltrano Dec 27, 2023
6a50d27
Add libmnl dependency.
abeltrano Dec 28, 2023
8972dd9
Add scope_exit impl.
abeltrano Dec 28, 2023
bbf2322
Add netlink socket establishment.
abeltrano Dec 28, 2023
e0ada5e
Fix libmnl target.
abeltrano Dec 28, 2023
d5c326a
Add initial tests for AccessPointDiscoveryAgentOperationsNetlink.
abeltrano Dec 28, 2023
8b3cde1
Add creation+destroy tests.
abeltrano Dec 28, 2023
427d7d8
Add ProbeAsync impl structure.
abeltrano Dec 28, 2023
59fea0f
Add ProbeAsync basic tests.
abeltrano Dec 28, 2023
ca21f50
Remove linmnl, add libnl.
abeltrano Dec 28, 2023
0321cae
Fix libnl target.
abeltrano Dec 29, 2023
2129db4
Add libnl helper library with raii wrappers.
abeltrano Dec 29, 2023
5de16fc
Document netlink wrappers.
abeltrano Dec 29, 2023
950494f
Add function to allocate new nl_socket.
abeltrano Dec 29, 2023
e65c449
Switch to libnl for async message processing.
abeltrano Dec 29, 2023
9cfb198
Use raii wrappers.
abeltrano Dec 29, 2023
f57daa9
Implement much of the netlink message processing loop.
abeltrano Dec 29, 2023
2af63a0
Make NetlinkSocket non-copyable.
abeltrano Dec 29, 2023
163cc9d
Make NetlinkMessage non-copyable.
abeltrano Dec 29, 2023
e82d899
Add ability to release ownership of NetlinkSocket.
abeltrano Dec 29, 2023
cf344af
Add netlink socket header for convenience.
abeltrano Dec 29, 2023
bfcc1f5
Allow 2nd-tier move of NetlinkSocket in lambda.
abeltrano Dec 29, 2023
e877de0
Add logging output to apmanager test.
abeltrano Dec 29, 2023
0358562
Avoid use of NetlinkMessage wrapper for processing.
abeltrano Dec 29, 2023
dd3f557
FIx presets.
abeltrano Dec 29, 2023
6fdb5b1
Fix bug processing epoll_wait() result.
abeltrano Dec 29, 2023
1b6277d
Add apmonitor test/utility program.
abeltrano Dec 29, 2023
560dea9
Force verbose makefile generation.
abeltrano Dec 29, 2023
b1fc0ce
Update impl to return nl message processing status.
abeltrano Dec 29, 2023
e2a6ed6
Remove libmnl changes from Dockerfile.
abeltrano Dec 29, 2023
25bdf6b
Add libnl-genl and libnl-route libraries.
abeltrano Dec 30, 2023
788de86
Add better cmake cache variable comment.
abeltrano Dec 30, 2023
f7e1639
Remove cmake property helper.
abeltrano Dec 30, 2023
12b8c72
Remove old target.
abeltrano Dec 30, 2023
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
5 changes: 3 additions & 2 deletions .docker/netremote-dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LABEL org.label-schema.schema-version = "1.0"
# sudo apt-get update
#
# 2. Install core build tools and dependencies:
# sudo apt-get install -y --no-install-recommends build-essential ca-certificates cmake curl dotnet7 git gnupg linux-libc-dev ninja-build pkg-config tar unzip zip libnl-3-dev libssl-dev libnl-genl-3-dev libdbus-c++-dev libnl-route-3-dev
# sudo apt-get install -y --no-install-recommends build-essential ca-certificates cmake curl dotnet7 git gnupg linux-libc-dev ninja-build pkg-config tar unzip zip libnl-3-200-dbg libnl-3-dev libssl-dev libnl-genl-3-dev libdbus-c++-dev libnl-route-3-dev
#
# 3. Remove llvm 16 toolchain packages to avoid conflicts with llvm 17 toolchain.
# sudo apt-get remove -y --purge clang-16* lldb-16* llvm-16*
Expand Down Expand Up @@ -57,7 +57,8 @@ RUN apt-get update && \
unzip \
zip \
# hostapd build dependencies.
# libnl-3-dev libssl-dev libnl-genl-3-dev
# libnl-3-200-dbg libnl-3-dev libssl-dev libnl-genl-3-dev
libnl-3-200-dbg \
libnl-3-dev \
libnl-genl-3-dev \
libssl-dev \
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ include(GNUInstallDirs)
include(grpc)
include(protoc)

# Enable verbose output until project is bootstrapped.
set(CMAKE_VERBOSE_MAKEFILE ON)
# Enable to debug CMake issues.
set(CMAKE_VERBOSE_MAKEFILE OFF CACHE BOOL "Verbose Makefile Generation")

# Pull in external dependencies.
# Look for protobuf-config.cmake.
Expand Down
10 changes: 4 additions & 6 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"cacheVariables": {
"CMAKE_CXX_COMPILER": "/usr/bin/clang++-17",
"CMAKE_C_COMPILER": "/usr/bin/clang-17",
"CMAKE_GENERATOR": "Ninja"
"CMAKE_GENERATOR": "Ninja Multi-Config"
}
},
{
Expand Down Expand Up @@ -106,10 +106,7 @@
"os-linux",
"linux-base",
"release-base"
],
"cacheVariables": {
"CMAKE_GENERATOR": "Ninja Multi-Config"
}
]
},
{
"name": "release-windows",
Expand All @@ -123,7 +120,8 @@
"buildPresets": [
{
"name": "dev-linux",
"configurePreset": "dev-linux"
"configurePreset": "dev-linux",
"configuration": "Debug"
},
{
"name": "dev-windows",
Expand Down
1 change: 1 addition & 0 deletions src/common/shared/notstd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target_sources(notstd
FILES
${NOTSTD_PUBLIC_INCLUDE_PREFIX}/Exceptions.hxx
${NOTSTD_PUBLIC_INCLUDE_PREFIX}/Memory.hxx
${NOTSTD_PUBLIC_INCLUDE_PREFIX}/Scope.hxx
${NOTSTD_PUBLIC_INCLUDE_PREFIX}/Utility.hxx
)

Expand Down
129 changes: 129 additions & 0 deletions src/common/shared/notstd/include/notstd/Scope.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#ifndef NOT_STD_SCOPE_HXX
#define NOT_STD_SCOPE_HXX

#include <type_traits>
#include <utility>

namespace notstd
{
namespace details
{
/**
* @brief Executes a given lambda when destroyed.
*
* @tparam TLambda
*/
template <typename TLambda>
class lambda_call
{
public:
lambda_call(const lambda_call&) = delete;
lambda_call&
operator=(const lambda_call&) = delete;
lambda_call&
operator=(lambda_call&& other) = delete;

/**
* @brief Construct a new lambda call object.
*
* @param lambda
*/
explicit lambda_call(TLambda&& lambda) noexcept :
m_lambda(std::move(lambda))
{
static_assert(std::is_same<decltype(lambda()), void>::value, "scope_exit lambdas must not have a return value");
static_assert(!std::is_lvalue_reference<TLambda>::value && !std::is_rvalue_reference<TLambda>::value,
"scope_exit should only be directly used with a lambda");
}

/**
* @brief Construct a new lambda call object.
*
* @param other
*/
lambda_call(lambda_call&& other) noexcept :
m_lambda(std::move(other.m_lambda)),
m_call(other.m_call)
{
other.m_call = false;
}

/**
* @brief Destroy the lambda call object.
*/
~lambda_call() noexcept
{
reset();
}

/**
* @brief Ensures the scope_exit lambda will not be called.
*/
void
release() noexcept
{
m_call = false;
}

/**
* @brief Executes the scope_exit lambda immediately if not yet run; ensures
* it will not run again.
*/
void
reset() noexcept
{
if (m_call) {
m_call = false;
m_lambda();
}
}

/**
* @brief Returns true if the scope_exit lambda is still going to be
* executed.
*
* @return true
* @return false
*/
explicit operator bool() const noexcept
{
return m_call;
}

private:
TLambda m_lambda;
bool m_call = true;
};
} // namespace details

/**
* @brief Returns an object that executes the given lambda when destroyed.
*
* @tparam TLambda
* @param lambda
* @return auto
*/
template <typename TLambda>
[[nodiscard]] inline auto
scope_exit(TLambda&& lambda) noexcept
{
return details::lambda_call<TLambda>(std::forward<TLambda>(lambda));
}

/**
* @brief Name alias for scope_exit.
*
* @tparam TLambda
* @param lambda
* @return auto
*/
template <typename TLambda>
[[nodiscard]] inline auto
ScopeExit(TLambda&& lambda) noexcept
{
return scope_exit(std::forward<TLambda>(lambda));
}

} // namespace notstd

#endif // NOT_STD_SCOPE_HXX
2 changes: 2 additions & 0 deletions src/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

add_subdirectory(external)
add_subdirectory(libnl-helpers)
add_subdirectory(server)
add_subdirectory(tools)
add_subdirectory(wifi)
add_subdirectory(wpa-controller)
1 change: 1 addition & 0 deletions src/linux/external/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@

add_subdirectory(hostap)
add_subdirectory(libnl)
29 changes: 29 additions & 0 deletions src/linux/external/libnl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

# Requires that libnl development package is installed (libnl-3-dev on ubuntu).
find_path(LIBNL_INCLUDE_DIR netlink/netlink.h
PATHS
/usr/include/libnl3
/usr/local/include/libnl3
REQUIRED
)

# libnl core
find_library(LIBNL_STATIC NAMES libnl-3.a REQUIRED)
add_library(nl STATIC IMPORTED GLOBAL)
set_target_properties(nl PROPERTIES IMPORTED_LOCATION ${LIBNL_STATIC})
set_target_properties(nl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBNL_INCLUDE_DIR})
target_include_directories(nl INTERFACE ${LIBNL_INCLUDE_DIR})

# libnl-genl
find_library(LIBNL_GENL_STATIC NAMES libnl-genl-3.a REQUIRED)
add_library(nl-genl STATIC IMPORTED GLOBAL)
set_target_properties(nl-genl PROPERTIES IMPORTED_LOCATION ${LIBNL_GENL_STATIC})
set_target_properties(nl-genl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBNL_INCLUDE_DIR})
target_include_directories(nl-genl INTERFACE ${LIBNL_INCLUDE_DIR})

# libnl-route
find_library(LIBNL_ROUTE_STATIC NAMES libnl-route-3.a REQUIRED)
add_library(nl-route STATIC IMPORTED GLOBAL)
set_target_properties(nl-route PROPERTIES IMPORTED_LOCATION ${LIBNL_ROUTE_STATIC})
set_target_properties(nl-route PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBNL_INCLUDE_DIR})
target_include_directories(nl-route INTERFACE ${LIBNL_INCLUDE_DIR})
30 changes: 30 additions & 0 deletions src/linux/libnl-helpers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

add_library(libnl-helpers STATIC "")

set(LIBNL_HELPERS_PUBLIC_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/include)
set(LIBNL_HELPERS_PUBLIC_INCLUDE_SUFFIX microsoft/net/netlink)
set(LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX ${LIBNL_HELPERS_PUBLIC_INCLUDE}/${LIBNL_HELPERS_PUBLIC_INCLUDE_SUFFIX})

target_sources(libnl-helpers
PRIVATE
NetlinkSocket.cxx
NetlinkMessage.cxx
PUBLIC
FILE_SET HEADERS
BASE_DIRS ${LIBNL_HELPERS_PUBLIC_INCLUDE}
FILES
${LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX}/NetlinkMessage.hxx
${LIBNL_HELPERS_PUBLIC_INCLUDE_PREFIX}/NetlinkSocket.hxx
)

target_link_libraries(libnl-helpers
PUBLIC
nl
)

install(
TARGETS libnl-helpers
EXPORT ${PROJECT_NAME}
FILE_SET HEADERS
PUBLIC_HEADER DESTINATION "${NETREMOTE_DIR_INSTALL_PUBLIC_HEADER_BASE}/${LIBNL_HELPERS_PUBLIC_INCLUDE_SUFFIX}"
)
60 changes: 60 additions & 0 deletions src/linux/libnl-helpers/NetlinkMessage.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

#include <microsoft/net/netlink/NetlinkMessage.hxx>

using namespace Microsoft::Net::Netlink;

NetlinkMessage::NetlinkMessage(struct nl_msg* message) :
Message(message)
{
}

NetlinkMessage::NetlinkMessage(NetlinkMessage&& other) :
Message(other.Message)
{
other.Message = nullptr;
}

NetlinkMessage&
NetlinkMessage::operator=(NetlinkMessage&& other)
{
if (this != &other) {
Reset();
Message = other.Message;
other.Message = nullptr;
}

return *this;
}

NetlinkMessage::~NetlinkMessage()
{
Reset();
}

void
NetlinkMessage::Reset()
{
if (Message != nullptr) {
nlmsg_free(Message);
Message = nullptr;
}
}

struct nl_msg*
NetlinkMessage::Release() noexcept
{
auto message = Message;
Message = nullptr;
return message;
}

NetlinkMessage::operator struct nl_msg *() const noexcept
{
return Message;
}

struct nlmsghdr*
NetlinkMessage::Header() const noexcept
{
return nlmsg_hdr(Message);
}
62 changes: 62 additions & 0 deletions src/linux/libnl-helpers/NetlinkSocket.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

#include <microsoft/net/netlink/NetlinkSocket.hxx>

using namespace Microsoft::Net::Netlink;

/* static */
NetlinkSocket
NetlinkSocket::Allocate()
{
auto socket = nl_socket_alloc();
return NetlinkSocket{ socket };
}

NetlinkSocket::NetlinkSocket(struct nl_sock* socket) :
Socket(socket)
{
}

NetlinkSocket::NetlinkSocket(NetlinkSocket&& other) :
Socket(other.Socket)
{
other.Socket = nullptr;
}

NetlinkSocket&
NetlinkSocket::operator=(NetlinkSocket&& other)
{
if (this != &other) {
Reset();
Socket = other.Socket;
other.Socket = nullptr;
}

return *this;
}

NetlinkSocket::~NetlinkSocket()
{
Reset();
}

void
NetlinkSocket::Reset()
{
if (Socket != nullptr) {
nl_socket_free(Socket);
Socket = nullptr;
}
}

struct nl_sock*
NetlinkSocket::Release() noexcept
{
auto socket = Socket;
Socket = nullptr;
return socket;
}

NetlinkSocket::operator struct nl_sock *() const noexcept
{
return Socket;
}
Loading
Loading