mirror of
https://github.com/polybar/polybar.git
synced 2024-11-18 13:55:11 -05:00
feat(net): Add nl80211 support (#1009)
This patch enables support for nl80211. In case the libnl-genl-3.0 library isn't found, it will fall back to Wext instead. The library to use can also be manually set with the CMake option WITH_LIBNL. The Wireless-Extensions (WE or Wext) are deprecated and long replaced by cfg80211. Although Wext isn't used by WiFi drivers anymore, CFG80211_WEXT allows old tools to communicate with modern drivers by providing a wrapper API.
This commit is contained in:
parent
d43a4a8d9d
commit
3afc341c7b
10 changed files with 448 additions and 149 deletions
|
@ -106,7 +106,7 @@ A compiler with C++14 support ([clang-3.4+](http://llvm.org/releases/download.ht
|
|||
- jsoncpp *required by `internal/i3`*
|
||||
- libmpdclient *required by `internal/mpd`*
|
||||
- libcurl *required by `internal/github`*
|
||||
- wireless_tools *required by `internal/network`*
|
||||
- libnl-genl or wireless_tools *required by `internal/network`*
|
||||
|
||||
Find a more complete list on the [dedicated wiki page](https://github.com/jaagr/polybar/wiki/Compiling).
|
||||
|
||||
|
|
16
build.sh
16
build.sh
|
@ -38,21 +38,21 @@ function main
|
|||
|
||||
msg "Setting build options"
|
||||
|
||||
read -r -p "$(msg "Use GCC even if Clang is installed -------------------------------- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Use GCC even if Clang is installed ----------------------------- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && try_to_use_clang="ON"
|
||||
read -r -p "$(msg "Include support for \"internal/i3\" (requires i3) ------------------- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/i3\" (requires i3) ---------------- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_i3="OFF"
|
||||
read -r -p "$(msg "Include support for \"internal/alsa\" (requires alsalib) ------------ [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/alsa\" (requires alsalib) --------- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_alsa="OFF"
|
||||
read -r -p "$(msg "Include support for \"internal/pulseaudio\" (requires libpulse) ----- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/pulseaudio\" (requires libpulse) -- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_pulseaudio="OFF"
|
||||
read -r -p "$(msg "Include support for \"internal/network\" (requires wireless_tools) -- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/network\" (requires libnl/libiw) -- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_network="OFF"
|
||||
read -r -p "$(msg "Include support for \"internal/mpd\" (requires libmpdclient) -------- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/mpd\" (requires libmpdclient) ----- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_mpd="OFF"
|
||||
read -r -p "$(msg "Include support for \"internal/github\" (requires libcurl) ---------- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Include support for \"internal/github\" (requires libcurl) ------- [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && enable_curl="OFF"
|
||||
read -r -p "$(msg "Build \"polybar-msg\" used to send ipc messages --------------------- [y/N]: ")" -n 1 p && echo
|
||||
read -r -p "$(msg "Build \"polybar-msg\" used to send ipc messages ------------------ [y/N]: ")" -n 1 p && echo
|
||||
[[ "${p^^}" != "Y" ]] && build_ipc_msg="OFF"
|
||||
|
||||
local cxx="c++"
|
||||
|
|
|
@ -6,7 +6,12 @@ checklib(ENABLE_ALSA "pkg-config" alsa)
|
|||
checklib(ENABLE_CURL "pkg-config" libcurl)
|
||||
checklib(ENABLE_I3 "binary" i3)
|
||||
checklib(ENABLE_MPD "pkg-config" libmpdclient)
|
||||
checklib(ENABLE_NETWORK "cmake" Libiw)
|
||||
checklib(WITH_LIBNL "pkg-config" libnl-genl-3.0)
|
||||
if(WITH_LIBNL)
|
||||
checklib(ENABLE_NETWORK "pkg-config" libnl-genl-3.0)
|
||||
else()
|
||||
checklib(ENABLE_NETWORK "cmake" Libiw)
|
||||
endif()
|
||||
checklib(ENABLE_PULSEAUDIO "pkg-config" libpulse)
|
||||
checklib(ENABLE_PULSEAUDIO "binary" pulseaudio)
|
||||
checklib(WITH_XKB "pkg-config" xcb-xkb)
|
||||
|
@ -28,6 +33,7 @@ option(ENABLE_ALSA "Enable alsa support" ON)
|
|||
option(ENABLE_CURL "Enable curl support" ON)
|
||||
option(ENABLE_I3 "Enable i3 support" ON)
|
||||
option(ENABLE_MPD "Enable mpd support" ON)
|
||||
option(WITH_LIBNL "Use netlink interface for wireless" ON)
|
||||
option(ENABLE_NETWORK "Enable network support" ON)
|
||||
option(ENABLE_XKEYBOARD "Enable xkeyboard support" ON)
|
||||
option(ENABLE_PULSEAUDIO "Enable PulseAudio support" ON)
|
||||
|
|
|
@ -10,7 +10,11 @@ querylib(TRUE "pkg-config" cairo-fc libs dirs)
|
|||
querylib(ENABLE_ALSA "pkg-config" alsa libs dirs)
|
||||
querylib(ENABLE_CURL "pkg-config" libcurl libs dirs)
|
||||
querylib(ENABLE_MPD "pkg-config" libmpdclient libs dirs)
|
||||
querylib(ENABLE_NETWORK "cmake" Libiw libs dirs)
|
||||
if(WITH_LIBNL)
|
||||
querylib(ENABLE_NETWORK "pkg-config" libnl-genl-3.0 libs dirs)
|
||||
else()
|
||||
querylib(ENABLE_NETWORK "cmake" Libiw libs dirs)
|
||||
endif()
|
||||
querylib(ENABLE_PULSEAUDIO "pkg-config" libpulse libs dirs)
|
||||
|
||||
querylib(WITH_XCOMPOSITE "pkg-config" xcb-composite libs dirs)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <iwlib.h>
|
||||
|
||||
#ifdef inline
|
||||
#undef inline
|
||||
|
@ -17,6 +16,15 @@
|
|||
#include "components/logger.hpp"
|
||||
#include "utils/math.hpp"
|
||||
|
||||
#if WITH_LIBNL
|
||||
#include <net/if.h>
|
||||
|
||||
struct nl_msg;
|
||||
struct nlattr;
|
||||
#else
|
||||
#include <iwlib.h>
|
||||
#endif
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
class file_descriptor;
|
||||
|
@ -103,6 +111,39 @@ namespace net {
|
|||
};
|
||||
|
||||
// }}}
|
||||
|
||||
#if WITH_LIBNL
|
||||
// class : wireless_network {{{
|
||||
|
||||
class wireless_network : public network {
|
||||
public:
|
||||
wireless_network(string interface) : network(interface), m_ifid(if_nametoindex(interface.c_str())){};
|
||||
|
||||
bool query(bool accumulate = false) override;
|
||||
bool connected() const override;
|
||||
string essid() const;
|
||||
int signal() const;
|
||||
int quality() const;
|
||||
|
||||
protected:
|
||||
static int scan_cb(struct nl_msg* msg, void* instance);
|
||||
|
||||
bool associated_or_joined(struct nlattr** bss);
|
||||
void parse_essid(struct nlattr** bss);
|
||||
void parse_frequency(struct nlattr** bss);
|
||||
void parse_quality(struct nlattr** bss);
|
||||
void parse_signal(struct nlattr** bss);
|
||||
|
||||
private:
|
||||
unsigned int m_ifid{};
|
||||
string m_essid{};
|
||||
int m_frequency{};
|
||||
quality_range m_signalstrength{};
|
||||
quality_range m_linkquality{};
|
||||
};
|
||||
|
||||
// }}}
|
||||
#else
|
||||
// class : wireless_network {{{
|
||||
|
||||
class wireless_network : public network {
|
||||
|
@ -128,9 +169,10 @@ namespace net {
|
|||
};
|
||||
|
||||
// }}}
|
||||
#endif
|
||||
|
||||
using wireless_t = unique_ptr<wireless_network>;
|
||||
using wired_t = unique_ptr<wired_network>;
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#cmakedefine01 ENABLE_ALSA
|
||||
#cmakedefine01 ENABLE_MPD
|
||||
#cmakedefine01 ENABLE_NETWORK
|
||||
#cmakedefine01 WITH_LIBNL
|
||||
#cmakedefine01 ENABLE_I3
|
||||
#cmakedefine01 ENABLE_CURL
|
||||
#cmakedefine01 ENABLE_PULSEAUDIO
|
||||
|
|
|
@ -23,6 +23,13 @@ endif()
|
|||
if(NOT ENABLE_NETWORK)
|
||||
list(REMOVE_ITEM files modules/network.cpp)
|
||||
list(REMOVE_ITEM files adapters/net.cpp)
|
||||
list(REMOVE_ITEM files adapters/net_iw.cpp)
|
||||
list(REMOVE_ITEM files adapters/net_nl.cpp)
|
||||
endif()
|
||||
if(WITH_LIBNL)
|
||||
list(REMOVE_ITEM files adapters/net_iw.cpp)
|
||||
else()
|
||||
list(REMOVE_ITEM files adapters/net_nl.cpp)
|
||||
endif()
|
||||
if(NOT ENABLE_I3)
|
||||
list(REMOVE_ITEM files modules/i3.cpp)
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
#include "adapters/net.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <climits>
|
||||
#include <csignal>
|
||||
|
||||
#ifdef inline
|
||||
#undef inline
|
||||
|
@ -192,9 +187,9 @@ namespace net {
|
|||
driver.cmd = ETHTOOL_GDRVINFO;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
|
||||
/*
|
||||
* Only copy array size minus one bytes over to ensure there is a
|
||||
* Only copy array size minus one bytes over to ensure there is a
|
||||
* terminating NUL byte (which is guaranteed by memset)
|
||||
*/
|
||||
strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
|
||||
|
@ -306,133 +301,7 @@ namespace net {
|
|||
}
|
||||
|
||||
// }}}
|
||||
// class : wireless_network {{{
|
||||
|
||||
/**
|
||||
* Query the wireless device for information
|
||||
* about the current connection
|
||||
*/
|
||||
bool wireless_network::query(bool accumulate) {
|
||||
if (!network::query(accumulate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto socket_fd = file_util::make_file_descriptor(iw_sockets_open());
|
||||
if (!*socket_fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct iwreq req {};
|
||||
|
||||
if (iw_get_ext(*socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore interfaces in ad-hoc mode
|
||||
if (req.u.mode == IW_MODE_ADHOC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query_essid(*socket_fd);
|
||||
query_quality(*socket_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check current connection state
|
||||
*/
|
||||
bool wireless_network::connected() const {
|
||||
if (!network::test_interface()) {
|
||||
return false;
|
||||
}
|
||||
return !m_essid.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* ESSID reported by last query
|
||||
*/
|
||||
string wireless_network::essid() const {
|
||||
return m_essid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal strength percentage reported by last query
|
||||
*/
|
||||
int wireless_network::signal() const {
|
||||
return m_signalstrength.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Link quality percentage reported by last query
|
||||
*/
|
||||
int wireless_network::quality() const {
|
||||
return m_linkquality.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Query for ESSID
|
||||
*/
|
||||
void wireless_network::query_essid(const int& socket_fd) {
|
||||
char essid[IW_ESSID_MAX_SIZE + 1];
|
||||
|
||||
struct iwreq req {};
|
||||
req.u.essid.pointer = &essid;
|
||||
req.u.essid.length = sizeof(essid);
|
||||
req.u.essid.flags = 0;
|
||||
|
||||
if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
|
||||
m_essid = string{essid};
|
||||
} else {
|
||||
m_essid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query for device driver quality values
|
||||
*/
|
||||
void wireless_network::query_quality(const int& socket_fd) {
|
||||
iwrange range{};
|
||||
iwstats stats{};
|
||||
|
||||
// Fill range
|
||||
if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1) {
|
||||
return;
|
||||
}
|
||||
// Fill stats
|
||||
if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the driver supplies the quality value
|
||||
if (stats.qual.updated & IW_QUAL_QUAL_INVALID) {
|
||||
return;
|
||||
}
|
||||
// Check if the driver supplies the quality level value
|
||||
if (stats.qual.updated & IW_QUAL_LEVEL_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the link quality has been uodated
|
||||
if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
|
||||
m_linkquality.val = stats.qual.qual;
|
||||
m_linkquality.max = range.max_qual.qual;
|
||||
}
|
||||
|
||||
// Check if the signal strength has been uodated
|
||||
if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
|
||||
m_signalstrength.val = stats.qual.level;
|
||||
m_signalstrength.max = range.max_qual.level;
|
||||
|
||||
// Check if the values are defined in dBm
|
||||
if (stats.qual.level > range.max_qual.level) {
|
||||
m_signalstrength.val -= 0x100;
|
||||
m_signalstrength.max = (stats.qual.level - range.max_qual.level) - 0x100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
|
137
src/adapters/net_iw.cpp
Normal file
137
src/adapters/net_iw.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
#include "adapters/net.hpp"
|
||||
|
||||
#include "utils/file.hpp"
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace net {
|
||||
// class : wireless_network {{{
|
||||
|
||||
/**
|
||||
* Query the wireless device for information
|
||||
* about the current connection
|
||||
*/
|
||||
bool wireless_network::query(bool accumulate) {
|
||||
if (!network::query(accumulate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto socket_fd = file_util::make_file_descriptor(iw_sockets_open());
|
||||
if (!*socket_fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct iwreq req {};
|
||||
|
||||
if (iw_get_ext(*socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore interfaces in ad-hoc mode
|
||||
if (req.u.mode == IW_MODE_ADHOC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query_essid(*socket_fd);
|
||||
query_quality(*socket_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check current connection state
|
||||
*/
|
||||
bool wireless_network::connected() const {
|
||||
if (!network::test_interface()) {
|
||||
return false;
|
||||
}
|
||||
return !m_essid.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* ESSID reported by last query
|
||||
*/
|
||||
string wireless_network::essid() const {
|
||||
return m_essid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal strength percentage reported by last query
|
||||
*/
|
||||
int wireless_network::signal() const {
|
||||
return m_signalstrength.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Link quality percentage reported by last query
|
||||
*/
|
||||
int wireless_network::quality() const {
|
||||
return m_linkquality.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Query for ESSID
|
||||
*/
|
||||
void wireless_network::query_essid(const int& socket_fd) {
|
||||
char essid[IW_ESSID_MAX_SIZE + 1];
|
||||
|
||||
struct iwreq req {};
|
||||
req.u.essid.pointer = &essid;
|
||||
req.u.essid.length = sizeof(essid);
|
||||
req.u.essid.flags = 0;
|
||||
|
||||
if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
|
||||
m_essid = string{essid};
|
||||
} else {
|
||||
m_essid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query for device driver quality values
|
||||
*/
|
||||
void wireless_network::query_quality(const int& socket_fd) {
|
||||
iwrange range{};
|
||||
iwstats stats{};
|
||||
|
||||
// Fill range
|
||||
if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1) {
|
||||
return;
|
||||
}
|
||||
// Fill stats
|
||||
if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the driver supplies the quality value
|
||||
if (stats.qual.updated & IW_QUAL_QUAL_INVALID) {
|
||||
return;
|
||||
}
|
||||
// Check if the driver supplies the quality level value
|
||||
if (stats.qual.updated & IW_QUAL_LEVEL_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the link quality has been uodated
|
||||
if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
|
||||
m_linkquality.val = stats.qual.qual;
|
||||
m_linkquality.max = range.max_qual.qual;
|
||||
}
|
||||
|
||||
// Check if the signal strength has been uodated
|
||||
if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
|
||||
m_signalstrength.val = stats.qual.level;
|
||||
m_signalstrength.max = range.max_qual.level;
|
||||
|
||||
// Check if the values are defined in dBm
|
||||
if (stats.qual.level > range.max_qual.level) {
|
||||
m_signalstrength.val -= 0x100;
|
||||
m_signalstrength.max = (stats.qual.level - range.max_qual.level) - 0x100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
} // namespace net
|
||||
|
||||
POLYBAR_NS_END
|
233
src/adapters/net_nl.cpp
Normal file
233
src/adapters/net_nl.cpp
Normal file
|
@ -0,0 +1,233 @@
|
|||
#include "adapters/net.hpp"
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
|
||||
#include "utils/file.hpp"
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace net {
|
||||
// class : wireless_network {{{
|
||||
|
||||
/**
|
||||
* Query the wireless device for information
|
||||
* about the current connection
|
||||
*/
|
||||
bool wireless_network::query(bool accumulate) {
|
||||
if (!network::query(accumulate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nl_sock* sk = nl_socket_alloc();
|
||||
if (sk == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (genl_connect(sk) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int driver_id = genl_ctrl_resolve(sk, "nl80211");
|
||||
if (driver_id < 0) {
|
||||
nl_socket_free(sk);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, scan_cb, this) != 0) {
|
||||
nl_socket_free(sk);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nl_msg* msg = nlmsg_alloc();
|
||||
if (msg == nullptr) {
|
||||
nl_socket_free(sk);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0) == nullptr) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, m_ifid) < 0) {
|
||||
nlmsg_free(msg);
|
||||
nl_socket_free(sk);
|
||||
return false;
|
||||
}
|
||||
|
||||
// nl_send_sync always frees msg
|
||||
if (nl_send_sync(sk, msg) < 0) {
|
||||
nl_socket_free(sk);
|
||||
return false;
|
||||
}
|
||||
|
||||
nl_socket_free(sk);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check current connection state
|
||||
*/
|
||||
bool wireless_network::connected() const {
|
||||
if (!network::test_interface()) {
|
||||
return false;
|
||||
}
|
||||
return !m_essid.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* ESSID reported by last query
|
||||
*/
|
||||
string wireless_network::essid() const {
|
||||
return m_essid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal strength percentage reported by last query
|
||||
*/
|
||||
int wireless_network::signal() const {
|
||||
return m_signalstrength.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Link quality percentage reported by last query
|
||||
*/
|
||||
int wireless_network::quality() const {
|
||||
return m_linkquality.percentage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to parse scan results
|
||||
*/
|
||||
int wireless_network::scan_cb(struct nl_msg* msg, void* instance) {
|
||||
auto wn = static_cast<wireless_network*>(instance);
|
||||
auto gnlh = static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(msg)));
|
||||
struct nlattr* tb[NL80211_ATTR_MAX + 1];
|
||||
struct nlattr* bss[NL80211_BSS_MAX + 1];
|
||||
|
||||
struct nla_policy bss_policy[NL80211_BSS_MAX + 1]{};
|
||||
bss_policy[NL80211_BSS_TSF].type = NLA_U64;
|
||||
bss_policy[NL80211_BSS_FREQUENCY].type = NLA_U32;
|
||||
bss_policy[NL80211_BSS_BSSID].type = NLA_UNSPEC;
|
||||
bss_policy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
|
||||
bss_policy[NL80211_BSS_CAPABILITY].type = NLA_U16;
|
||||
bss_policy[NL80211_BSS_INFORMATION_ELEMENTS].type = NLA_UNSPEC;
|
||||
bss_policy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
|
||||
bss_policy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;
|
||||
bss_policy[NL80211_BSS_STATUS].type = NLA_U32;
|
||||
|
||||
if (nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), nullptr) < 0) {
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
if (tb[NL80211_ATTR_BSS] == nullptr) {
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy) != 0) {
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
if (!wn->associated_or_joined(bss)) {
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
wn->parse_essid(bss);
|
||||
wn->parse_frequency(bss);
|
||||
wn->parse_signal(bss);
|
||||
wn->parse_quality(bss);
|
||||
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a connection to a AP
|
||||
*/
|
||||
bool wireless_network::associated_or_joined(struct nlattr** bss) {
|
||||
if (bss[NL80211_BSS_STATUS] == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto status = nla_get_u32(bss[NL80211_BSS_STATUS]);
|
||||
|
||||
switch (status) {
|
||||
case NL80211_BSS_STATUS_ASSOCIATED:
|
||||
case NL80211_BSS_STATUS_IBSS_JOINED:
|
||||
case NL80211_BSS_STATUS_AUTHENTICATED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ESSID
|
||||
*/
|
||||
void wireless_network::parse_essid(struct nlattr** bss) {
|
||||
m_essid.clear();
|
||||
|
||||
if (bss[NL80211_BSS_INFORMATION_ELEMENTS] != nullptr) {
|
||||
// Information Element ID from ieee80211.h
|
||||
#define WLAN_EID_SSID 0
|
||||
|
||||
auto ies = static_cast<char*>(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
|
||||
auto ies_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
|
||||
const auto hdr_len = 2;
|
||||
|
||||
while (ies_len > hdr_len && ies[0] != WLAN_EID_SSID) {
|
||||
ies_len -= ies[1] + hdr_len;
|
||||
ies += ies[1] + hdr_len;
|
||||
}
|
||||
|
||||
if (ies_len > hdr_len && ies_len > ies[1] + hdr_len) {
|
||||
auto essid_begin = ies + hdr_len;
|
||||
auto essid_end = essid_begin + ies[1];
|
||||
|
||||
// Only use printable characters of the current locale
|
||||
std::copy_if(essid_begin, essid_end, std::back_inserter(m_essid),
|
||||
[](char c) { return isprint(static_cast<unsigned char>(c)); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency
|
||||
*/
|
||||
void wireless_network::parse_frequency(struct nlattr** bss) {
|
||||
if (bss[NL80211_BSS_FREQUENCY] != nullptr) {
|
||||
// in MHz
|
||||
m_frequency = static_cast<int>(nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set device driver quality values
|
||||
*/
|
||||
void wireless_network::parse_quality(struct nlattr** bss) {
|
||||
if (bss[NL80211_BSS_SIGNAL_UNSPEC] != nullptr) {
|
||||
// Signal strength in unspecified units, scaled to 0..100 (u8)
|
||||
m_linkquality.val = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
|
||||
m_linkquality.max = 100;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the signalstrength
|
||||
*/
|
||||
void wireless_network::parse_signal(struct nlattr** bss) {
|
||||
if (bss[NL80211_BSS_SIGNAL_MBM] != nullptr) {
|
||||
// signalstrength in dBm
|
||||
int signalstrength = static_cast<int>(nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM])) / 100;
|
||||
|
||||
// WiFi-hardware usually operates in the range -90 to -20dBm.
|
||||
const int hardware_max = -20;
|
||||
const int hardware_min = -90;
|
||||
signalstrength = std::max(hardware_min, std::min(signalstrength, hardware_max));
|
||||
|
||||
// Shift for positive values
|
||||
m_signalstrength.val = signalstrength - hardware_min;
|
||||
m_signalstrength.max = hardware_max - hardware_min;
|
||||
}
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
POLYBAR_NS_END
|
Loading…
Reference in a new issue