diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-10-24 11:12:39 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-24 11:12:39 +0900 |
commit | 6f3ad94590e3d6092f008b8b1443e12af84534e8 (patch) | |
tree | d2cfdf09444d26f48920b1d813a66d49b713f7f4 | |
parent | 14cd12b3d50f21cb9be7e27785142c6c321fac39 (diff) | |
parent | 8d07de25342b754f50073f2257f7329ec587d480 (diff) | |
download | systemd-6f3ad94590e3d6092f008b8b1443e12af84534e8.tar.gz |
Merge pull request #13828 from keszybz/networkctl-print-wlan
networkctl support for ssid and bssid
-rw-r--r-- | src/network/networkctl.c | 146 | ||||
-rw-r--r-- | src/network/networkd-wifi.c | 107 | ||||
-rw-r--r-- | src/shared/meson.build | 2 | ||||
-rw-r--r-- | src/shared/wifi-util.c | 90 | ||||
-rw-r--r-- | src/shared/wifi-util.h | 8 |
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); |