Skip to content

Commit

Permalink
Merge pull request #85 from microsoft/apdiscoveryagentlinux
Browse files Browse the repository at this point in the history
Implement access point discovery operations for Linux using netlink
  • Loading branch information
abeltrano authored Dec 30, 2023
2 parents d44ddb1 + 12b8c72 commit cda9454
Show file tree
Hide file tree
Showing 24 changed files with 1,269 additions and 10 deletions.
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

0 comments on commit cda9454

Please sign in to comment.