From e5a2520069c21a533554f493db11af072eb56071 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Tue, 17 Nov 2020 16:17:13 +0100 Subject: [PATCH] platform: Add a wifi_get_station utility Merge nm_platform_wifi_get_bssid, nm_platform_wifi_get_quality, nm_platform_wifi_get_rate into one utility, nm_platform_wifi_get_station that uses the single NL80211_CMD_GET_STATION command dump when the nl80211 driver is used. With wext each function mapped to one ioctl while with nl80211 all three can be obtained with one netlink command. The new function should use the minimum number of calls with either driver. --- src/platform/nm-linux-platform.c | 12 +++++++++ src/platform/nm-platform.c | 14 ++++++++++ src/platform/nm-platform.h | 10 +++++++ src/platform/wifi/nm-wifi-utils-nl80211.c | 28 +++++++++++++++++++ src/platform/wifi/nm-wifi-utils-private.h | 12 +++++++++ src/platform/wifi/nm-wifi-utils.c | 33 +++++++++++++++++++++++ src/platform/wifi/nm-wifi-utils.h | 12 +++++++++ 7 files changed, 121 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index b377c85e7a..5f8ca938ae 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -8309,6 +8309,17 @@ wifi_get_rate(NMPlatform *platform, int ifindex) return nm_wifi_utils_get_rate(wifi_data); } +static gboolean +wifi_get_station(NMPlatform *platform, + int ifindex, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate) +{ + WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); + return nm_wifi_utils_get_station(wifi_data, out_bssid, out_quality, out_rate); +} + static NM80211Mode wifi_get_mode(NMPlatform *platform, int ifindex) { @@ -9673,6 +9684,7 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->wifi_get_frequency = wifi_get_frequency; platform_class->wifi_get_quality = wifi_get_quality; platform_class->wifi_get_rate = wifi_get_rate; + platform_class->wifi_get_station = wifi_get_station; platform_class->wifi_get_mode = wifi_get_mode; platform_class->wifi_set_mode = wifi_set_mode; platform_class->wifi_set_powersave = wifi_set_powersave; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index c843ad91fe..666b8dfc18 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3091,6 +3091,20 @@ nm_platform_wifi_get_rate(NMPlatform *self, int ifindex) return klass->wifi_get_rate(self, ifindex); } +gboolean +nm_platform_wifi_get_station(NMPlatform *self, + int ifindex, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate) +{ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return klass->wifi_get_station(self, ifindex, out_bssid, out_quality, out_rate); +} + NM80211Mode nm_platform_wifi_get_mode(NMPlatform *self, int ifindex) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 8a0ead61d7..60571b8b7c 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1182,6 +1182,11 @@ typedef struct { gboolean (*wifi_get_capabilities)(NMPlatform * self, int ifindex, NMDeviceWifiCapabilities *caps); + gboolean (*wifi_get_station)(NMPlatform *self, + int ifindex, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate); gboolean (*wifi_get_bssid)(NMPlatform *self, int ifindex, guint8 *bssid); guint32 (*wifi_get_frequency)(NMPlatform *self, int ifindex); int (*wifi_get_quality)(NMPlatform *self, int ifindex); @@ -1966,6 +1971,11 @@ gboolean nm_platform_wifi_get_bssid(NMPlatform *self, int ifindex, guint8 *bs guint32 nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex); int nm_platform_wifi_get_quality(NMPlatform *self, int ifindex); guint32 nm_platform_wifi_get_rate(NMPlatform *self, int ifindex); +gboolean nm_platform_wifi_get_station(NMPlatform *self, + int ifindex, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate); NM80211Mode nm_platform_wifi_get_mode(NMPlatform *self, int ifindex); void nm_platform_wifi_set_mode(NMPlatform *self, int ifindex, NM80211Mode mode); void nm_platform_wifi_set_powersave(NMPlatform *self, int ifindex, guint32 powersave); diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c index 841f621e7c..1299165cf4 100644 --- a/src/platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/platform/wifi/nm-wifi-utils-nl80211.c @@ -545,6 +545,33 @@ wifi_nl80211_get_qual(NMWifiUtils *data) return self->sta_info.signal; } +static gboolean +wifi_nl80211_get_station(NMWifiUtils *data, guint8 *out_bssid, int *out_quality, guint32 *out_rate) +{ + NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; + nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl80211_station_info sta_info = {}; + + msg = nl80211_alloc_msg(self, NL80211_CMD_GET_STATION, NLM_F_DUMP); + + nl80211_send_and_recv(self, msg, nl80211_station_dump_handler, &sta_info); + + if (!sta_info.valid || (out_quality && !sta_info.signal_valid) + || (out_rate && !sta_info.txrate_valid)) + return FALSE; + + if (out_bssid) + memcpy(out_bssid, sta_info.bssid, ETH_ALEN); + + if (out_quality) + *out_quality = sta_info.signal; + + if (out_rate) + *out_rate = sta_info.txrate; + + return TRUE; +} + static gboolean wifi_nl80211_indicate_addressing_running(NMWifiUtils *data, gboolean running) { @@ -860,6 +887,7 @@ nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass) wifi_utils_class->get_bssid = wifi_nl80211_get_bssid; wifi_utils_class->get_rate = wifi_nl80211_get_rate; wifi_utils_class->get_qual = wifi_nl80211_get_qual; + wifi_utils_class->get_station = wifi_nl80211_get_station; wifi_utils_class->indicate_addressing_running = wifi_nl80211_indicate_addressing_running; wifi_utils_class->get_mesh_channel = wifi_nl80211_get_mesh_channel; wifi_utils_class->set_mesh_channel = wifi_nl80211_set_mesh_channel; diff --git a/src/platform/wifi/nm-wifi-utils-private.h b/src/platform/wifi/nm-wifi-utils-private.h index 1a5303a668..f175523b87 100644 --- a/src/platform/wifi/nm-wifi-utils-private.h +++ b/src/platform/wifi/nm-wifi-utils-private.h @@ -41,6 +41,18 @@ typedef struct { */ int (*get_qual)(NMWifiUtils *data); + /* + * @out_bssid: must be NULL or an ETH_ALEN-byte buffer + * @out_quality: receives signal strength percentage 0 - 100% for the current BSSID, if not NULL + * @out_rate: receives current bitrate in Kbps if not NULL + * + * Returns %TRUE on succcess, %FALSE on errors or if not associated. + */ + gboolean (*get_station)(NMWifiUtils *data, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate); + /* OLPC Mesh-only functions */ guint32 (*get_mesh_channel)(NMWifiUtils *data); diff --git a/src/platform/wifi/nm-wifi-utils.c b/src/platform/wifi/nm-wifi-utils.c index 3f9d3a48f5..eeed6cfdda 100644 --- a/src/platform/wifi/nm-wifi-utils.c +++ b/src/platform/wifi/nm-wifi-utils.c @@ -155,6 +155,39 @@ nm_wifi_utils_get_qual(NMWifiUtils *data) return NM_WIFI_UTILS_GET_CLASS(data)->get_qual(data); } +gboolean +nm_wifi_utils_get_station(NMWifiUtils *data, guint8 *out_bssid, int *out_quality, guint32 *out_rate) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail(data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS(data); + + if (klass->get_station != NULL) + return klass->get_station(data, out_bssid, out_quality, out_rate); + + if (out_bssid) { + memset(out_bssid, 0, ETH_ALEN); + if (!klass->get_bssid(data, out_bssid)) + return FALSE; + } + + if (out_quality) { + *out_quality = klass->get_qual(data); + if (*out_quality < 0) + return FALSE; + } + + if (out_rate) { + *out_rate = klass->get_rate(data); + if (*out_rate == 0) + return FALSE; + } + + return TRUE; +} + gboolean nm_wifi_utils_is_wifi(int dirfd, const char *ifname) { diff --git a/src/platform/wifi/nm-wifi-utils.h b/src/platform/wifi/nm-wifi-utils.h index d1df2fb822..2b7c9f1a9b 100644 --- a/src/platform/wifi/nm-wifi-utils.h +++ b/src/platform/wifi/nm-wifi-utils.h @@ -52,6 +52,18 @@ guint32 nm_wifi_utils_get_rate(NMWifiUtils *data); /* Returns quality 0 - 100% on success, or -1 on error */ int nm_wifi_utils_get_qual(NMWifiUtils *data); +/* + * @out_bssid: must be NULL or an ETH_ALEN-byte buffer + * @out_quality: receives signal quality in 0 - 100% range if not NULL + * @out_rate: receives current bitrate in Kbps if not NULL + * + * Returns %TRUE on succcess. + */ +gboolean nm_wifi_utils_get_station(NMWifiUtils *data, + guint8 * out_bssid, + int * out_quality, + guint32 * out_rate); + /* Tells the driver DHCP or SLAAC is running */ gboolean nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running);