1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-26 03:22:00 +03:00

Merge pull request #13828 from keszybz/networkctl-print-wlan

networkctl support for ssid and bssid
This commit is contained in:
Yu Watanabe 2019-10-24 11:12:39 +09:00 committed by GitHub
commit 6f3ad94590
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 222 additions and 131 deletions

View File

@ -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);
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);
(void) sd_device_new_from_device_id(&d, devid);
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 (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(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;

View File

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

View File

@ -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())

90
src/shared/wifi-util.c Normal file
View File

@ -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;
}

8
src/shared/wifi-util.h Normal file
View File

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