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);