summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-10-24 11:12:39 +0900
committerGitHub <noreply@github.com>2019-10-24 11:12:39 +0900
commit6f3ad94590e3d6092f008b8b1443e12af84534e8 (patch)
treed2cfdf09444d26f48920b1d813a66d49b713f7f4
parent14cd12b3d50f21cb9be7e27785142c6c321fac39 (diff)
parent8d07de25342b754f50073f2257f7329ec587d480 (diff)
downloadsystemd-6f3ad94590e3d6092f008b8b1443e12af84534e8.tar.gz
Merge pull request #13828 from keszybz/networkctl-print-wlan
networkctl support for ssid and bssid
-rw-r--r--src/network/networkctl.c146
-rw-r--r--src/network/networkd-wifi.c107
-rw-r--r--src/shared/meson.build2
-rw-r--r--src/shared/wifi-util.c90
-rw-r--r--src/shared/wifi-util.h8
5 files changed, 222 insertions, 131 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 5e8dce0b73..60d6a3f75f 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -21,6 +21,7 @@
#include "bus-error.h"
#include "bus-util.h"
#include "device-util.h"
+#include "escape.h"
#include "ether-addr-util.h"
#include "ethtool-util.h"
#include "fd-util.h"
@@ -46,10 +47,14 @@
#include "strxcpyx.h"
#include "terminal-util.h"
#include "verbs.h"
+#include "wifi-util.h"
/* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
#define NETDEV_KIND_MAX 64
+/* use 128 kB for receive socket kernel queue, we shouldn't need more here */
+#define RCVBUF_SIZE (128*1024)
+
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
static bool arg_all = false;
@@ -76,11 +81,12 @@ static char *link_get_type_string(unsigned short iftype, sd_device *d) {
return p;
}
-static void operational_state_to_color(const char *state, const char **on, const char **off) {
+static void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) {
assert(on);
assert(off);
- if (STRPTR_IN_SET(state, "routable", "enslaved")) {
+ if (STRPTR_IN_SET(state, "routable", "enslaved") ||
+ (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) {
*on = ansi_highlight_green();
*off = ansi_normal();
} else if (streq_ptr(state, "degraded")) {
@@ -124,6 +130,7 @@ typedef struct VxLanInfo {
typedef struct LinkInfo {
char name[IFNAMSIZ+1];
char netdev_kind[NETDEV_KIND_MAX];
+ sd_device *sd_device;
int ifindex;
unsigned short iftype;
struct ether_addr mac_address;
@@ -159,6 +166,10 @@ typedef struct LinkInfo {
Duplex duplex;
NetDevPort port;
+ /* wlan info */
+ char *ssid;
+ struct ether_addr bssid;
+
bool has_mac_address:1;
bool has_tx_queues:1;
bool has_rx_queues:1;
@@ -166,12 +177,25 @@ typedef struct LinkInfo {
bool has_stats:1;
bool has_bitrates:1;
bool has_ethtool_link_info:1;
+ bool has_wlan_link_info:1;
+
+ bool needs_freeing:1;
} LinkInfo;
static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
return CMP(a->ifindex, b->ifindex);
}
+static const LinkInfo* link_info_array_free(LinkInfo *array) {
+ for (unsigned i = 0; array && array[i].needs_freeing; i++) {
+ sd_device_unref(array[i].sd_device);
+ free(array[i].ssid);
+ }
+
+ return mfree(array);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(LinkInfo*, link_info_array_free);
+
static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
const char *received_kind;
int r;
@@ -348,9 +372,47 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
return 0;
}
+static void acquire_ether_link_info(int *fd, LinkInfo *link) {
+ if (ethtool_get_link_info(fd, link->name,
+ &link->autonegotiation,
+ &link->speed,
+ &link->duplex,
+ &link->port) >= 0)
+ link->has_ethtool_link_info = true;
+}
+
+static void acquire_wlan_link_info(LinkInfo *link) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
+ const char *type = NULL;
+ int r, k;
+
+ if (link->sd_device)
+ (void) sd_device_get_devtype(link->sd_device, &type);
+ if (!streq_ptr(type, "wlan"))
+ return;
+
+ r = sd_genl_socket_open(&genl);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to open generic netlink socket: %m");
+ return;
+ }
+
+ (void) sd_netlink_inc_rcvbuf(genl, RCVBUF_SIZE);
+
+ r = wifi_get_ssid(genl, link->ifindex, &link->ssid);
+ if (r < 0)
+ log_debug_errno(r, "%s: failed to query ssid: %m", link->name);
+
+ k = wifi_get_bssid(genl, link->ifindex, &link->bssid);
+ if (k < 0)
+ log_debug_errno(k, "%s: failed to query bssid: %m", link->name);
+
+ link->has_wlan_link_info = r > 0 || k > 0;
+}
+
static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
+ _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
_cleanup_close_ int fd = -1;
size_t allocated = 0, c = 0, j;
sd_netlink_message *i;
@@ -372,7 +434,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
return log_error_errno(r, "Failed to enumerate links: %m");
for (i = reply; i; i = sd_netlink_message_next(i)) {
- if (!GREEDY_REALLOC0(links, allocated, c+1))
+ if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */
return -ENOMEM;
r = decode_link(i, links + c, patterns);
@@ -381,11 +443,14 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
if (r == 0)
continue;
- r = ethtool_get_link_info(&fd, links[c].name,
- &links[c].autonegotiation, &links[c].speed,
- &links[c].duplex, &links[c].port);
- if (r >= 0)
- links[c].has_ethtool_link_info = true;
+ links[c].needs_freeing = true;
+
+ char devid[2 + DECIMAL_STR_MAX(int)];
+ xsprintf(devid, "n%i", links[c].ifindex);
+ (void) sd_device_new_from_device_id(&links[c].sd_device, devid);
+
+ acquire_ether_link_info(&fd, &links[c]);
+ acquire_wlan_link_info(&links[c]);
c++;
}
@@ -403,7 +468,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
static int list_links(int argc, char *argv[], void *userdata) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
+ _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
TableCell *cell;
int c, i, r;
@@ -435,24 +500,19 @@ static int list_links(int argc, char *argv[], void *userdata) {
for (i = 0; i < c; i++) {
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
- _cleanup_(sd_device_unrefp) sd_device *d = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
- char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL;
(void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
- operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
+ operational_state_to_color(links[i].name, operational_state, &on_color_operational, &off_color_operational);
r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
setup_state = strdup("unmanaged");
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- xsprintf(devid, "n%i", links[i].ifindex);
- (void) sd_device_new_from_device_id(&d, devid);
-
- t = link_get_type_string(links[i].iftype, d);
+ t = link_get_type_string(links[i].iftype, links[i].sd_device);
r = table_add_many(table,
TABLE_INT, links[i].ifindex,
@@ -998,8 +1058,6 @@ static int link_status_one(
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- _cleanup_(sd_device_unrefp) sd_device *d = NULL;
- char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
@@ -1013,7 +1071,7 @@ static int link_status_one(
assert(info);
(void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
- operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
+ operational_state_to_color(info->name, operational_state, &on_color_operational, &off_color_operational);
r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
@@ -1025,23 +1083,19 @@ static int link_status_one(
(void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
(void) sd_network_link_get_ntp(info->ifindex, &ntp);
- xsprintf(devid, "n%i", info->ifindex);
-
- (void) sd_device_new_from_device_id(&d, devid);
+ if (info->sd_device) {
+ (void) sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE", &link);
+ (void) sd_device_get_property_value(info->sd_device, "ID_NET_DRIVER", &driver);
+ (void) sd_device_get_property_value(info->sd_device, "ID_PATH", &path);
- if (d) {
- (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
- (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
- (void) sd_device_get_property_value(d, "ID_PATH", &path);
+ if (sd_device_get_property_value(info->sd_device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
+ (void) sd_device_get_property_value(info->sd_device, "ID_VENDOR", &vendor);
- if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
- (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
-
- if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
- (void) sd_device_get_property_value(d, "ID_MODEL", &model);
+ if (sd_device_get_property_value(info->sd_device, "ID_MODEL_FROM_DATABASE", &model) < 0)
+ (void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model);
}
- t = link_get_type_string(info->iftype, d);
+ t = link_get_type_string(info->iftype, info->sd_device);
(void) sd_network_link_get_network_file(info->ifindex, &network);
@@ -1244,6 +1298,26 @@ static int link_status_one(
}
}
+ if (info->has_wlan_link_info) {
+ _cleanup_free_ char *esc = NULL;
+ char buf[ETHER_ADDR_TO_STRING_MAX];
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "WiFi access point:");
+ if (r < 0)
+ return r;
+
+ if (info->ssid)
+ esc = cescape(info->ssid);
+
+ r = table_add_cell_stringf(table, NULL, "%s (%s)",
+ strnull(esc),
+ ether_addr_to_string(&info->bssid, buf));
+ if (r < 0)
+ return r;
+ }
+
if (info->has_bitrates) {
char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
@@ -1368,7 +1442,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
assert(rtnl);
(void) sd_network_get_operational_state(&operational_state);
- operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
+ operational_state_to_color(NULL, operational_state, &on_color_operational, &off_color_operational);
table = table_new("dot", "key", "value");
if (!table)
@@ -1424,7 +1498,7 @@ static int link_status(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
+ _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
int r, c, i;
(void) pager_open(arg_pager_flags);
@@ -1512,7 +1586,7 @@ static void lldp_capabilities_legend(uint16_t x) {
static int link_lldp_status(int argc, char *argv[], void *userdata) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
+ _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
int i, r, c, m = 0;
uint16_t all = 0;
diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c
index 94195d778f..877c742280 100644
--- a/src/network/networkd-wifi.c
+++ b/src/network/networkd-wifi.c
@@ -12,101 +12,9 @@
#include "networkd-manager.h"
#include "networkd-wifi.h"
#include "string-util.h"
-
-static int wifi_get_ssid(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
- _cleanup_free_ char *ssid = NULL;
- sd_genl_family family;
- int r;
-
- r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to create generic netlink message: %m");
-
- r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
-
- r = sd_netlink_call(link->manager->genl, m, 0, &reply);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to request information about wifi interface: %m");
- if (!reply)
- return 0;
-
- r = sd_netlink_message_get_errno(reply);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to get information about wifi interface: %m");
-
- r = sd_genl_message_get_family(link->manager->genl, reply, &family);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to determine genl family: %m");
- if (family != SD_GENL_NL80211) {
- log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family);
- return 0;
- }
-
- r = sd_netlink_message_read_string_strdup(reply, NL80211_ATTR_SSID, &ssid);
- if (r < 0 && r != -ENODATA)
- return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_SSID attribute: %m");
-
- free_and_replace(link->ssid, ssid);
- return r == -ENODATA ? 0 : 1;
-}
-
-static int wifi_get_bssid(Link *link) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
- struct ether_addr mac = {};
- sd_genl_family family;
- int r;
-
- assert(link);
- assert(link->manager);
- assert(link->manager->genl);
-
- r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to create generic netlink message: %m");
-
- r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to set dump flag: %m");
-
- r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
-
- r = sd_netlink_call(link->manager->genl, m, 0, &reply);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to request information about wifi station: %m");
- if (!reply)
- return 0;
-
- r = sd_netlink_message_get_errno(reply);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to get information about wifi station: %m");
-
- r = sd_genl_message_get_family(link->manager->genl, reply, &family);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to determine genl family: %m");
- if (family != SD_GENL_NL80211) {
- log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family);
- return 0;
- }
-
- r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, &mac);
- if (r < 0 && r != -ENODATA)
- return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_MAC attribute: %m");
-
- r = memcmp(&link->bssid, &mac, sizeof(mac));
- if (r == 0)
- return 0;
-
- memcpy(&link->bssid, &mac, sizeof(mac));
- return 1;
-}
+#include "wifi-util.h"
int wifi_get_info(Link *link) {
- char buf[ETHER_ADDR_TO_STRING_MAX];
const char *type;
int r, s;
@@ -124,15 +32,24 @@ int wifi_get_info(Link *link) {
if (!streq(type, "wlan"))
return 0;
- r = wifi_get_ssid(link);
+ _cleanup_free_ char *ssid = NULL;
+ r = wifi_get_ssid(link->manager->genl, link->ifindex, &ssid);
if (r < 0)
return r;
+ if (r > 0 && streq_ptr(link->ssid, ssid))
+ r = 0;
+ free_and_replace(link->ssid, ssid);
- s = wifi_get_bssid(link);
+ struct ether_addr old_bssid = link->bssid;
+ s = wifi_get_bssid(link->manager->genl, link->ifindex, &link->bssid);
if (s < 0)
return s;
+ if (s > 0 && memcmp(&old_bssid, &link->bssid, sizeof old_bssid) == 0)
+ s = 0;
if (r > 0 || s > 0) {
+ char buf[ETHER_ADDR_TO_STRING_MAX];
+
if (link->ssid)
log_link_info(link, "Connected WiFi access point: %s (%s)",
link->ssid, ether_addr_to_string(&link->bssid, buf));
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 40412de433..135f285f4b 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -189,6 +189,8 @@ shared_sources = files('''
watchdog.h
web-util.c
web-util.h
+ wifi-util.c
+ wifi-util.h
xml.c
xml.h
'''.split())
diff --git a/src/shared/wifi-util.c b/src/shared/wifi-util.c
new file mode 100644
index 0000000000..c301a306d3
--- /dev/null
+++ b/src/shared/wifi-util.c
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <net/ethernet.h>
+#include <linux/nl80211.h>
+
+#include "sd-bus.h"
+
+#include "log.h"
+#include "netlink-util.h"
+#include "wifi-util.h"
+
+int wifi_get_ssid(sd_netlink *genl, int ifindex, char **ssid) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
+ sd_genl_family family;
+ int r;
+
+ r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to create generic netlink message: %m");
+
+ r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, ifindex);
+ if (r < 0)
+ return log_debug_errno(r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
+
+ r = sd_netlink_call(genl, m, 0, &reply);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to request information about wifi interface %d: %m", ifindex);
+ if (!reply)
+ return 0;
+
+ r = sd_netlink_message_get_errno(reply);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex);
+
+ r = sd_genl_message_get_family(genl, reply, &family);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to determine genl family: %m");
+ if (family != SD_GENL_NL80211) {
+ log_debug("Received message of unexpected genl family %u, ignoring.", family);
+ return 0;
+ }
+
+ r = sd_netlink_message_read_string_strdup(reply, NL80211_ATTR_SSID, ssid);
+ if (r < 0 && r != -ENODATA)
+ return log_debug_errno(r, "Failed to get NL80211_ATTR_SSID attribute: %m");
+
+ return r == -ENODATA ? 0 : 1;
+}
+
+int wifi_get_bssid(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
+ sd_genl_family family;
+ int r;
+
+ r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to create generic netlink message: %m");
+
+ r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to set dump flag: %m");
+
+ r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, ifindex);
+ if (r < 0)
+ return log_debug_errno(r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
+
+ r = sd_netlink_call(genl, m, 0, &reply);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to request information about wifi station: %m");
+ if (!reply)
+ return 0;
+
+ r = sd_netlink_message_get_errno(reply);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get information about wifi station: %m");
+
+ r = sd_genl_message_get_family(genl, reply, &family);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to determine genl family: %m");
+ if (family != SD_GENL_NL80211) {
+ log_debug("Received message of unexpected genl family %u, ignoring.", family);
+ return 0;
+ }
+
+ r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, bssid);
+ if (r < 0 && r != -ENODATA)
+ return log_debug_errno(r, "Failed to get NL80211_ATTR_MAC attribute: %m");
+
+ return r == -ENODATA ? 0 : 1;
+}
diff --git a/src/shared/wifi-util.h b/src/shared/wifi-util.h
new file mode 100644
index 0000000000..8887140100
--- /dev/null
+++ b/src/shared/wifi-util.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#pragma once
+
+#include "netlink-util.h"
+
+int wifi_get_ssid(sd_netlink *genl, int ifindex, char **ssid);
+int wifi_get_bssid(sd_netlink *genl, int ifindex, struct ether_addr *bssid);