diff options
Diffstat (limited to 'clients/cli/devices.c')
| -rw-r--r-- | clients/cli/devices.c | 5045 |
1 files changed, 0 insertions, 5045 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c deleted file mode 100644 index 5800fe76..00000000 --- a/clients/cli/devices.c +++ /dev/null @@ -1,5045 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2010 - 2018 Red Hat, Inc. - */ - -#include "libnm/nm-default-client.h" - -#include "devices.h" - -#include <stdio.h> -#include <stdlib.h> -#include <readline/readline.h> -#include <linux/if_ether.h> - -#include "nm-glib-aux/nm-secret-utils.h" -#include "common.h" -#include "connections.h" -#include "nm-client-utils.h" -#include "nm-secret-agent-simple.h" -#include "polkit-agent.h" -#include "utils.h" - -/* define some prompts */ -#define PROMPT_INTERFACE _("Interface: ") -#define PROMPT_INTERFACES _("Interface(s): ") - -/*****************************************************************************/ - -static char * -ap_wpa_rsn_flags_to_string(NM80211ApSecurityFlags flags, NMMetaAccessorGetType get_type) -{ - char *flags_str[16]; - int i = 0; - - if (flags & NM_802_11_AP_SEC_PAIR_WEP40) - flags_str[i++] = "pair_wpe40"; - if (flags & NM_802_11_AP_SEC_PAIR_WEP104) - flags_str[i++] = "pair_wpe104"; - if (flags & NM_802_11_AP_SEC_PAIR_TKIP) - flags_str[i++] = "pair_tkip"; - if (flags & NM_802_11_AP_SEC_PAIR_CCMP) - flags_str[i++] = "pair_ccmp"; - if (flags & NM_802_11_AP_SEC_GROUP_WEP40) - flags_str[i++] = "group_wpe40"; - if (flags & NM_802_11_AP_SEC_GROUP_WEP104) - flags_str[i++] = "group_wpe104"; - if (flags & NM_802_11_AP_SEC_GROUP_TKIP) - flags_str[i++] = "group_tkip"; - if (flags & NM_802_11_AP_SEC_GROUP_CCMP) - flags_str[i++] = "group_ccmp"; - if (flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - flags_str[i++] = "psk"; - if (flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) - flags_str[i++] = "802.1X"; - if (flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) - flags_str[i++] = "sae"; - if (flags & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192) - flags_str[i++] = "wpa-eap-suite-b-192"; - if (NM_FLAGS_ANY(flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) - flags_str[i++] = "owe"; - - /* Make sure you grow flags_str when adding items here. */ - nm_assert(i < G_N_ELEMENTS(flags_str)); - - if (i == 0) { - if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup(_("(none)")); - return g_strdup("(none)"); - } - - flags_str[i] = NULL; - return g_strjoinv(" ", flags_str); -} - -static NMMetaColor -wifi_signal_to_color(guint8 strength) -{ - if (strength > 80) - return NM_META_COLOR_WIFI_SIGNAL_EXCELLENT; - else if (strength > 55) - return NM_META_COLOR_WIFI_SIGNAL_GOOD; - else if (strength > 30) - return NM_META_COLOR_WIFI_SIGNAL_FAIR; - else if (strength > 5) - return NM_META_COLOR_WIFI_SIGNAL_POOR; - else - return NM_META_COLOR_WIFI_SIGNAL_UNKNOWN; -} - -/*****************************************************************************/ - -static gconstpointer _metagen_device_status_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice * d = target; - NMActiveConnection *ac; - - NMC_HANDLE_COLOR(nmc_device_state_to_color(d)); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DEVICE: - return nm_device_get_iface(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_TYPE: - return nm_device_get_type_description(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE: - return nmc_meta_generic_get_str_i18n(nmc_device_state_to_string_with_external(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP4_CONNECTIVITY: - return nmc_meta_generic_get_str_i18n( - nm_connectivity_to_string(nm_device_get_connectivity(d, AF_INET)), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP6_CONNECTIVITY: - return nmc_meta_generic_get_str_i18n( - nm_connectivity_to_string(nm_device_get_connectivity(d, AF_INET6)), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH: - return nm_object_get_path(NM_OBJECT(d)); - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION: - ac = nm_device_get_active_connection(d); - return ac ? nm_active_connection_get_id(ac) : NULL; - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_UUID: - ac = nm_device_get_active_connection(d); - return ac ? nm_active_connection_get_uuid(ac) : NULL; - case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_PATH: - ac = nm_device_get_active_connection(d); - return ac ? nm_object_get_path(NM_OBJECT(ac)) : NULL; - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo - *const metagen_device_status[_NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_NUM + 1] = { -#define _METAGEN_DEVICE_STATUS(type, name) \ - [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_device_status_get_fcn) - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DEVICE, "DEVICE"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_TYPE, "TYPE"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE, "STATE"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP4_CONNECTIVITY, - "IP4-CONNECTIVITY"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP6_CONNECTIVITY, - "IP6-CONNECTIVITY"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH, "DBUS-PATH"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION, "CONNECTION"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_UUID, "CON-UUID"), - _METAGEN_DEVICE_STATUS(NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_PATH, "CON-PATH"), -}; - -/*****************************************************************************/ - -static gconstpointer _metagen_device_detail_general_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice * d = target; - NMActiveConnection *ac; - NMDeviceStateReason state_reason; - NMConnectivityState connectivity; - const char * s; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DEVICE: - return nm_device_get_iface(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_TYPE: - return nm_device_get_type_description(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_TYPE: - return G_OBJECT_TYPE_NAME(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DBUS_PATH: - return nm_object_get_path(NM_OBJECT(d)); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_VENDOR: - return nm_device_get_vendor(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PRODUCT: - return nm_device_get_product(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER: - s = nm_device_get_driver(d); - return s ?: nmc_meta_generic_get_unknown(get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER_VERSION: - return nm_device_get_driver_version(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_FIRMWARE_VERSION: - return nm_device_get_firmware_version(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_HWADDR: - s = nm_device_get_hw_address(d); - return s ?: nmc_meta_generic_get_unknown(get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_MTU: - return (*out_to_free = g_strdup_printf("%u", (guint) nm_device_get_mtu(d))); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_STATE: - return (*out_to_free = nmc_meta_generic_get_enum_with_detail( - NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, - nm_device_get_state(d), - nmc_device_state_to_string_with_external(d), - get_type)); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_REASON: - state_reason = nm_device_get_state_reason(d); - return (*out_to_free = nmc_meta_generic_get_enum_with_detail( - NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, - state_reason, - nmc_device_reason_to_string(state_reason), - get_type)); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP4_CONNECTIVITY: - connectivity = nm_device_get_connectivity(d, AF_INET); - return (*out_to_free = nmc_meta_generic_get_enum_with_detail( - NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, - connectivity, - nm_connectivity_to_string(connectivity), - get_type)); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP6_CONNECTIVITY: - connectivity = nm_device_get_connectivity(d, AF_INET6); - return (*out_to_free = nmc_meta_generic_get_enum_with_detail( - NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, - connectivity, - nm_connectivity_to_string(connectivity), - get_type)); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_UDI: - return nm_device_get_udi(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PATH: - return nm_device_get_path(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP_IFACE: - return nm_device_get_ip_iface(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IS_SOFTWARE: - return nmc_meta_generic_get_bool(nm_device_is_software(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_MANAGED: - return nmc_meta_generic_get_bool(nm_device_get_managed(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_AUTOCONNECT: - return nmc_meta_generic_get_bool(nm_device_get_autoconnect(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_FIRMWARE_MISSING: - return nmc_meta_generic_get_bool(nm_device_get_firmware_missing(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_PLUGIN_MISSING: - return nmc_meta_generic_get_bool(nm_device_get_nm_plugin_missing(d), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PHYS_PORT_ID: - return nm_device_get_physical_port_id(d); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CONNECTION: - ac = nm_device_get_active_connection(d); - return ac ? nm_active_connection_get_id(ac) : NULL; - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CON_UUID: - ac = nm_device_get_active_connection(d); - return ac ? nm_active_connection_get_uuid(ac) : NULL; - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CON_PATH: - ac = nm_device_get_active_connection(d); - return ac ? nm_object_get_path(NM_OBJECT(ac)) : NULL; - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_METERED: - return nmc_meta_generic_get_str_i18n(nmc_device_metered_to_string(nm_device_get_metered(d)), - get_type); - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo - *const metagen_device_detail_general[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NUM + 1] = { -#define _METAGEN_DEVICE_DETAIL_GENERAL(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_general_get_fcn) - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DEVICE, - "DEVICE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_TYPE, "TYPE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_TYPE, - "NM-TYPE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DBUS_PATH, - "DBUS-PATH"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_VENDOR, - "VENDOR"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PRODUCT, - "PRODUCT"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER, - "DRIVER"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER_VERSION, - "DRIVER-VERSION"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_FIRMWARE_VERSION, - "FIRMWARE-VERSION"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_HWADDR, - "HWADDR"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_MTU, "MTU"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_STATE, "STATE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_REASON, - "REASON"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP4_CONNECTIVITY, - "IP4-CONNECTIVITY"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP6_CONNECTIVITY, - "IP6-CONNECTIVITY"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_UDI, "UDI"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PATH, "PATH"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP_IFACE, - "IP-IFACE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IS_SOFTWARE, - "IS-SOFTWARE"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_MANAGED, - "NM-MANAGED"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_AUTOCONNECT, - "AUTOCONNECT"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_FIRMWARE_MISSING, - "FIRMWARE-MISSING"), - _METAGEN_DEVICE_DETAIL_GENERAL( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_PLUGIN_MISSING, - "NM-PLUGIN-MISSING"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PHYS_PORT_ID, - "PHYS-PORT-ID"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CONNECTION, - "CONNECTION"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CON_UUID, - "CON-UUID"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_CON_PATH, - "CON-PATH"), - _METAGEN_DEVICE_DETAIL_GENERAL(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_METERED, - "METERED"), -}; - -/*****************************************************************************/ - -static NMRemoteConnection ** -_device_get_available_connections(NMDevice *d, guint *out_len) -{ - NMRemoteConnection **avail_cons; - const GPtrArray * avail_cons_arr; - - avail_cons_arr = nm_device_get_available_connections(d); - if (!avail_cons_arr || avail_cons_arr->len == 0) { - *out_len = 0; - return NULL; - } - - avail_cons = (NMRemoteConnection **) nmc_objects_sort_by_path( - (const NMObject *const *) avail_cons_arr->pdata, - avail_cons_arr->len); - nm_assert(avail_cons_arr->len == NM_PTRARRAY_LEN(avail_cons)); - *out_len = avail_cons_arr->len; - return avail_cons; -} - -static gconstpointer _metagen_device_detail_connections_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice *d = target; - gs_free NMRemoteConnection **avail_cons = NULL; - guint avail_cons_len; - guint i, j; - char ** arr = NULL; - GString * str; - gboolean had_prefix, has_prefix; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CONNECTIONS_AVAILABLE_CONNECTIONS: - if (!NM_FLAGS_HAS(get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) - return NULL; - - avail_cons = _device_get_available_connections(d, &avail_cons_len); - if (avail_cons_len == 0) - goto arr_out; - - arr = g_new(char *, avail_cons_len + 1); - j = 0; - for (i = 0; i < avail_cons_len; i++) { - NMRemoteConnection *ac = avail_cons[i]; - const char * ac_id = nm_connection_get_id(NM_CONNECTION(ac)); - const char * ac_uuid = nm_connection_get_uuid(NM_CONNECTION(ac)); - - if (!ac_id || !ac_uuid) { - const char *ac_path = nm_connection_get_path(NM_CONNECTION(ac)); - - if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) { - arr[j++] = ac_path ? g_strdup_printf(_("<invisible> | %s"), ac_path) - : g_strdup(_("<invisible>")); - } else { - arr[j++] = ac_path ? g_strdup_printf("<invisible> | %s", ac_path) - : g_strdup("<invisible>"); - } - } else - arr[j++] = g_strdup_printf("%s | %s", ac_uuid, ac_id); - } - arr[j] = NULL; - goto arr_out; - - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CONNECTIONS_AVAILABLE_CONNECTION_PATHS: - - avail_cons = _device_get_available_connections(d, &avail_cons_len); - if (avail_cons_len == 0) - return NULL; - - str = g_string_new(NULL); - - had_prefix = FALSE; - for (i = 0; i < avail_cons_len; i++) { - NMRemoteConnection *ac = avail_cons[i]; - const char * p = nm_connection_get_path(NM_CONNECTION(ac)); - - if (!p) - continue; - - has_prefix = g_str_has_prefix(p, NM_DBUS_PATH_SETTINGS_CONNECTION "/") - && p[NM_STRLEN(NM_DBUS_PATH_SETTINGS_CONNECTION "/")]; - - if (str->len > 0) { - if (had_prefix && !has_prefix) - g_string_append_c(str, '}'); - g_string_append_c(str, ','); - } - - if (!has_prefix) - g_string_append(str, p); - else { - if (!had_prefix) - g_string_printf(str, "%s/{", NM_DBUS_PATH_SETTINGS_CONNECTION); - g_string_append(str, &p[NM_STRLEN(NM_DBUS_PATH_SETTINGS_CONNECTION "/")]); - } - had_prefix = has_prefix; - } - if (had_prefix) - g_string_append_c(str, '}'); - - return (*out_to_free = g_string_free(str, FALSE)); - - default: - break; - } - - g_return_val_if_reached(NULL); - -arr_out: - NM_SET_OUT(out_is_default, !arr || !arr[0]); - *out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV; - *out_to_free = arr; - return arr; -} - -const NmcMetaGenericInfo *const - metagen_device_detail_connections[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CONNECTIONS_NUM + 1] = { -#define _METAGEN_DEVICE_DETAIL_CONNECTIONS(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_connections_get_fcn) - _METAGEN_DEVICE_DETAIL_CONNECTIONS( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CONNECTIONS_AVAILABLE_CONNECTION_PATHS, - "AVAILABLE-CONNECTION-PATHS"), - _METAGEN_DEVICE_DETAIL_CONNECTIONS( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CONNECTIONS_AVAILABLE_CONNECTIONS, - "AVAILABLE-CONNECTIONS"), -}; - -/*****************************************************************************/ - -static gconstpointer _metagen_device_detail_capabilities_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice * d = target; - NMDeviceCapabilities caps; - guint32 speed; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - caps = nm_device_get_capabilities(d); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_CARRIER_DETECT: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(caps, NM_DEVICE_CAP_CARRIER_DETECT), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_SPEED: - speed = 0; - if (NM_IS_DEVICE_ETHERNET(d)) { - /* Speed in Mb/s */ - speed = nm_device_ethernet_get_speed(NM_DEVICE_ETHERNET(d)); - } else if (NM_IS_DEVICE_WIFI(d)) { - /* Speed in b/s */ - speed = nm_device_wifi_get_bitrate(NM_DEVICE_WIFI(d)); - speed /= 1000; - } - - if (speed) { - if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - return (*out_to_free = g_strdup_printf(_("%u Mb/s"), (guint) speed)); - return (*out_to_free = g_strdup_printf("%u Mb/s", (guint) speed)); - } - return nmc_meta_generic_get_str_i18n(N_("unknown"), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_IS_SOFTWARE: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(caps, NM_DEVICE_CAP_IS_SOFTWARE), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_SRIOV: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(caps, NM_DEVICE_CAP_SRIOV), get_type); - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo - *const metagen_device_detail_capabilities[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_NUM - + 1] = { -#define _METAGEN_DEVICE_DETAIL_CAPABILITIES(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_capabilities_get_fcn) - _METAGEN_DEVICE_DETAIL_CAPABILITIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_CARRIER_DETECT, - "CARRIER-DETECT"), - _METAGEN_DEVICE_DETAIL_CAPABILITIES(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_SPEED, - "SPEED"), - _METAGEN_DEVICE_DETAIL_CAPABILITIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_IS_SOFTWARE, - "IS-SOFTWARE"), - _METAGEN_DEVICE_DETAIL_CAPABILITIES(NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_CAPABILITIES_SRIOV, - "SRIOV"), -}; - -/*****************************************************************************/ - -static gconstpointer - _metagen_device_detail_wired_properties_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice *d = target; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIRED_PROPERTIES_CARRIER: - return nmc_meta_generic_get_bool_onoff( - nm_device_ethernet_get_carrier(NM_DEVICE_ETHERNET(d)), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIRED_PROPERTIES_S390_SUBCHANNELS: - if (!NM_FLAGS_HAS(get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) - return NULL; - *out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV; - return nm_device_ethernet_get_s390_subchannels(NM_DEVICE_ETHERNET(d)); - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo *const - metagen_device_detail_wired_properties[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIRED_PROPERTIES_NUM - + 1] = { -#define _METAGEN_DEVICE_DETAIL_WIRED_PROPERTIES(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_wired_properties_get_fcn) - _METAGEN_DEVICE_DETAIL_WIRED_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIRED_PROPERTIES_CARRIER, - "CARRIER"), - _METAGEN_DEVICE_DETAIL_WIRED_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIRED_PROPERTIES_S390_SUBCHANNELS, - "S390-SUBCHANNELS"), -}; - -/*****************************************************************************/ - -static gconstpointer - _metagen_device_detail_wifi_properties_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice * d = target; - NMDeviceWifiCapabilities wcaps; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - wcaps = nm_device_wifi_get_capabilities(NM_DEVICE_WIFI(d)); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WEP: - return nmc_meta_generic_get_bool( - NM_FLAGS_ANY(wcaps, NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_WPA), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA2: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_RSN), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_TKIP: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_CIPHER_TKIP), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_CCMP: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_CIPHER_CCMP), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_AP: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_AP), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_ADHOC), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ: - return nmc_meta_generic_get_str_i18n( - NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_FREQ_VALID) - ? (NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_FREQ_2GHZ) ? N_("yes") : N_("no")) - : N_("unknown"), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ: - return nmc_meta_generic_get_str_i18n( - NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_FREQ_VALID) - ? (NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_FREQ_5GHZ) ? N_("yes") : N_("no")) - : N_("unknown"), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_MESH), get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_IBSS_RSN: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(wcaps, NM_WIFI_DEVICE_CAP_IBSS_RSN), - get_type); - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo *const - metagen_device_detail_wifi_properties[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_NUM - + 1] = { -#define _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_wifi_properties_get_fcn) - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WEP, - "WEP"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA, - "WPA"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA2, - "WPA2"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_TKIP, - "TKIP"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_CCMP, - "CCMP"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_AP, - "AP"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC, - "ADHOC"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ, - "2GHZ"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ, - "5GHZ"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH, - "MESH"), - _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_IBSS_RSN, - "IBSS-RSN"), -}; - -/*****************************************************************************/ - -static gconstpointer - _metagen_device_detail_interface_flags_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) -{ - NMDevice * d = target; - NMDeviceInterfaceFlags flags; - - NMC_HANDLE_COLOR(NM_META_COLOR_NONE); - - flags = nm_device_get_interface_flags(d); - - switch (info->info_type) { - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_UP: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(flags, NM_DEVICE_INTERFACE_FLAG_UP), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_LOWER_UP: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(flags, NM_DEVICE_INTERFACE_FLAG_LOWER_UP), - get_type); - case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_CARRIER: - return nmc_meta_generic_get_bool(NM_FLAGS_HAS(flags, NM_DEVICE_INTERFACE_FLAG_CARRIER), - get_type); - default: - break; - } - - g_return_val_if_reached(NULL); -} - -const NmcMetaGenericInfo *const - metagen_device_detail_interface_flags[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_NUM - + 1] = { -#define _METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS(type, name) \ - [type] = NMC_META_GENERIC(name, \ - .info_type = type, \ - .get_fcn = _metagen_device_detail_interface_flags_get_fcn) - _METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_UP, - "UP"), - _METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_LOWER_UP, - "LOWER-UP"), - _METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS( - NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_CARRIER, - "CARRIER"), -}; - -/*****************************************************************************/ - -const NmcMetaGenericInfo *const metagen_device_detail_wimax_properties[] = { - NMC_META_GENERIC("CTR-FREQ"), - NMC_META_GENERIC("RSSI"), - NMC_META_GENERIC("CINR"), - NMC_META_GENERIC("TX-POW"), - NMC_META_GENERIC("BSID"), -}; - -/*****************************************************************************/ - -const NmcMetaGenericInfo *const nmc_fields_dev_wifi_list[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("SSID"), /* 1 */ - NMC_META_GENERIC("SSID-HEX"), /* 2 */ - NMC_META_GENERIC("BSSID"), /* 3 */ - NMC_META_GENERIC("MODE"), /* 4 */ - NMC_META_GENERIC("CHAN"), /* 5 */ - NMC_META_GENERIC("FREQ"), /* 6 */ - NMC_META_GENERIC("RATE"), /* 7 */ - NMC_META_GENERIC("SIGNAL"), /* 8 */ - NMC_META_GENERIC("BARS"), /* 9 */ - NMC_META_GENERIC("SECURITY"), /* 10 */ - NMC_META_GENERIC("WPA-FLAGS"), /* 11 */ - NMC_META_GENERIC("RSN-FLAGS"), /* 12 */ - NMC_META_GENERIC("DEVICE"), /* 13 */ - NMC_META_GENERIC("ACTIVE"), /* 14 */ - NMC_META_GENERIC("IN-USE"), /* 15 */ - NMC_META_GENERIC("DBUS-PATH"), /* 16 */ - NULL, -}; -#define NMC_FIELDS_DEV_WIFI_LIST_COMMON "IN-USE,BSSID,SSID,MODE,CHAN,RATE,SIGNAL,BARS,SECURITY" -#define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST "NAME," NMC_FIELDS_DEV_WIFI_LIST_COMMON - -const NmcMetaGenericInfo *const nmc_fields_dev_wimax_list[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("NSP"), /* 1 */ - NMC_META_GENERIC("SIGNAL"), /* 2 */ - NMC_META_GENERIC("TYPE"), /* 3 */ - NMC_META_GENERIC("DEVICE"), /* 4 */ - NMC_META_GENERIC("ACTIVE"), /* 5 */ - NMC_META_GENERIC("DBUS-PATH"), /* 6 */ - NULL, -}; -#define NMC_FIELDS_DEV_WIMAX_LIST_COMMON "NSP,SIGNAL,TYPE,DEVICE,ACTIVE" -#define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST "NAME," NMC_FIELDS_DEV_WIMAX_LIST_COMMON - -const NmcMetaGenericInfo *const nmc_fields_dev_show_master_prop[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("SLAVES"), /* 1 */ - NULL, -}; -#define NMC_FIELDS_DEV_SHOW_MASTER_PROP_COMMON "NAME,SLAVES" - -const NmcMetaGenericInfo *const nmc_fields_dev_show_team_prop[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("SLAVES"), /* 1 */ - NMC_META_GENERIC("CONFIG"), /* 2 */ - NULL, -}; -#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_COMMON "NAME,SLAVES,CONFIG" - -const NmcMetaGenericInfo *const nmc_fields_dev_show_vlan_prop[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("PARENT"), /* 1 */ - NMC_META_GENERIC("ID"), /* 2 */ - NULL, -}; -#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON "NAME,PARENT,ID" - -const NmcMetaGenericInfo *const nmc_fields_dev_show_bluetooth[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("CAPABILITIES"), /* 1 */ - NULL, -}; -#define NMC_FIELDS_DEV_SHOW_BLUETOOTH_COMMON "NAME,CAPABILITIES" - -/* Available sections for 'device show' */ -const NmcMetaGenericInfo *const nmc_fields_dev_show_sections[] = { - NMC_META_GENERIC_WITH_NESTED("GENERAL", metagen_device_detail_general), /* 0 */ - NMC_META_GENERIC_WITH_NESTED("CAPABILITIES", metagen_device_detail_capabilities), /* 1 */ - NMC_META_GENERIC_WITH_NESTED("INTERFACE-FLAGS", metagen_device_detail_interface_flags), /* 2 */ - NMC_META_GENERIC_WITH_NESTED("WIFI-PROPERTIES", metagen_device_detail_wifi_properties), /* 3 */ - NMC_META_GENERIC_WITH_NESTED("AP", nmc_fields_dev_wifi_list + 1), /* 4 */ - NMC_META_GENERIC_WITH_NESTED("WIRED-PROPERTIES", - metagen_device_detail_wired_properties), /* 5 */ - NMC_META_GENERIC_WITH_NESTED("WIMAX-PROPERTIES", - metagen_device_detail_wimax_properties), /* 6 */ - NMC_META_GENERIC_WITH_NESTED("NSP", nmc_fields_dev_wimax_list + 1), /* 7 */ - NMC_META_GENERIC_WITH_NESTED("IP4", metagen_ip4_config), /* 8 */ - NMC_META_GENERIC_WITH_NESTED("DHCP4", metagen_dhcp_config), /* 9 */ - NMC_META_GENERIC_WITH_NESTED("IP6", metagen_ip6_config), /* 10 */ - NMC_META_GENERIC_WITH_NESTED("DHCP6", metagen_dhcp_config), /* 11 */ - NMC_META_GENERIC_WITH_NESTED("BOND", nmc_fields_dev_show_master_prop + 1), /* 12 */ - NMC_META_GENERIC_WITH_NESTED("TEAM", nmc_fields_dev_show_team_prop + 1), /* 13 */ - NMC_META_GENERIC_WITH_NESTED("BRIDGE", nmc_fields_dev_show_master_prop + 1), /* 14 */ - NMC_META_GENERIC_WITH_NESTED("VLAN", nmc_fields_dev_show_vlan_prop + 1), /* 15 */ - NMC_META_GENERIC_WITH_NESTED("BLUETOOTH", nmc_fields_dev_show_bluetooth + 1), /* 16 */ - NMC_META_GENERIC_WITH_NESTED("CONNECTIONS", metagen_device_detail_connections), /* 17 */ - NULL, -}; -#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON \ - "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.HWADDR,GENERAL.MTU,GENERAL.STATE," \ - "GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6" - -const NmcMetaGenericInfo *const nmc_fields_dev_lldp_list[] = { - NMC_META_GENERIC("NAME"), /* 0 */ - NMC_META_GENERIC("DEVICE"), /* 1 */ - NMC_META_GENERIC("CHASSIS-ID"), /* 2 */ - NMC_META_GENERIC("PORT-ID"), /* 3 */ - NMC_META_GENERIC("PORT-DESCRIPTION"), /* 4 */ - NMC_META_GENERIC("SYSTEM-NAME"), /* 5 */ - NMC_META_GENERIC("SYSTEM-DESCRIPTION"), /* 6 */ - NMC_META_GENERIC("SYSTEM-CAPABILITIES"), /* 7 */ - NMC_META_GENERIC("IEEE-802-1-PVID"), /* 8 */ - NMC_META_GENERIC("IEEE-802-1-PPVID"), /* 9 */ - NMC_META_GENERIC("IEEE-802-1-PPVID-FLAGS"), /* 10 */ - NMC_META_GENERIC("IEEE-802-1-VID"), /* 11 */ - NMC_META_GENERIC("IEEE-802-1-VLAN-NAME"), /* 12 */ - NMC_META_GENERIC("DESTINATION"), /* 13 */ - NMC_META_GENERIC("CHASSIS-ID-TYPE"), /* 14 */ - NMC_META_GENERIC("PORT-ID-TYPE"), /* 15 */ - NULL, -}; -#define NMC_FIELDS_DEV_LLDP_LIST_COMMON \ - "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \ - "SYSTEM-CAPABILITIES" - -static guint progress_id = 0; /* ID of event source for displaying progress */ - -static void -usage(void) -{ - g_printerr(_("Usage: nmcli device { COMMAND | help }\n\n" - "COMMAND := { status | show | set | connect | reapply | modify | disconnect | " - "delete | monitor | wifi | lldp }\n\n" - " status\n\n" - " show [<ifname>]\n\n" - " set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n" - " connect <ifname>\n\n" - " reapply <ifname>\n\n" - " modify <ifname> ([+|-]<setting>.<property> <value>)+\n\n" - " disconnect <ifname> ...\n\n" - " delete <ifname> ...\n\n" - " monitor <ifname> ...\n\n" - " wifi [list [ifname <ifname>] [bssid <BSSID>] [--rescan yes|no|auto]]\n\n" - " wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname " - "<ifname>]\n" - " [bssid <BSSID>] [name <name>] [private yes|no] [hidden " - "yes|no]\n\n" - " wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] " - "[channel <channel>] [password <password>]\n\n" - " wifi rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n\n" - " wifi show-password [ifname <ifname>]\n\n" - " lldp [list [ifname <ifname>]]\n\n")); -} - -static void -usage_device_status(void) -{ - g_printerr( - _("Usage: nmcli device status { help }\n" - "\n" - "Show status for all devices.\n" - "By default, the following columns are shown:\n" - " DEVICE - interface name\n" - " TYPE - device type\n" - " STATE - device state\n" - " CONNECTION - connection activated on device (if any)\n" - "Displayed columns can be changed using '--fields' global option. 'status' is\n" - "the default command, which means 'nmcli device' calls 'nmcli device status'.\n\n")); -} - -static void -usage_device_show(void) -{ - g_printerr(_("Usage: nmcli device show { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [<ifname>]\n" - "\n" - "Show details of device(s).\n" - "The command lists details for all devices, or for a given device.\n\n")); -} - -static void -usage_device_connect(void) -{ - g_printerr(_("Usage: nmcli device connect { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := <ifname>\n" - "\n" - "Connect the device.\n" - "NetworkManager will try to find a suitable connection that will be activated.\n" - "It will also consider connections that are not set to auto-connect.\n\n")); -} - -static void -usage_device_reapply(void) -{ - g_printerr(_("Usage: nmcli device reapply { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := <ifname>\n" - "\n" - "Attempts to update device with changes to the currently active connection\n" - "made since it was last applied.\n\n")); -} - -static void -usage_device_modify(void) -{ - g_printerr(_( - "Usage: nmcli device modify { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := <ifname> ([+|-]<setting>.<property> <value>)+\n" - "\n" - "Modify one or more properties that are currently active on the device without modifying\n" - "the connection profile. The changes have immediate effect. For multi-valued\n" - "properties you can use optional '+' or '-' prefix to the property name.\n" - "The '+' sign allows appending items instead of overwriting the whole value.\n" - "The '-' sign allows removing selected items instead of the whole value.\n" - "\n" - "Examples:\n" - "nmcli dev mod em1 ipv4.method manual ipv4.addr \"192.168.1.2/24, 10.10.1.5/8\"\n" - "nmcli dev mod em1 +ipv4.dns 8.8.4.4\n" - "nmcli dev mod em1 -ipv4.dns 1\n" - "nmcli dev mod em1 -ipv6.addr \"abbe::cafe/56\"\n")); -} - -static void -usage_device_disconnect(void) -{ - g_printerr(_("Usage: nmcli device disconnect { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := <ifname> ...\n" - "\n" - "Disconnect devices.\n" - "The command disconnects the device and prevents it from auto-activating\n" - "further connections without user/manual intervention.\n\n")); -} - -static void -usage_device_delete(void) -{ - g_printerr(_("Usage: nmcli device delete { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := <ifname> ...\n" - "\n" - "Delete the software devices.\n" - "The command removes the interfaces. It only works for software devices\n" - "(like bonds, bridges, etc.). Hardware devices cannot be deleted by the\n" - "command.\n\n")); -} - -static void -usage_device_set(void) -{ - g_printerr(_("Usage: nmcli device set { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := DEVICE { PROPERTY [ PROPERTY ... ] }\n" - "DEVICE := [ifname] <ifname> \n" - "PROPERTY := { autoconnect { yes | no } |\n" - " { managed { yes | no }\n" - "\n" - "Modify device properties.\n\n")); -} - -static void -usage_device_monitor(void) -{ - g_printerr(_("Usage: nmcli device monitor { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [<ifname>] ...\n" - "\n" - "Monitor device activity.\n" - "This command prints a line whenever the specified devices change state.\n" - "Monitors all devices in case no interface is specified.\n\n")); -} - -static void -usage_device_wifi(void) -{ - g_printerr( - _("Usage: nmcli device wifi { ARGUMENTS | help }\n" - "\n" - "Perform operation on Wi-Fi devices.\n" - "\n" - "ARGUMENTS := [list [ifname <ifname>] [bssid <BSSID>] [--rescan yes|no|auto]]\n" - "\n" - "List available Wi-Fi access points. The 'ifname' and 'bssid' options can be\n" - "used to list APs for a particular interface, or with a specific BSSID. The\n" - "--rescan flag tells whether a new Wi-Fi scan should be triggered.\n" - "\n" - "ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname " - "<ifname>]\n" - " [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n" - "\n" - "Connect to a Wi-Fi network specified by SSID or BSSID. The command finds a\n" - "matching connection or creates one and then activates it on a device. This\n" - "is a command-line counterpart of clicking an SSID in a GUI client. If a\n" - "connection for the network already exists, it is possible to bring up the\n" - "existing profile as follows: nmcli con up id <name>. Note that only open,\n" - "WEP and WPA-PSK networks are supported if no previous connection exists.\n" - "It is also assumed that IP configuration is obtained via DHCP.\n" - "\n" - "ARGUMENTS := hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>]\n" - " [band a|bg] [channel <channel>] [password <password>]\n" - "\n" - "Create a Wi-Fi hotspot. Use 'connection down' or 'device disconnect'\n" - "to stop the hotspot.\n" - "Parameters of the hotspot can be influenced by the optional parameters:\n" - "ifname - Wi-Fi device to use\n" - "con-name - name of the created hotspot connection profile\n" - "ssid - SSID of the hotspot\n" - "band - Wi-Fi band to use\n" - "channel - Wi-Fi channel to use\n" - "password - password to use for the hotspot\n" - "\n" - "ARGUMENTS := rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n" - "\n" - "Request that NetworkManager immediately re-scan for available access points.\n" - "NetworkManager scans Wi-Fi networks periodically, but in some cases it might\n" - "be useful to start scanning manually. 'ssid' allows scanning for a specific\n" - "SSID, which is useful for APs with hidden SSIDs. More 'ssid' parameters can be\n" - "given. Note that this command does not show the APs,\n" - "use 'nmcli device wifi list' for that.\n\n")); -} - -static void -usage_device_lldp(void) -{ - g_printerr(_("Usage: nmcli device lldp { ARGUMENTS | help }\n" - "\n" - "ARGUMENTS := [list [ifname <ifname>]]\n" - "\n" - "List neighboring devices discovered through LLDP. The 'ifname' option can be\n" - "used to list neighbors for a particular interface.\n\n")); -} - -static void -quit(void) -{ - if (nm_clear_g_source(&progress_id)) - nmc_terminal_erase_line(); - g_main_loop_quit(loop); -} - -static int -compare_devices(const void *a, const void *b) -{ - NMDevice * da = *(NMDevice **) a; - NMDevice * db = *(NMDevice **) b; - NMActiveConnection *da_ac = nm_device_get_active_connection(da); - NMActiveConnection *db_ac = nm_device_get_active_connection(db); - - NM_CMP_DIRECT(nm_device_get_state(db), nm_device_get_state(da)); - NM_CMP_RETURN(nmc_active_connection_cmp(db_ac, da_ac)); - NM_CMP_DIRECT_STRCMP0(nm_device_get_type_description(da), nm_device_get_type_description(db)); - NM_CMP_DIRECT_STRCMP0(nm_device_get_iface(da), nm_device_get_iface(db)); - NM_CMP_DIRECT_STRCMP0(nm_object_get_path(NM_OBJECT(da)), nm_object_get_path(NM_OBJECT(db))); - - g_return_val_if_reached(0); -} - -NMDevice ** -nmc_get_devices_sorted(NMClient *client) -{ - const GPtrArray *devs; - NMDevice ** sorted; - - devs = nm_client_get_devices(client); - - sorted = g_new(NMDevice *, devs->len + 1); - if (devs->len > 0) - memcpy(sorted, devs->pdata, devs->len * sizeof(NMDevice *)); - sorted[devs->len] = NULL; - - qsort(sorted, devs->len, sizeof(NMDevice *), compare_devices); - return sorted; -} - -static void -complete_device(NMDevice **devices, const char *prefix, gboolean wifi_only) -{ - int i; - - for (i = 0; devices[i]; i++) { - const char *iface = nm_device_get_iface(devices[i]); - - if (wifi_only && !NM_IS_DEVICE_WIFI(devices[i])) - continue; - - if (g_str_has_prefix(iface, prefix)) - g_print("%s\n", iface); - } -} - -void -nmc_complete_device(NMClient *client, const char *prefix, gboolean wifi_only) -{ - gs_free NMDevice **devices = NULL; - - devices = nmc_get_devices_sorted(client); - complete_device(devices, prefix, wifi_only); -} - -static GSList * -get_device_list(NmCli *nmc, int argc, const char *const *argv) -{ - int arg_num = argc; - gs_strfreev char **arg_arr = NULL; - const char *const *arg_ptr = argv; - NMDevice ** devices; - GSList * queue = NULL; - NMDevice * device; - int i; - - if (argc == 0) { - if (nmc->ask) { - gs_free char *line = NULL; - - line = nmc_readline(&nmc->nmc_config, PROMPT_INTERFACES); - nmc_string_to_arg_array(line, NULL, FALSE, &arg_arr, &arg_num); - arg_ptr = (const char *const *) arg_arr; - } - if (arg_num == 0) { - g_string_printf(nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } - } - - devices = nmc_get_devices_sorted(nmc->client); - while (arg_num > 0) { - if (arg_num == 1 && nmc->complete) - complete_device(devices, *arg_ptr, FALSE); - - device = NULL; - for (i = 0; devices[i]; i++) { - if (!g_strcmp0(nm_device_get_iface(devices[i]), *arg_ptr)) { - device = devices[i]; - break; - } - } - - if (device) { - if (!g_slist_find(queue, device)) - queue = g_slist_prepend(queue, device); - else - g_printerr(_("Warning: argument '%s' is duplicated.\n"), *arg_ptr); - } else { - if (!nmc->complete) - g_printerr(_("Error: Device '%s' not found.\n"), *arg_ptr); - g_string_printf(nmc->return_text, _("Error: not all devices found.")); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - } - - /* Take next argument */ - next_arg(nmc->ask ? NULL : nmc, &arg_num, &arg_ptr, NULL); - } - g_free(devices); - -error: - g_strfreev(arg_arr); - - return queue; -} - -static NMDevice * -get_device(NmCli *nmc, int *argc, const char *const **argv, GError **error) -{ - gs_free NMDevice **devices = NULL; - gs_free char * ifname_ask = NULL; - const char * ifname = NULL; - int i; - - if (*argc == 0) { - if (nmc->ask) { - ifname = ifname_ask = nmc_readline(&nmc->nmc_config, PROMPT_INTERFACE); - } - - if (!ifname_ask) { - g_set_error_literal(error, - NMCLI_ERROR, - NMC_RESULT_ERROR_USER_INPUT, - _("No interface specified")); - return NULL; - } - } else { - ifname = **argv; - next_arg(nmc, argc, argv, NULL); - } - - devices = nmc_get_devices_sorted(nmc->client); - for (i = 0; devices[i]; i++) { - if (!g_strcmp0(nm_device_get_iface(devices[i]), ifname)) - break; - } - - if (nmc->complete && !*argc) - complete_device(devices, ifname, FALSE); - - if (devices[i] == NULL) { - g_set_error(error, - NMCLI_ERROR, - NMC_RESULT_ERROR_NOT_FOUND, - _("Device '%s' not found"), - ifname); - } - - return devices[i]; -} - -static int -compare_aps(gconstpointer a, gconstpointer b, gpointer user_data) -{ - NMAccessPoint *apa = *(NMAccessPoint **) a; - NMAccessPoint *apb = *(NMAccessPoint **) b; - - NM_CMP_DIRECT(nm_access_point_get_strength(apb), nm_access_point_get_strength(apa)); - NM_CMP_DIRECT(nm_access_point_get_frequency(apa), nm_access_point_get_frequency(apb)); - NM_CMP_DIRECT(nm_access_point_get_max_bitrate(apb), nm_access_point_get_max_bitrate(apa)); - - /* as fallback, just give it some stable order and use the D-Bus path (literally). */ - NM_CMP_DIRECT_STRCMP0(nm_object_get_path(NM_OBJECT(apa)), nm_object_get_path(NM_OBJECT(apb))); - - return 0; -} - -static GPtrArray * -sort_access_points(const GPtrArray *aps) -{ - GPtrArray *sorted; - guint i; - - g_return_val_if_fail(aps, NULL); - - sorted = g_ptr_array_sized_new(aps->len); - g_ptr_array_set_free_func(sorted, nm_g_object_unref); - for (i = 0; i < aps->len; i++) - g_ptr_array_add(sorted, g_object_ref(aps->pdata[i])); - g_ptr_array_sort_with_data(sorted, compare_aps, NULL); - return sorted; -} - -typedef struct { - NmCli * nmc; - int index; - guint32 output_flags; - const char *active_bssid; - const char *device; - GPtrArray * output_data; -} APInfo; - -static void -fill_output_access_point(gpointer data, gpointer user_data) -{ - NMAccessPoint * ap = NM_ACCESS_POINT(data); - APInfo * info = (APInfo *) user_data; - NmcOutputField * arr; - gboolean active = FALSE; - NM80211ApFlags flags; - NM80211ApSecurityFlags wpa_flags, rsn_flags; - guint32 freq, bitrate; - guint8 strength; - GBytes * ssid; - const char * bssid; - NM80211Mode mode; - char *channel_str, *freq_str, *ssid_str = NULL, *ssid_hex_str = NULL, *bitrate_str, - *strength_str, *wpa_flags_str, *rsn_flags_str; - GString * security_str; - char * ap_name; - const char *sig_bars; - NMMetaColor color; - - if (info->active_bssid) { - const char *current_bssid = nm_access_point_get_bssid(ap); - if (current_bssid && !strcmp(current_bssid, info->active_bssid)) - active = TRUE; - } - - /* Get AP properties */ - flags = nm_access_point_get_flags(ap); - wpa_flags = nm_access_point_get_wpa_flags(ap); - rsn_flags = nm_access_point_get_rsn_flags(ap); - ssid = nm_access_point_get_ssid(ap); - bssid = nm_access_point_get_bssid(ap); - freq = nm_access_point_get_frequency(ap); - mode = nm_access_point_get_mode(ap); - bitrate = nm_access_point_get_max_bitrate(ap); - strength = MIN(nm_access_point_get_strength(ap), 100); - - /* Convert to strings */ - if (ssid) { - const guint8 *ssid_data; - gsize ssid_len; - - ssid_data = g_bytes_get_data(ssid, &ssid_len); - ssid_str = nm_utils_ssid_to_utf8(ssid_data, ssid_len); - ssid_hex_str = ssid_to_hex((const char *) ssid_data, ssid_len); - } - channel_str = g_strdup_printf("%u", nm_utils_wifi_freq_to_channel(freq)); - freq_str = g_strdup_printf(_("%u MHz"), freq); - bitrate_str = g_strdup_printf(_("%u Mbit/s"), bitrate / 1000); - strength_str = nm_strdup_int(strength); - wpa_flags_str = ap_wpa_rsn_flags_to_string(wpa_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY); - rsn_flags_str = ap_wpa_rsn_flags_to_string(rsn_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY); - sig_bars = nmc_wifi_strength_bars(strength); - - security_str = g_string_new(NULL); - - if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags == NM_802_11_AP_SEC_NONE) - && (rsn_flags == NM_802_11_AP_SEC_NONE)) { - g_string_append(security_str, "WEP "); - } - if (wpa_flags != NM_802_11_AP_SEC_NONE) { - g_string_append(security_str, "WPA1 "); - } - if ((rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - g_string_append(security_str, "WPA2 "); - } - if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { - g_string_append(security_str, "WPA3 "); - } - if (NM_FLAGS_ANY(rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { - g_string_append(security_str, "OWE "); - } - if ((wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) - || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - g_string_append(security_str, "802.1X "); - } - - if (security_str->len > 0) - g_string_truncate(security_str, security_str->len - 1); /* Chop off last space */ - - arr = nmc_dup_fields_array((const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list, - info->output_flags); - - ap_name = g_strdup_printf("AP[%d]", info->index++); /* AP */ - set_val_str(arr, 0, ap_name); - set_val_str(arr, 1, ssid_str); - set_val_str(arr, 2, ssid_hex_str); - set_val_strc(arr, 3, bssid); - set_val_strc(arr, - 4, - mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc") - : mode == NM_802_11_MODE_INFRA ? _("Infra") - : mode == NM_802_11_MODE_MESH ? _("Mesh") - : _("N/A")); - set_val_str(arr, 5, channel_str); - set_val_str(arr, 6, freq_str); - set_val_str(arr, 7, bitrate_str); - set_val_str(arr, 8, strength_str); - set_val_strc(arr, 9, sig_bars); - set_val_str(arr, 10, security_str->str); - set_val_str(arr, 11, wpa_flags_str); - set_val_str(arr, 12, rsn_flags_str); - set_val_strc(arr, 13, info->device); - set_val_strc(arr, 14, active ? _("yes") : _("no")); - set_val_strc(arr, 15, active ? "*" : " "); - set_val_strc(arr, 16, nm_object_get_path(NM_OBJECT(ap))); - - /* Set colors */ - color = wifi_signal_to_color(strength); - set_val_color_all(arr, color); - if (active) - arr[15].color = NM_META_COLOR_CONNECTION_ACTIVATED; - - g_ptr_array_add(info->output_data, arr); - - g_string_free(security_str, FALSE); -} - -static char * -bluetooth_caps_to_string(NMBluetoothCapabilities caps) -{ - char *caps_str[8]; /* Enough space for caps and terminating NULL */ - char *ret_str; - int i = 0; - - if (caps & NM_BT_CAPABILITY_DUN) - caps_str[i++] = g_strdup("DUN"); - if (caps & NM_BT_CAPABILITY_NAP) - caps_str[i++] = g_strdup("NAP"); - - if (i == 0) - caps_str[i++] = g_strdup(_("(none)")); - - caps_str[i] = NULL; - - ret_str = g_strjoinv(" ", caps_str); - - i = 0; - while (caps_str[i]) - g_free(caps_str[i++]); - - return ret_str; -} - -static char * -construct_header_name(const char *base, const char *spec) -{ - if (spec == NULL) - return g_strdup(base); - - return g_strdup_printf("%s (%s)", base, spec); -} - -static gboolean -print_bond_bridge_info(NMDevice * device, - NmCli * nmc, - const char *group_prefix, - const char *one_field) -{ - const GPtrArray * slaves = NULL; - GString * slaves_str; - int idx; - const NMMetaAbstractInfo *const *tmpl; - NmcOutputField * arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - - if (NM_IS_DEVICE_BOND(device)) - slaves = nm_device_bond_get_slaves(NM_DEVICE_BOND(device)); - else if (NM_IS_DEVICE_BRIDGE(device)) - slaves = nm_device_bridge_get_slaves(NM_DEVICE_BRIDGE(device)); - else - g_return_val_if_reached(FALSE); - - slaves_str = g_string_new(NULL); - for (idx = 0; slaves && idx < slaves->len; idx++) { - NMDevice * slave = g_ptr_array_index(slaves, idx); - const char *iface = nm_device_get_iface(slave); - - if (iface) { - g_string_append(slaves_str, iface); - g_string_append_c(slaves_str, ' '); - } - } - if (slaves_str->len > 0) - g_string_truncate(slaves_str, slaves_str->len - 1); /* Chop off last space */ - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_show_master_prop; - out_indices = parse_output_fields(one_field, tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc(arr, 0, group_prefix); /* i.e. BOND, TEAM, BRIDGE */ - set_val_str(arr, 1, slaves_str->str); - g_ptr_array_add(out.output_data, arr); - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); - - g_string_free(slaves_str, FALSE); - - return TRUE; -} - -static char * -sanitize_team_config(const char *config) -{ - char *ret; - int i; - - if (!config) - return NULL; - - ret = g_strdup(config); - - for (i = 0; i < strlen(ret); i++) { - if (ret[i] == '\n') - ret[i] = ' '; - } - - return ret; -} - -static gboolean -print_team_info(NMDevice *device, NmCli *nmc, const char *group_prefix, const char *one_field) -{ - const GPtrArray * slaves = NULL; - GString * slaves_str; - int idx; - const NMMetaAbstractInfo *const *tmpl; - NmcOutputField * arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - - if (NM_IS_DEVICE_TEAM(device)) - slaves = nm_device_team_get_slaves(NM_DEVICE_TEAM(device)); - else - g_return_val_if_reached(FALSE); - - slaves_str = g_string_new(NULL); - for (idx = 0; slaves && idx < slaves->len; idx++) { - NMDevice * slave = g_ptr_array_index(slaves, idx); - const char *iface = nm_device_get_iface(slave); - - if (iface) { - g_string_append(slaves_str, iface); - g_string_append_c(slaves_str, ' '); - } - } - if (slaves_str->len > 0) - g_string_truncate(slaves_str, slaves_str->len - 1); /* Chop off last space */ - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_show_team_prop; - out_indices = parse_output_fields(one_field, tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc(arr, 0, group_prefix); /* TEAM */ - set_val_str(arr, 1, slaves_str->str); - set_val_str(arr, 2, sanitize_team_config(nm_device_team_get_config(NM_DEVICE_TEAM(device)))); - g_ptr_array_add(out.output_data, arr); - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); - - g_string_free(slaves_str, FALSE); - - return TRUE; -} - -static gboolean -show_device_info(NMDevice *device, NmCli *nmc) -{ - GError * error = NULL; - NMDeviceState state = NM_DEVICE_STATE_UNKNOWN; - GArray * sections_array; - int k; - const char * fields_str = NULL; - const NMMetaAbstractInfo *const *tmpl; - NmcOutputField * arr; - gboolean was_output = FALSE; - NMIPConfig * cfg4, *cfg6; - NMDhcpConfig * dhcp4, *dhcp6; - const char * base_hdr = _("Device details"); - GPtrArray * fields_in_section = NULL; - - if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "common") == 0) - fields_str = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON; - else if (g_ascii_strcasecmp(nmc->required_fields, "all") == 0) { - /* pass */ - } else - fields_str = nmc->required_fields; - - sections_array = - parse_output_fields(fields_str, - (const NMMetaAbstractInfo *const *) nmc_fields_dev_show_sections, - TRUE, - &fields_in_section, - &error); - if (error) { - g_string_printf(nmc->return_text, _("Error: 'device show': %s"), error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } - - { - gs_unref_array GArray *out_indices = NULL; - gs_free char * header_name = NULL; - gs_free NmcOutputField *row = NULL; - int i; - - /* Main header (pretty only) */ - header_name = construct_header_name(base_hdr, nm_device_get_iface(device)); - - /* Lazy way to retrieve sorted array from 0 to the number of dev fields */ - out_indices = - parse_output_fields(NULL, - (const NMMetaAbstractInfo *const *) metagen_device_detail_general, - FALSE, - NULL, - NULL); - - row = g_new0(NmcOutputField, G_N_ELEMENTS(metagen_device_detail_general)); - for (i = 0; i < G_N_ELEMENTS(metagen_device_detail_general); i++) - row[i].info = (const NMMetaAbstractInfo *) &metagen_device_detail_general[i]; - - print_required_fields(&nmc->nmc_config, - &nmc->pager_data, - NMC_OF_FLAG_MAIN_HEADER_ONLY, - out_indices, - header_name, - 0, - row); - } - - /* Loop through the required sections and print them. */ - for (k = 0; k < sections_array->len; k++) { - int section_idx = g_array_index(sections_array, int, k); - char *section_fld = (char *) g_ptr_array_index(fields_in_section, k); - - if (NM_IN_SET(nmc->nmc_config.print_output, NMC_PRINT_NORMAL, NMC_PRINT_PRETTY) - && !nmc->nmc_config.multiline_output && was_output) - g_print("\n"); /* Print empty line between groups in tabular mode */ - - was_output = FALSE; - - state = nm_device_get_state(device); - - if (nmc_fields_dev_show_sections[section_idx]->nested == metagen_device_detail_general) { - gs_free char *f = section_fld ? g_strdup_printf("GENERAL.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("GENERAL", metagen_device_detail_general, N_("NAME")), - f, - NULL); - was_output = TRUE; - continue; - } - - if (nmc_fields_dev_show_sections[section_idx]->nested - == metagen_device_detail_capabilities) { - gs_free char *f = section_fld ? g_strdup_printf("CAPABILITIES.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("CAPABILITIES", - metagen_device_detail_capabilities, - N_("NAME")), - f, - NULL); - was_output = TRUE; - continue; - } - - if (nmc_fields_dev_show_sections[section_idx]->nested - == metagen_device_detail_interface_flags) { - gs_free char *f = - section_fld ? g_strdup_printf("INTERFACE-FLAGS.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("INTERFACE-FLAGS", - metagen_device_detail_interface_flags, - N_("NAME")), - f, - NULL); - was_output = TRUE; - continue; - } - - if (nmc_fields_dev_show_sections[section_idx]->nested - == metagen_device_detail_wifi_properties) { - if (NM_IS_DEVICE_WIFI(device)) { - gs_free char *f = - section_fld ? g_strdup_printf("WIFI-PROPERTIES.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("WIFI-PROPERTIES", - metagen_device_detail_wifi_properties, - N_("NAME")), - f, - NULL); - was_output = TRUE; - } - continue; - } - - /* Wireless specific information */ - if ((NM_IS_DEVICE_WIFI(device))) { - NMAccessPoint *active_ap = NULL; - const char * active_bssid = NULL; - - /* section AP */ - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[4]->name)) { - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - - if (state == NM_DEVICE_STATE_ACTIVATED) { - active_ap = nm_device_wifi_get_active_access_point(NM_DEVICE_WIFI(device)); - active_bssid = active_ap ? nm_access_point_get_bssid(active_ap) : NULL; - } - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list; - out_indices = - parse_output_fields(section_fld ?: NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST, - tmpl, - FALSE, - NULL, - NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - { - gs_unref_ptrarray GPtrArray *aps = NULL; - APInfo info = { - .nmc = nmc, - .index = 1, - .output_flags = NMC_OF_FLAG_SECTION_PREFIX, - .active_bssid = active_bssid, - .device = nm_device_get_iface(device), - .output_data = out.output_data, - }; - - aps = sort_access_points( - nm_device_wifi_get_access_points(NM_DEVICE_WIFI(device))); - g_ptr_array_foreach(aps, fill_output_access_point, &info); - } - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); - was_output = TRUE; - } - } - - if (nmc_fields_dev_show_sections[section_idx]->nested - == metagen_device_detail_wired_properties) { - if ((NM_IS_DEVICE_ETHERNET(device))) { - gs_free char *f = - section_fld ? g_strdup_printf("WIRED-PROPERTIES.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("WIRED-PROPERTIES", - metagen_device_detail_wired_properties, - N_("NAME")), - f, - NULL); - was_output = TRUE; - } - continue; - } - - /* IP configuration info */ - cfg4 = nm_device_get_ip4_config(device); - cfg6 = nm_device_get_ip6_config(device); - dhcp4 = nm_device_get_dhcp4_config(device); - dhcp6 = nm_device_get_dhcp6_config(device); - - /* IP4 */ - if (cfg4 - && !g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[8]->name)) - was_output = print_ip_config(cfg4, AF_INET, &nmc->nmc_config, section_fld); - - /* DHCP4 */ - if (dhcp4 - && !g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[9]->name)) - was_output = print_dhcp_config(dhcp4, AF_INET, &nmc->nmc_config, section_fld); - - /* IP6 */ - if (cfg6 - && !g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[10]->name)) - was_output = print_ip_config(cfg6, AF_INET6, &nmc->nmc_config, section_fld); - - /* DHCP6 */ - if (dhcp6 - && !g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[11]->name)) - was_output = print_dhcp_config(dhcp6, AF_INET6, &nmc->nmc_config, section_fld); - - /* Bond specific information */ - if (NM_IS_DEVICE_BOND(device)) { - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[12]->name)) - was_output = print_bond_bridge_info(device, - nmc, - nmc_fields_dev_show_sections[12]->name, - section_fld); - } - - /* Team specific information */ - if (NM_IS_DEVICE_TEAM(device)) { - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[13]->name)) - was_output = print_team_info(device, - nmc, - nmc_fields_dev_show_sections[13]->name, - section_fld); - } - - /* Bridge specific information */ - if (NM_IS_DEVICE_BRIDGE(device)) { - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[14]->name)) - was_output = print_bond_bridge_info(device, - nmc, - nmc_fields_dev_show_sections[14]->name, - section_fld); - } - - /* VLAN-specific information */ - if ((NM_IS_DEVICE_VLAN(device))) { - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[15]->name)) { - char *vlan_id_str = - g_strdup_printf("%u", nm_device_vlan_get_vlan_id(NM_DEVICE_VLAN(device))); - NMDevice *parent = nm_device_vlan_get_parent(NM_DEVICE_VLAN(device)); - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_show_vlan_prop; - out_indices = parse_output_fields(section_fld, tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc(arr, 0, nmc_fields_dev_show_sections[15]->name); /* "VLAN" */ - set_val_strc(arr, 1, parent ? nm_device_get_iface(parent) : NULL); - set_val_str(arr, 2, vlan_id_str); - g_ptr_array_add(out.output_data, arr); - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); - - was_output = TRUE; - } - } - - if (NM_IS_DEVICE_BT(device)) { - if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, - nmc_fields_dev_show_sections[16]->name)) { - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_show_bluetooth; - out_indices = parse_output_fields(section_fld, tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc(arr, 0, nmc_fields_dev_show_sections[16]->name); /* "BLUETOOTH" */ - set_val_str( - arr, - 1, - bluetooth_caps_to_string(nm_device_bt_get_capabilities(NM_DEVICE_BT(device)))); - g_ptr_array_add(out.output_data, arr); - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); - was_output = TRUE; - } - } - - if (nmc_fields_dev_show_sections[section_idx]->nested - == metagen_device_detail_connections) { - gs_free char *f = section_fld ? g_strdup_printf("CONNECTIONS.%s", section_fld) : NULL; - - nmc_print(&nmc->nmc_config, - (gpointer[]){device, NULL}, - NULL, - NULL, - NMC_META_GENERIC_GROUP("CONNECTIONS", - metagen_device_detail_connections, - N_("NAME")), - f, - NULL); - was_output = TRUE; - continue; - } - } - - if (sections_array) - g_array_free(sections_array, TRUE); - if (fields_in_section) - g_ptr_array_free(fields_in_section, TRUE); - - return TRUE; -} - -NMMetaColor -nmc_device_state_to_color(NMDevice *device) -{ - NMDeviceState state; - NMActiveConnection *ac; - - if (!device) - return NM_META_COLOR_DEVICE_UNKNOWN; - - ac = nm_device_get_active_connection(device); - if (ac - && NM_FLAGS_HAS(nm_active_connection_get_state_flags(ac), - NM_ACTIVATION_STATE_FLAG_EXTERNAL)) - return NM_META_COLOR_CONNECTION_EXTERNAL; - - state = nm_device_get_state(device); - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - return NM_META_COLOR_DEVICE_UNAVAILABLE; - else if (state == NM_DEVICE_STATE_DISCONNECTED) - return NM_META_COLOR_DEVICE_DISCONNECTED; - else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - return NM_META_COLOR_DEVICE_ACTIVATING; - else if (state == NM_DEVICE_STATE_ACTIVATED) - return NM_META_COLOR_DEVICE_ACTIVATED; - - return NM_META_COLOR_DEVICE_UNKNOWN; -} - -static void -do_devices_status(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - GError *error = NULL; - gs_free NMDevice **devices = NULL; - const char * fields_str = NULL; - - next_arg(nmc, &argc, &argv, NULL); - - if (nmc->complete) - return; - - if (argc) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "common") == 0) - fields_str = "DEVICE,TYPE,STATE,CONNECTION"; - else if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "all") == 0) { - /* pass */ - } else - fields_str = nmc->required_fields; - - devices = nmc_get_devices_sorted(nmc->client); - - if (!nmc_print(&nmc->nmc_config, - (gpointer *) devices, - NULL, - N_("Status of devices"), - (const NMMetaAbstractInfo *const *) metagen_device_status, - fields_str, - &error)) { - g_string_printf(nmc->return_text, _("Error: 'device status': %s"), error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } -} - -static void -do_device_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - gs_free_error GError *error = NULL; - - next_arg(nmc, &argc, &argv, NULL); - if (!nmc->mode_specified) - nmc->nmc_config_mutable.multiline_output = - TRUE; /* multiline mode is default for 'device show' */ - - if (argc) { - NMDevice *device; - - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - - if (argc) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (nmc->complete) - return; - - show_device_info(device, nmc); - } else { - NMDevice **devices = nmc_get_devices_sorted(nmc->client); - int i; - - /* nmc_do_cmd() should not call this with argc=0. */ - nm_assert(!nmc->complete); - - /* Show details for all devices */ - for (i = 0; devices[i]; i++) { - if (!show_device_info(devices[i], nmc)) - break; - if (devices[i + 1]) - g_print("\n"); /* Empty line */ - } - - g_free(devices); - } -} - -static gboolean -timeout_cb(gpointer user_data) -{ - /* Time expired -> exit nmcli */ - - NmCli *nmc = (NmCli *) user_data; - - g_string_printf(nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout); - nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED; - quit(); - return FALSE; -} - -static gboolean -progress_cb(gpointer user_data) -{ - NMDevice *device = (NMDevice *) user_data; - - nmc_terminal_show_progress(device ? gettext(nmc_device_state_to_string_with_external(device)) - : ""); - - return TRUE; -} - -typedef struct { - NmCli * nmc; - NMDevice * device; - NMActiveConnection *active; - char * specific_object; - bool hotspot : 1; - bool create : 1; -} AddAndActivateInfo; - -static AddAndActivateInfo * -add_and_activate_info_new(NmCli * nmc, - NMDevice * device, - gboolean hotspot, - gboolean create, - const char *specific_object) -{ - AddAndActivateInfo *info; - - info = g_slice_new(AddAndActivateInfo); - *info = (AddAndActivateInfo){ - .nmc = nmc, - .device = g_object_ref(device), - .hotspot = hotspot, - .create = create, - .specific_object = g_strdup(specific_object), - }; - return info; -} - -static void -add_and_activate_info_free(AddAndActivateInfo *info) -{ - g_object_unref(info->device); - g_clear_object(&info->active); - g_free(info->specific_object); - nm_g_slice_free(info); -} - -NM_AUTO_DEFINE_FCN0(AddAndActivateInfo *, - _nm_auto_free_add_and_activate_info, - add_and_activate_info_free); -#define nm_auto_free_add_and_activate_info nm_auto(_nm_auto_free_add_and_activate_info) - -static void -connected_state_cb(AddAndActivateInfo *info) -{ - NMDeviceState state; - NMDeviceStateReason reason; - NMActiveConnectionState ac_state; - - state = nm_device_get_state(info->device); - ac_state = nm_active_connection_get_state(info->active); - - if (ac_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) - return; - - if (state == NM_DEVICE_STATE_ACTIVATED) { - nmc_terminal_erase_line(); - g_print(_("Device '%s' successfully activated with '%s'.\n"), - nm_device_get_iface(info->device), - nm_active_connection_get_uuid(info->active)); - - if (info->hotspot) - g_print( - _("Hint: \"nmcli dev wifi show-password\" shows the Wi-Fi name and password.\n")); - } else if (state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) { - reason = nm_device_get_state_reason(info->device); - g_print(_("Error: Connection activation failed: (%d) %s.\n"), - reason, - gettext(nmc_device_reason_to_string(reason))); - } else { - return; - } - - g_signal_handlers_disconnect_by_func(info->active, G_CALLBACK(connected_state_cb), info); - g_signal_handlers_disconnect_by_func(info->device, G_CALLBACK(connected_state_cb), info); - add_and_activate_info_free(info); - - quit(); -} - -static void -add_and_activate_cb(GObject *client, GAsyncResult *result, gpointer user_data) -{ - nm_auto_free_add_and_activate_info AddAndActivateInfo *info = user_data; - NmCli * nmc = info->nmc; - gs_unref_object NMActiveConnection *active = NULL; - gs_free_error GError *error = NULL; - - if (info->create) - active = nm_client_add_and_activate_connection_finish(NM_CLIENT(client), result, &error); - else - active = nm_client_activate_connection_finish(NM_CLIENT(client), result, &error); - - if (error) { - if (info->hotspot) { - g_string_printf(nmc->return_text, - _("Error: Failed to setup a Wi-Fi hotspot: %s"), - error->message); - } else if (info->create) { - g_string_printf(nmc->return_text, - _("Error: Failed to add/activate new connection: %s"), - error->message); - } else { - g_string_printf(nmc->return_text, - _("Error: Failed to activate connection: %s"), - error->message); - } - nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; - quit(); - return; - } - - if (nmc->nowait_flag) { - quit(); - return; - } - - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - progress_id = g_timeout_add(120, progress_cb, info->device); - - info->active = g_steal_pointer(&active); - g_signal_connect_swapped(info->device, "notify::state", G_CALLBACK(connected_state_cb), info); - g_signal_connect_swapped(info->active, "notify::state", G_CALLBACK(connected_state_cb), info); - connected_state_cb(g_steal_pointer(&info)); - - g_timeout_add_seconds(nmc->timeout, timeout_cb, nmc); /* Exit if timeout expires */ -} - -static void -create_connect_connection_for_device(AddAndActivateInfo *info) -{ - NMConnection * connection; - NMSettingConnection *s_con; - - /* Create new connection and tie it to the device */ - connection = nm_simple_connection_new(); - s_con = (NMSettingConnection *) nm_setting_connection_new(); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - g_object_set(s_con, NM_SETTING_CONNECTION_ID, nm_device_get_iface(info->device), NULL); - - nm_client_add_and_activate_connection_async(info->nmc->client, - connection, - info->device, - NULL, - NULL, - add_and_activate_cb, - info); -} - -static void -connect_device_cb(GObject *client, GAsyncResult *result, gpointer user_data) -{ - nm_auto_free_add_and_activate_info AddAndActivateInfo *info = user_data; - NmCli * nmc = info->nmc; - gs_unref_object NMActiveConnection *active = NULL; - GError * error = NULL; - - active = nm_client_activate_connection_finish(NM_CLIENT(client), result, &error); - - if (error) { - /* If no connection existed for the device, create one and activate it */ - if (g_error_matches(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION)) { - info->create = TRUE; - create_connect_connection_for_device(g_steal_pointer(&info)); - return; - } - - g_string_printf(nmc->return_text, _("Error: Device activation failed: %s"), error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; - quit(); - return; - } - - nm_assert(NM_IS_ACTIVE_CONNECTION(active)); - - if (nmc->nowait_flag) { - quit(); - return; - } - - if (nmc->secret_agent) { - NMRemoteConnection *connection = nm_active_connection_get_connection(active); - - nm_secret_agent_simple_enable(nmc->secret_agent, - nm_connection_get_path(NM_CONNECTION(connection))); - } - - info->active = g_steal_pointer(&active); - g_signal_connect_swapped(info->device, "notify::state", G_CALLBACK(connected_state_cb), info); - g_signal_connect_swapped(info->active, "notify::state", G_CALLBACK(connected_state_cb), info); - connected_state_cb(g_steal_pointer(&info)); - - /* Start timer not to loop forever if "notify::state" signal is not issued */ - g_timeout_add_seconds(nmc->timeout, timeout_cb, nmc); -} - -static void -do_device_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device = NULL; - AddAndActivateInfo *info; - gs_free_error GError *error = NULL; - - /* Set default timeout for connect operation. */ - if (nmc->timeout == -1) - nmc->timeout = 90; - - next_arg(nmc, &argc, &argv, NULL); - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - - if (*argv) { - g_string_printf(nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (nmc->complete) - return; - - /* - * Use nowait_flag instead of should_wait, because exiting has to be postponed - * till connect_device_cb() is called, giving NM time to check our permissions. - */ - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - /* Create secret agent */ - nmc->secret_agent = nm_secret_agent_simple_new("nmcli-connect"); - if (nmc->secret_agent) { - g_signal_connect(nmc->secret_agent, - NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, - G_CALLBACK(nmc_secrets_requested), - nmc); - } - - info = add_and_activate_info_new(nmc, device, FALSE, FALSE, NULL); - - nm_client_activate_connection_async(nmc->client, - NULL, /* let NM find a connection automatically */ - device, - NULL, - NULL, - connect_device_cb, - info); - - /* Start progress indication */ - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - progress_id = g_timeout_add(120, progress_cb, device); -} - -typedef struct { - NmCli * nmc; - GSList * queue; - guint timeout_id; - gboolean cmd_disconnect; - GCancellable *cancellable; -} DeviceCbInfo; - -static void device_cb_info_finish(DeviceCbInfo *info, NMDevice *device); - -static gboolean -device_op_timeout_cb(gpointer user_data) -{ - DeviceCbInfo *info = user_data; - - timeout_cb(info->nmc); - device_cb_info_finish(info, NULL); - return G_SOURCE_REMOVE; -} - -static void -device_removed_cb(NMClient *client, NMDevice *device, DeviceCbInfo *info) -{ - /* Success: device has been removed. - * It can also happen when disconnecting a software device. - */ - if (!g_slist_find(info->queue, device)) - return; - - if (info->cmd_disconnect) - g_print(_("Device '%s' successfully disconnected.\n"), nm_device_get_iface(device)); - else - g_print(_("Device '%s' successfully removed.\n"), nm_device_get_iface(device)); - device_cb_info_finish(info, device); -} - -static void -disconnect_state_cb(NMDevice *device, GParamSpec *pspec, DeviceCbInfo *info) -{ - if (!g_slist_find(info->queue, device)) - return; - - if (nm_device_get_state(device) <= NM_DEVICE_STATE_DISCONNECTED) { - g_print(_("Device '%s' successfully disconnected.\n"), nm_device_get_iface(device)); - device_cb_info_finish(info, device); - } -} - -static void -destroy_queue_element(gpointer data) -{ - g_signal_handlers_disconnect_matched(data, - G_SIGNAL_MATCH_FUNC, - 0, - 0, - 0, - disconnect_state_cb, - NULL); - g_object_unref(data); -} - -static void -device_cb_info_finish(DeviceCbInfo *info, NMDevice *device) -{ - if (device) { - GSList *elem = g_slist_find(info->queue, device); - if (!elem) - return; - info->queue = g_slist_delete_link(info->queue, elem); - destroy_queue_element(device); - } else { - g_slist_free_full(info->queue, destroy_queue_element); - info->queue = NULL; - } - - if (info->queue) - return; - - if (info->timeout_id) - g_source_remove(info->timeout_id); - - g_signal_handlers_disconnect_by_func(info->nmc->client, device_removed_cb, info); - nm_clear_g_cancellable(&info->cancellable); - - g_slice_free(DeviceCbInfo, info); - quit(); -} - -static void -reapply_device_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(object); - DeviceCbInfo *info = (DeviceCbInfo *) user_data; - NmCli * nmc = info->nmc; - GError * error = NULL; - - if (!nm_device_reapply_finish(device, result, &error)) { - g_string_printf(nmc->return_text, - _("Error: Reapplying connection to device '%s' (%s) failed: %s"), - nm_device_get_iface(device), - nm_object_get_path(NM_OBJECT(device)), - error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; - device_cb_info_finish(info, device); - } else { - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - nmc_terminal_erase_line(); - g_print(_("Connection successfully reapplied to device '%s'.\n"), - nm_device_get_iface(device)); - device_cb_info_finish(info, device); - } -} - -static void -do_device_reapply(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device; - DeviceCbInfo *info = NULL; - gs_free_error GError *error = NULL; - - /* Set default timeout for reapply operation. */ - if (nmc->timeout == -1) - nmc->timeout = 10; - - next_arg(nmc, &argc, &argv, NULL); - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - - if (argc) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (nmc->complete) - return; - - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - info = g_slice_new0(DeviceCbInfo); - info->nmc = nmc; - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); - - /* Now reapply the connection to the device */ - nm_device_reapply_async(device, NULL, 0, 0, NULL, reapply_device_cb, info); -} - -typedef struct { - NmCli *nmc; - int argc; - char **argv; -} ModifyInfo; - -static void -modify_info_free(ModifyInfo *info) -{ - g_strfreev(info->argv); - nm_g_slice_free(info); -} - -NM_AUTO_DEFINE_FCN_VOID0(ModifyInfo *, _auto_free_modify_info, modify_info_free); - -static void -modify_reapply_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(object); - nm_auto(_auto_free_modify_info) ModifyInfo *info = user_data; - NmCli * nmc = info->nmc; - GError * error = NULL; - - if (!nm_device_reapply_finish(device, result, &error)) { - g_string_printf(nmc->return_text, - _("Error: Reapplying connection to device '%s' (%s) failed: %s"), - nm_device_get_iface(device), - nm_object_get_path(NM_OBJECT(device)), - error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; - } else { - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - nmc_terminal_erase_line(); - g_print(_("Connection successfully reapplied to device '%s'.\n"), - nm_device_get_iface(device)); - } - - quit(); -} - -static void -modify_get_applied_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(object); - nm_auto(_auto_free_modify_info) ModifyInfo *info = user_data; - NmCli * nmc = info->nmc; - gs_free_error GError *error = NULL; - NMConnection * connection; - guint64 version_id; - int argc; - const char *const * argv; - - connection = nm_device_get_applied_connection_finish(device, result, &version_id, &error); - if (!connection) { - g_string_printf(nmc->return_text, - _("Error: Reading applied connection from device '%s' (%s) failed: %s"), - nm_device_get_iface(device), - nm_object_get_path(NM_OBJECT(device)), - error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - quit(); - return; - } - - argc = info->argc; - argv = (const char *const *) info->argv; - - if (!nmc_process_connection_properties(info->nmc, connection, &argc, &argv, TRUE, &error)) { - g_string_assign(nmc->return_text, error->message); - nmc->return_value = error->code; - quit(); - return; - } - - if (nmc->complete) { - quit(); - return; - } - - nm_device_reapply_async(device, - connection, - version_id, - 0, - NULL, - modify_reapply_cb, - g_steal_pointer(&info)); -} - -static void -do_device_modify(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device = NULL; - ModifyInfo * info; - gs_free_error GError *error = NULL; - - next_arg(nmc, &argc, &argv, NULL); - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - - if (nmc->timeout == -1) - nmc->timeout = 10; - - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - info = g_slice_new(ModifyInfo); - *info = (ModifyInfo){ - .nmc = nmc, - .argc = argc, - .argv = nm_utils_strv_dup(argv, argc, TRUE), - }; - - nm_device_get_applied_connection_async(device, 0, NULL, modify_get_applied_cb, info); -} - -static void -disconnect_device_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(object); - DeviceCbInfo *info = (DeviceCbInfo *) user_data; - NmCli * nmc; - NMDeviceState state; - GError * error = NULL; - - if (!nm_device_disconnect_finish(device, result, &error)) { - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - nmc = info->nmc; - g_string_printf(nmc->return_text, _("Error: not all devices disconnected.")); - g_printerr(_("Error: Device '%s' (%s) disconnecting failed: %s\n"), - nm_device_get_iface(device), - nm_object_get_path(NM_OBJECT(device)), - error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; - device_cb_info_finish(info, device); - } else { - nmc = info->nmc; - state = nm_device_get_state(device); - if (nmc->nowait_flag || state <= NM_DEVICE_STATE_DISCONNECTED) { - /* Don't want to wait or device already disconnected */ - if (state <= NM_DEVICE_STATE_DISCONNECTED) { - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - nmc_terminal_erase_line(); - g_print(_("Device '%s' successfully disconnected.\n"), nm_device_get_iface(device)); - } - device_cb_info_finish(info, device); - } - } -} - -static void -do_devices_disconnect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device; - DeviceCbInfo *info = NULL; - GSList * queue, *iter; - - /* Set default timeout for disconnect operation. */ - if (nmc->timeout == -1) - nmc->timeout = 10; - - next_arg(nmc, &argc, &argv, NULL); - queue = get_device_list(nmc, argc, argv); - if (!queue) - return; - if (nmc->complete) - goto out; - queue = g_slist_reverse(queue); - - info = g_slice_new0(DeviceCbInfo); - info->nmc = nmc; - info->cmd_disconnect = TRUE; - info->cancellable = g_cancellable_new(); - if (nmc->timeout > 0) - info->timeout_id = g_timeout_add_seconds(nmc->timeout, device_op_timeout_cb, info); - - g_signal_connect(nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK(device_removed_cb), info); - - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - for (iter = queue; iter; iter = g_slist_next(iter)) { - device = iter->data; - - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); - g_signal_connect(device, "notify::" NM_DEVICE_STATE, G_CALLBACK(disconnect_state_cb), info); - - /* Now disconnect the device */ - nm_device_disconnect_async(device, info->cancellable, disconnect_device_cb, info); - } - -out: - g_slist_free(queue); -} - -static void -delete_device_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(object); - DeviceCbInfo *info = (DeviceCbInfo *) user_data; - NmCli * nmc = info->nmc; - GError * error = NULL; - - if (!nm_device_delete_finish(device, result, &error)) { - g_string_printf(nmc->return_text, _("Error: not all devices deleted.")); - g_printerr(_("Error: Device '%s' (%s) deletion failed: %s\n"), - nm_device_get_iface(device), - nm_object_get_path(NM_OBJECT(device)), - error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - device_cb_info_finish(info, device); - } else { - g_print(_("Device '%s' successfully removed.\n"), nm_device_get_iface(device)); - device_cb_info_finish(info, device); - } -} - -static void -do_devices_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device; - DeviceCbInfo *info = NULL; - GSList * queue, *iter; - - /* Set default timeout for delete operation. */ - if (nmc->timeout == -1) - nmc->timeout = 10; - - next_arg(nmc, &argc, &argv, NULL); - queue = get_device_list(nmc, argc, argv); - if (!queue) - return; - if (nmc->complete) - goto out; - queue = g_slist_reverse(queue); - - info = g_slice_new0(DeviceCbInfo); - info->nmc = nmc; - if (nmc->timeout > 0) - info->timeout_id = g_timeout_add_seconds(nmc->timeout, device_op_timeout_cb, info); - - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - for (iter = queue; iter; iter = g_slist_next(iter)) { - device = iter->data; - - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); - - /* Now delete the device */ - nm_device_delete_async(device, NULL, delete_device_cb, info); - } - -out: - g_slist_free(queue); -} - -static void -do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ -#define DEV_SET_AUTOCONNECT 0 -#define DEV_SET_MANAGED 1 - NMDevice *device = NULL; - int i; - struct { - int idx; - gboolean value; - } values[2] = { - [DEV_SET_AUTOCONNECT] = {-1}, - [DEV_SET_MANAGED] = {-1}, - }; - gs_free_error GError *error = NULL; - - next_arg(nmc, &argc, &argv, NULL); - if (argc >= 1 && g_strcmp0(*argv, "ifname") == 0) - next_arg(nmc, &argc, &argv, NULL); - - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - - if (!argc) { - g_string_printf(nmc->return_text, _("Error: No property specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - i = 0; - do { - gboolean flag; - - if (argc == 1 && nmc->complete) - nmc_complete_strings(*argv, "managed", "autoconnect"); - - if (matches(*argv, "managed")) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, - _("Error: '%s' argument is missing."), - *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - if (argc == 1 && nmc->complete) - nmc_complete_bool(*argv); - if (!nmc_string_to_bool(*argv, &flag, &error)) { - g_string_printf(nmc->return_text, _("Error: 'managed': %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - values[DEV_SET_MANAGED].idx = ++i; - values[DEV_SET_MANAGED].value = flag; - } else if (matches(*argv, "autoconnect")) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, - _("Error: '%s' argument is missing."), - *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - if (argc == 1 && nmc->complete) - nmc_complete_bool(*argv); - if (!nmc_string_to_bool(*argv, &flag, &error)) { - g_string_printf(nmc->return_text, _("Error: 'autoconnect': %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - values[DEV_SET_AUTOCONNECT].idx = ++i; - values[DEV_SET_AUTOCONNECT].value = flag; - } else { - g_string_printf(nmc->return_text, _("Error: property '%s' is not known."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - } while (next_arg(nmc, &argc, &argv, NULL) == 0); - - if (nmc->complete) - return; - - /* when multiple properties are specified, set them in the order as they - * are specified on the command line. */ - if (values[DEV_SET_AUTOCONNECT].idx >= 0 && values[DEV_SET_MANAGED].idx >= 0 - && values[DEV_SET_MANAGED].idx < values[DEV_SET_AUTOCONNECT].idx) { - nm_device_set_managed(device, values[DEV_SET_MANAGED].value); - values[DEV_SET_MANAGED].idx = -1; - } - if (values[DEV_SET_AUTOCONNECT].idx >= 0) - nm_device_set_autoconnect(device, values[DEV_SET_AUTOCONNECT].value); - if (values[DEV_SET_MANAGED].idx >= 0) - nm_device_set_managed(device, values[DEV_SET_MANAGED].value); -} - -static void -device_state(NMDevice *device, GParamSpec *pspec, NmCli *nmc) -{ - gs_free char *str = NULL; - NMMetaColor color; - - color = nmc_device_state_to_color(device); - str = nmc_colorize(&nmc->nmc_config, - color, - "%s: %s\n", - nm_device_get_iface(device), - gettext(nmc_device_state_to_string_with_external(device))); - - g_print("%s", str); -} - -static void -device_ac(NMDevice *device, GParamSpec *pspec, NmCli *nmc) -{ - NMActiveConnection *ac = nm_device_get_active_connection(device); - const char * id = ac ? nm_active_connection_get_id(ac) : NULL; - - if (!id) - return; - - g_print(_("%s: using connection '%s'\n"), nm_device_get_iface(device), id); -} - -static void -device_watch(NmCli *nmc, NMDevice *device) -{ - nmc->should_wait++; - g_signal_connect(device, "notify::" NM_DEVICE_STATE, G_CALLBACK(device_state), nmc); - g_signal_connect(device, "notify::" NM_DEVICE_ACTIVE_CONNECTION, G_CALLBACK(device_ac), nmc); -} - -static void -device_unwatch(NmCli *nmc, NMDevice *device) -{ - g_signal_handlers_disconnect_by_func(device, device_state, nmc); - if (g_signal_handlers_disconnect_by_func(device, device_ac, nmc)) - nmc->should_wait--; - - /* Terminate if all the watched devices disappeared. */ - if (!nmc->should_wait) - quit(); -} - -static void -device_added(NMClient *client, NMDevice *device, NmCli *nmc) -{ - g_print(_("%s: device created\n"), nm_device_get_iface(device)); - device_watch(nmc, NM_DEVICE(device)); -} - -static void -device_removed(NMClient *client, NMDevice *device, NmCli *nmc) -{ - g_print(_("%s: device removed\n"), nm_device_get_iface(device)); - device_unwatch(nmc, device); -} - -static void -do_devices_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - if (nmc->complete) - return; - - next_arg(nmc, &argc, &argv, NULL); - if (argc == 0) { - /* No devices specified. Monitor all. */ - const GPtrArray *devices = nm_client_get_devices(nmc->client); - int i; - - for (i = 0; i < devices->len; i++) - device_watch(nmc, g_ptr_array_index(devices, i)); - - /* We'll watch the device additions too, never exit. */ - nmc->should_wait++; - g_signal_connect(nmc->client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK(device_added), nmc); - } else { - GSList *queue = get_device_list(nmc, argc, argv); - GSList *iter; - - /* Monitor the specified devices. */ - for (iter = queue; iter; iter = g_slist_next(iter)) - device_watch(nmc, NM_DEVICE(iter->data)); - g_slist_free(queue); - } - - g_signal_connect(nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK(device_removed), nmc); -} - -/* - * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL, - * the first Wi-Fi device is returned. 'idx' parameter is updated to the point - * where the function finished so that the function can be called repeatedly - * to get next matching device. - * Returns: found device or NULL - */ -static NMDevice * -find_wifi_device_by_iface(NMDevice **devices, const char *iface, int *idx) -{ - int i; - - for (i = idx ? *idx : 0; devices[i]; i++) { - const char *dev_iface = nm_device_get_iface(devices[i]); - - if (!NM_IS_DEVICE_WIFI(devices[i])) - continue; - - if (iface) { - /* If a iface was specified then use it. */ - if (g_strcmp0(dev_iface, iface) == 0) - break; - } else { - /* Else return the first Wi-Fi device. */ - break; - } - } - - if (idx) - *idx = i + 1; - return devices[i]; -} - -/* - * Find AP on 'device' according to 'bssid' and 'ssid' parameters. - * Returns: found AP or NULL - */ -static NMAccessPoint * -find_ap_on_device(NMDevice *device, const char *bssid, const char *ssid, gboolean complete) -{ - const GPtrArray *aps; - NMAccessPoint * ap = NULL; - int i; - - g_return_val_if_fail(NM_IS_DEVICE_WIFI(device), NULL); - - aps = nm_device_wifi_get_access_points(NM_DEVICE_WIFI(device)); - for (i = 0; i < aps->len; i++) { - NMAccessPoint *candidate_ap = g_ptr_array_index(aps, i); - - if (bssid) { - const char *candidate_bssid = nm_access_point_get_bssid(candidate_ap); - - if (!candidate_bssid) - continue; - - /* Compare BSSIDs */ - if (complete) { - if (g_str_has_prefix(candidate_bssid, bssid)) - g_print("%s\n", candidate_bssid); - } else if (strcmp(bssid, candidate_bssid) != 0) - continue; - } - - if (ssid) { - /* Parameter is SSID */ - GBytes *candidate_ssid; - char * ssid_tmp; - - candidate_ssid = nm_access_point_get_ssid(candidate_ap); - if (!candidate_ssid) - continue; - - ssid_tmp = nm_utils_ssid_to_utf8(g_bytes_get_data(candidate_ssid, NULL), - g_bytes_get_size(candidate_ssid)); - - /* Compare SSIDs */ - if (complete) { - if (g_str_has_prefix(ssid_tmp, ssid)) - g_print("%s\n", ssid_tmp); - } else if (strcmp(ssid, ssid_tmp) != 0) { - g_free(ssid_tmp); - continue; - } - g_free(ssid_tmp); - } - - if (complete) - continue; - - ap = candidate_ap; - break; - } - - return ap; -} - -static void -show_access_point_info(NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out) -{ - NMAccessPoint * active_ap = NULL; - const char * active_bssid = NULL; - NmcOutputField *arr; - - if (nm_device_get_state(NM_DEVICE(wifi)) == NM_DEVICE_STATE_ACTIVATED) { - active_ap = nm_device_wifi_get_active_access_point(wifi); - active_bssid = active_ap ? nm_access_point_get_bssid(active_ap) : NULL; - } - - arr = nmc_dup_fields_array((const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list, - NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out->output_data, arr); - - { - gs_unref_ptrarray GPtrArray *aps = NULL; - APInfo info = { - .nmc = nmc, - .index = 1, - .output_flags = 0, - .active_bssid = active_bssid, - .device = nm_device_get_iface(NM_DEVICE(wifi)), - .output_data = out->output_data, - }; - - aps = sort_access_points(nm_device_wifi_get_access_points(wifi)); - g_ptr_array_foreach(aps, fill_output_access_point, &info); - } - - print_data_prepare_width(out->output_data); -} - -static void -wifi_print_aps(NMDeviceWifi * wifi, - NmCli * nmc, - GArray * _out_indices, - const NMMetaAbstractInfo *const *tmpl, - const char * bssid_user, - gboolean * bssid_found) -{ - NMAccessPoint * ap = NULL; - const GPtrArray *aps; - APInfo * info; - guint i; - NmcOutputField * arr; - const char * base_hdr = _("Wi-Fi scan list"); - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - gs_free char * header_name = NULL; - static gboolean empty_line = FALSE; - - if (empty_line) - g_print("\n"); /* Empty line between devices' APs */ - - /* Main header name */ - header_name = construct_header_name(base_hdr, nm_device_get_iface(NM_DEVICE(wifi))); - - out_indices = g_array_ref(_out_indices); - - if (bssid_user) { - /* Specific AP requested - list only that */ - aps = nm_device_wifi_get_access_points(wifi); - for (i = 0; i < aps->len; i++) { - NMAccessPoint *candidate_ap = g_ptr_array_index(aps, i); - - if (nm_utils_hwaddr_matches(bssid_user, - -1, - nm_access_point_get_bssid(candidate_ap), - -1)) - ap = candidate_ap; - } - if (ap) { - /* Add headers (field names) */ - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - info = g_malloc0(sizeof(APInfo)); - info->nmc = nmc; - info->index = 1; - info->output_flags = 0; - info->active_bssid = NULL; - info->device = nm_device_get_iface(NM_DEVICE(wifi)); - info->output_data = out.output_data; - - fill_output_access_point(ap, info); - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); - g_free(info); - - *bssid_found = TRUE; - empty_line = TRUE; - } - } else { - show_access_point_info(wifi, nmc, &out); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); - empty_line = TRUE; - } -} - -static gint64 -_device_wifi_get_last_scan(NMDeviceWifi *wifi) -{ - gint64 timestamp; - - timestamp = nm_device_wifi_get_last_scan(wifi); - if (timestamp == -1) - return G_MININT64; - return timestamp; -} - -typedef struct { - NmCli * nmc; - NMDevice ** devices; - const NMMetaAbstractInfo *const *tmpl; - char * bssid_user; - GArray * out_indices; - gint64 rescan_cutoff_msec; - guint pending; -} ScanInfo; - -typedef struct { - ScanInfo * scan_info; - NMDeviceWifi *wifi; - gulong last_scan_id; - guint timeout_id; - GCancellable *scan_cancellable; -} WifiListData; - -static void -wifi_list_finish(WifiListData *wifi_list_data, gboolean force_finished) -{ - ScanInfo *scan_info = wifi_list_data->scan_info; - NmCli * nmc = scan_info->nmc; - gboolean bssid_found = FALSE; - guint i; - - if (!force_finished - && scan_info->rescan_cutoff_msec > _device_wifi_get_last_scan(wifi_list_data->wifi)) { - /* wait longer... */ - return; - } - - nm_clear_g_signal_handler(wifi_list_data->wifi, &wifi_list_data->last_scan_id); - nm_clear_g_source(&wifi_list_data->timeout_id); - nm_clear_g_cancellable(&wifi_list_data->scan_cancellable); - nm_g_slice_free(wifi_list_data); - - if (--scan_info->pending > 0) - return; - - for (i = 0; scan_info->devices[i]; i++) { - wifi_print_aps(NM_DEVICE_WIFI(scan_info->devices[i]), - nmc, - scan_info->out_indices, - scan_info->tmpl, - scan_info->bssid_user, - &bssid_found); - } - - if (scan_info->bssid_user && !bssid_found) { - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - g_string_printf(nmc->return_text, - _("Error: Access point with bssid '%s' not found."), - scan_info->bssid_user); - } - - for (i = 0; scan_info->devices[i]; i++) - g_object_unref(scan_info->devices[i]); - g_free(scan_info->devices); - g_array_unref(scan_info->out_indices); - g_free(scan_info->bssid_user); - nm_g_slice_free(scan_info); - - nmc->should_wait--; - g_main_loop_quit(loop); -} - -static void -wifi_last_scan_updated(GObject *gobject, GParamSpec *pspec, gpointer user_data) -{ - wifi_list_finish(user_data, FALSE); -} - -static void wifi_list_rescan_cb(GObject *source_object, GAsyncResult *res, gpointer user_data); - -static void -wifi_list_rescan_retry_cb(gpointer user_data, GCancellable *cancellable) -{ - WifiListData *wifi_list_data; - - if (g_cancellable_is_cancelled(cancellable)) - return; - - wifi_list_data = user_data; - nm_device_wifi_request_scan_async(wifi_list_data->wifi, - wifi_list_data->scan_cancellable, - wifi_list_rescan_cb, - wifi_list_data); -} - -static void -wifi_list_rescan_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMDeviceWifi *wifi = NM_DEVICE_WIFI(source_object); - gs_free_error GError *error = NULL; - WifiListData * wifi_list_data; - gboolean force_finished; - gboolean done; - - nm_device_wifi_request_scan_finish(wifi, res, &error); - if (nm_utils_error_is_cancelled(error)) - return; - - wifi_list_data = user_data; - - if (g_error_matches(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) { - if (nm_device_get_state(NM_DEVICE(wifi)) < NM_DEVICE_STATE_DISCONNECTED) { - /* the device is either unmanaged or unavailable. - * - * If it's unmanaged, we don't expect any scan result and are done. - * If it's unavailable, that usually means that we wait for wpa_supplicant - * to start. In that case, also quit (without scan results). */ - force_finished = TRUE; - done = TRUE; - } else { - /* This likely means that scanning is already in progress. There's - * a good chance we'll get updated results soon; wait for them. - * - * But also, NetworkManager ratelimits (and rejects requests). That - * means, possibly we were just ratelimited, so waiting will not lead - * to a new scan result. Instead, repeatedly ask new scans... */ - nm_utils_invoke_on_timeout(1000, - wifi_list_data->scan_cancellable, - wifi_list_rescan_retry_cb, - wifi_list_data); - force_finished = FALSE; - done = FALSE; - } - } else if (error) { - force_finished = TRUE; - done = TRUE; - } else { - force_finished = FALSE; - done = TRUE; - } - - if (done) - g_clear_object(&wifi_list_data->scan_cancellable); - wifi_list_finish(wifi_list_data, force_finished); -} - -static gboolean -wifi_list_scan_timeout(gpointer user_data) -{ - WifiListData *wifi_list_data = user_data; - - wifi_list_data->timeout_id = 0; - wifi_list_finish(user_data, TRUE); - return G_SOURCE_REMOVE; -} - -static void -complete_aps(NMDevice ** devices, - const char *ifname, - const char *bssid_prefix, - const char *ssid_prefix) -{ - int devices_idx = 0; - NMDevice *device; - - while ((device = find_wifi_device_by_iface(devices, ifname, &devices_idx))) - find_ap_on_device(device, bssid_prefix, ssid_prefix, TRUE); -} - -void -nmc_complete_bssid(NMClient *client, const char *ifname, const char *bssid_prefix) -{ - gs_free NMDevice **devices = NULL; - - devices = nmc_get_devices_sorted(client); - complete_aps(devices, ifname, bssid_prefix, NULL); -} - -static void -do_device_wifi_list(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - GError * error = NULL; - NMDevice * device = NULL; - const char *ifname = NULL; - const char *bssid_user = NULL; - const char *rescan = NULL; - gs_free NMDevice ** devices = NULL; - const char * fields_str = NULL; - const NMMetaAbstractInfo *const *tmpl; - gs_unref_array GArray *out_indices = NULL; - int option; - gint64 rescan_cutoff_msec; - ScanInfo * scan_info = NULL; - gboolean ifname_handled; - NMDevice * ifname_handled_candidate; - guint i, j; - - devices = nmc_get_devices_sorted(nmc->client); - - while ((option = next_arg(nmc, &argc, &argv, "ifname", "hwaddr", "bssid", "--rescan", NULL)) - > 0) { - switch (option) { - case 1: /* ifname */ - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - ifname = *argv; - if (argc == 1 && nmc->complete) - complete_device(devices, ifname, TRUE); - break; - case 2: /* hwaddr is deprecated and will be removed later */ - case 3: /* bssid */ - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - bssid_user = *argv; - if (argc == 1 && nmc->complete) - complete_aps(devices, NULL, bssid_user, NULL); - break; - case 4: /* --rescan */ - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - rescan = *argv; - if (argc == 1 && nmc->complete) - nmc_complete_strings(rescan, "auto", "no", "yes"); - break; - default: - nm_assert_not_reached(); - break; - } - } - - if (nmc->complete) - return; - - if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "common") == 0) - fields_str = NMC_FIELDS_DEV_WIFI_LIST_COMMON; - else if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "all") == 0) { - /* pass */ - } else - fields_str = nmc->required_fields; - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list; - out_indices = parse_output_fields(fields_str, tmpl, FALSE, NULL, &error); - - if (error) { - g_string_printf(nmc->return_text, _("Error: 'device wifi': %s"), error->message); - g_error_free(error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (argc) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (NM_IN_STRSET(rescan, NULL, "auto")) - rescan_cutoff_msec = nm_utils_get_timestamp_msec() - (30 * NM_UTILS_MSEC_PER_SEC); - else if (nm_streq(rescan, "no")) - rescan_cutoff_msec = G_MININT64; - else if (nm_streq(rescan, "yes")) - rescan_cutoff_msec = nm_utils_get_timestamp_msec(); - else { - g_string_printf(nmc->return_text, - _("Error: invalid rescan argument: '%s' not among [auto, no, yes]"), - rescan); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - ifname_handled = (ifname == NULL); - ifname_handled_candidate = NULL; - - j = 0; - for (i = 0; devices[i]; i++) { - const char *dev_iface; - - device = devices[i]; - dev_iface = nm_device_get_iface(device); - - if (ifname) { - if (!nm_streq0(ifname, dev_iface)) - continue; - if (!NM_IS_DEVICE_WIFI(device)) { - if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_GENERIC - && nm_streq0(nm_device_get_type_description(device), "wifi")) - ifname_handled_candidate = device; - else if (!ifname_handled_candidate) - ifname_handled_candidate = device; - continue; - } - ifname_handled = TRUE; - } else { - if (!NM_IS_DEVICE_WIFI(device)) - continue; - } - - devices[j++] = device; - } - devices[j] = NULL; - - if (!ifname_handled) { - if (!ifname_handled_candidate) { - g_string_printf(nmc->return_text, _("Error: Device '%s' not found."), ifname); - } else if (nm_device_get_device_type(ifname_handled_candidate) == NM_DEVICE_TYPE_GENERIC - && nm_streq0(nm_device_get_type_description(ifname_handled_candidate), "wifi")) { - g_string_printf(nmc->return_text, - _("Error: Device '%s' was not recognized as a Wi-Fi device, check " - "NetworkManager Wi-Fi plugin."), - ifname); - } else { - g_string_printf(nmc->return_text, - _("Error: Device '%s' is not a Wi-Fi device."), - ifname); - } - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - return; - } - - if (!devices[0]) { - if (bssid_user) { - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - g_string_printf(nmc->return_text, - _("Error: Access point with bssid '%s' not found."), - bssid_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - } - return; - } - - scan_info = g_slice_new(ScanInfo); - *scan_info = (ScanInfo){ - .out_indices = g_array_ref(out_indices), - .tmpl = tmpl, - .bssid_user = g_strdup(bssid_user), - .nmc = nmc, - .rescan_cutoff_msec = rescan_cutoff_msec, - }; - - for (i = 0; devices[i]; i++) - g_object_ref(devices[i]); - - for (i = 0; devices[i]; i++) { - NMDeviceWifi *wifi = NM_DEVICE_WIFI(devices[i]); - WifiListData *wifi_list_data; - int timeout_msec; - - if (rescan_cutoff_msec <= _device_wifi_get_last_scan(wifi)) - timeout_msec = 0; - else - timeout_msec = 15000; - - wifi_list_data = g_slice_new(WifiListData); - *wifi_list_data = (WifiListData){ - .wifi = wifi, - .scan_info = scan_info, - .timeout_id = g_timeout_add(timeout_msec, wifi_list_scan_timeout, wifi_list_data), - }; - - scan_info->pending++; - - if (timeout_msec > 0) { - wifi_list_data->last_scan_id = g_signal_connect(wifi, - "notify::" NM_DEVICE_WIFI_LAST_SCAN, - G_CALLBACK(wifi_last_scan_updated), - wifi_list_data), - wifi_list_data->scan_cancellable = g_cancellable_new(), - nm_device_wifi_request_scan_async(wifi, - wifi_list_data->scan_cancellable, - wifi_list_rescan_cb, - wifi_list_data); - } - } - - scan_info->devices = g_steal_pointer(&devices); - - nmc->should_wait++; -} - -static void -activate_update2_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMRemoteConnection *remote_con = NM_REMOTE_CONNECTION(source_object); - AddAndActivateInfo *info = user_data; - NmCli * nmc = info->nmc; - gs_unref_variant GVariant *ret = NULL; - GError * error = NULL; - - ret = nm_remote_connection_update2_finish(remote_con, res, &error); - - if (!ret) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - g_error_free(error); - quit(); - add_and_activate_info_free(info); - return; - } - - nm_client_activate_connection_async(nmc->client, - NM_CONNECTION(remote_con), - info->device, - info->specific_object, - NULL, - add_and_activate_cb, - info); -} - -static void -save_and_activate_connection(NmCli * nmc, - NMDevice * device, - NMConnection *connection, - gboolean hotspot, - const char * specific_object) -{ - AddAndActivateInfo *info; - - info = add_and_activate_info_new(nmc, - device, - hotspot, - !NM_IS_REMOTE_CONNECTION(connection), - specific_object); - - if (NM_IS_REMOTE_CONNECTION(connection)) { - nm_remote_connection_update2(NM_REMOTE_CONNECTION(connection), - nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), - NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT, - NULL, - NULL, - activate_update2_cb, - info); - } else { - nm_client_add_and_activate_connection_async(nmc->client, - connection, - info->device, - info->specific_object, - NULL, - add_and_activate_cb, - info); - } -} - -static void -do_device_wifi_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device = NULL; - NMAccessPoint * ap = NULL; - NM80211ApFlags ap_flags; - NM80211ApSecurityFlags ap_wpa_flags; - NM80211ApSecurityFlags ap_rsn_flags; - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingWireless * s_wifi; - const char * param_user = NULL; - const char * ifname = NULL; - const char * bssid = NULL; - const char * password = NULL; - const char * con_name = NULL; - gboolean private = FALSE; - gboolean hidden = FALSE; - gboolean wep_passphrase = FALSE; - GByteArray *bssid1_arr = NULL; - GByteArray *bssid2_arr = NULL; - gs_free NMDevice **devices = NULL; - int devices_idx; - char * ssid_ask = NULL; - char * passwd_ask = NULL; - const GPtrArray * avail_cons; - gboolean name_match = FALSE; - int i; - - /* Set default timeout waiting for operation completion. */ - if (nmc->timeout == -1) - nmc->timeout = 90; - - devices = nmc_get_devices_sorted(nmc->client); - - next_arg(nmc, &argc, &argv, NULL); - /* Get the first compulsory argument (SSID or BSSID) */ - if (argc > 0) { - param_user = *argv; - bssid1_arr = nm_utils_hwaddr_atoba(param_user, ETH_ALEN); - - if (argc == 1 && nmc->complete) - complete_aps(devices, NULL, param_user, param_user); - - next_arg(nmc, &argc, &argv, NULL); - } else { - /* nmc_do_cmd() should not call this with argc=0. */ - nm_assert(!nmc->complete); - - if (nmc->ask) { - ssid_ask = nmc_readline(&nmc->nmc_config, _("SSID or BSSID: ")); - param_user = ssid_ask ?: ""; - bssid1_arr = nm_utils_hwaddr_atoba(param_user, ETH_ALEN); - } - if (!ssid_ask) { - g_string_printf(nmc->return_text, _("Error: SSID or BSSID are missing.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - } - - /* Get the rest of the parameters */ - while (argc > 0) { - if (argc == 1 && nmc->complete) { - nmc_complete_strings(*argv, - "ifname", - "bssid", - "password", - "wep-key-type", - "name", - "private", - "hidden"); - } - - if (strcmp(*argv, "ifname") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - ifname = *argv; - if (argc == 1 && nmc->complete) - complete_device(devices, ifname, TRUE); - } else if (strcmp(*argv, "bssid") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - bssid = *argv; - if (argc == 1 && nmc->complete) - complete_aps(devices, NULL, bssid, NULL); - bssid2_arr = nm_utils_hwaddr_atoba(bssid, ETH_ALEN); - if (!bssid2_arr) { - g_string_printf(nmc->return_text, - _("Error: bssid argument value '%s' is not a valid BSSID."), - bssid); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - } else if (strcmp(*argv, "password") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - password = *argv; - } else if (strcmp(*argv, "wep-key-type") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - if (argc == 1 && nmc->complete) - nmc_complete_strings(*argv, "key", "phrase"); - if (strcmp(*argv, "key") == 0) - wep_passphrase = FALSE; - else if (strcmp(*argv, "phrase") == 0) - wep_passphrase = TRUE; - else { - g_string_printf( - nmc->return_text, - _("Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."), - *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - } else if (strcmp(*argv, "name") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - con_name = *argv; - } else if (strcmp(*argv, "private") == 0) { - GError *err_tmp = NULL; - - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - if (argc == 1 && nmc->complete) - nmc_complete_bool(*argv); - if (!nmc_string_to_bool(*argv, &private, &err_tmp)) { - g_string_printf(nmc->return_text, - _("Error: %s: %s."), - *(argv - 1), - err_tmp->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_clear_error(&err_tmp); - goto finish; - } - } else if (strcmp(*argv, "hidden") == 0) { - GError *err_tmp = NULL; - - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - if (argc == 1 && nmc->complete) - nmc_complete_bool(*argv); - if (!nmc_string_to_bool(*argv, &hidden, &err_tmp)) { - g_string_printf(nmc->return_text, - _("Error: %s: %s."), - *(argv - 1), - err_tmp->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_clear_error(&err_tmp); - goto finish; - } - } else if (!nmc->complete) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - - next_arg(nmc, &argc, &argv, NULL); - } - - if (nmc->complete) - goto finish; - - /* Verify SSID/BSSID parameters */ - if (bssid1_arr && bssid2_arr && memcmp(bssid1_arr->data, bssid2_arr->data, ETH_ALEN)) { - g_string_printf(nmc->return_text, - _("Error: BSSID to connect to (%s) differs from bssid argument (%s)."), - param_user, - bssid); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - if (!bssid1_arr && strlen(param_user) > 32) { - g_string_printf(nmc->return_text, - _("Error: Parameter '%s' is neither SSID nor BSSID."), - param_user); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; - } - - /* Find a device to activate the connection on */ - devices_idx = 0; - device = find_wifi_device_by_iface(devices, ifname, &devices_idx); - - if (!device) { - if (ifname) - g_string_printf(nmc->return_text, - _("Error: Device '%s' is not a Wi-Fi device."), - ifname); - else - g_string_printf(nmc->return_text, _("Error: No Wi-Fi device found.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto finish; - } - - /* For hidden SSID first scan it so that NM learns about the AP */ - if (hidden) { - GVariantBuilder builder, array_builder; - GVariant * options; - GError * scan_err = NULL; - - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aay")); - g_variant_builder_add( - &array_builder, - "@ay", - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, param_user, strlen(param_user), 1)); - g_variant_builder_add(&builder, "{sv}", "ssids", g_variant_builder_end(&array_builder)); - options = g_variant_builder_end(&builder); - - nm_device_wifi_request_scan_options(NM_DEVICE_WIFI(device), options, NULL, &scan_err); - if (scan_err) { - g_string_printf(nmc->return_text, - _("Error: Failed to scan hidden SSID: %s."), - scan_err->message); - g_clear_error(&scan_err); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto finish; - } - } - - /* Find an AP to connect to */ - ap = find_ap_on_device(device, - bssid1_arr ? param_user : bssid, - bssid1_arr ? NULL : param_user, - FALSE); - if (!ap && !ifname) { - NMDevice *dev; - - /* AP not found, ifname was not specified, so try finding the AP on another device. */ - while ((dev = find_wifi_device_by_iface(devices, NULL, &devices_idx)) != NULL) { - ap = find_ap_on_device(dev, - bssid1_arr ? param_user : bssid, - bssid1_arr ? NULL : param_user, - FALSE); - if (ap) { - device = dev; - break; - } - } - } - - if (!ap) { - if (!bssid1_arr) - g_string_printf(nmc->return_text, - _("Error: No network with SSID '%s' found."), - param_user); - else - g_string_printf(nmc->return_text, - _("Error: No access point with BSSID '%s' found."), - param_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto finish; - } - - avail_cons = nm_device_get_available_connections(device); - for (i = 0; i < avail_cons->len; i++) { - NMConnection *avail_con = g_ptr_array_index(avail_cons, i); - const char * id = nm_connection_get_id(NM_CONNECTION(avail_con)); - - if (con_name) { - if (!id || strcmp(id, con_name)) - continue; - - name_match = TRUE; - } - - if (nm_access_point_connection_valid(ap, NM_CONNECTION(avail_con))) { - /* ap has been checked against bssid1, bssid2 and the ssid - * and now avail_con has been checked against ap. - */ - connection = g_object_ref(avail_con); - break; - } - } - - if (name_match && !connection) { - g_string_printf(nmc->return_text, - _("Error: Connection '%s' exists but properties don't match."), - con_name); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto finish; - } - - if (!connection) { - /* If there are some connection data from user, create a connection and - * fill them into proper settings. */ - if (con_name || private || bssid2_arr || hidden) - connection = nm_simple_connection_new(); - - if (con_name || private) { - s_con = (NMSettingConnection *) nm_setting_connection_new(); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - - /* Set user provided connection name */ - if (con_name) - g_object_set(s_con, NM_SETTING_CONNECTION_ID, con_name, NULL); - - /* Connection will only be visible to this user when 'private' is specified */ - if (private) - nm_setting_connection_add_permission(s_con, - NM_SETTINGS_CONNECTION_PERMISSION_USER, - g_get_user_name() ?: "", - NULL); - } - if (bssid2_arr || hidden) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - - /* 'bssid' parameter is used to restrict the connection only to the BSSID */ - if (bssid2_arr) - g_object_set(s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL); - - /* 'hidden' parameter is used to indicate that SSID is not broadcasted */ - if (hidden) { - GBytes *ssid = g_bytes_new(param_user, strlen(param_user)); - - g_object_set(s_wifi, - NM_SETTING_WIRELESS_SSID, - ssid, - NM_SETTING_WIRELESS_HIDDEN, - hidden, - NULL); - g_bytes_unref(ssid); - - /* Warn when the provided AP identifier looks like BSSID instead of SSID */ - if (bssid1_arr) - g_printerr(_("Warning: '%s' should be SSID for hidden APs; but it looks like a " - "BSSID.\n"), - param_user); - } - } - } - - /* handle password */ - ap_flags = nm_access_point_get_flags(ap); - ap_wpa_flags = nm_access_point_get_wpa_flags(ap); - ap_rsn_flags = nm_access_point_get_rsn_flags(ap); - - /* Set password for WEP or WPA-PSK. */ - if ((ap_flags & NM_802_11_AP_FLAGS_PRIVACY) - || (ap_wpa_flags != NM_802_11_AP_SEC_NONE - && !NM_FLAGS_ANY(ap_wpa_flags, - NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) - || (ap_rsn_flags != NM_802_11_AP_SEC_NONE - && !NM_FLAGS_ANY(ap_rsn_flags, - NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM))) { - const char * con_password = NULL; - NMSettingWirelessSecurity *s_wsec = NULL; - - if (connection) { - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (s_wsec) { - if (ap_wpa_flags == NM_802_11_AP_SEC_NONE - && ap_rsn_flags == NM_802_11_AP_SEC_NONE) { - /* WEP */ - con_password = nm_setting_wireless_security_get_wep_key(s_wsec, 0); - } else if ((ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { - /* WPA PSK */ - con_password = nm_setting_wireless_security_get_psk(s_wsec); - } - } - } - - /* Ask for missing password when one is expected and '--ask' is used */ - if (!password && !con_password && nmc->ask) { - password = passwd_ask = - nmc_readline_echo(&nmc->nmc_config, nmc->nmc_config.show_secrets, _("Password: ")); - } - - if (password) { - if (!connection) - connection = nm_simple_connection_new(); - if (!s_wsec) { - s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wsec)); - } - - if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) { - /* WEP */ - nm_setting_wireless_security_set_wep_key(s_wsec, 0, password); - g_object_set(G_OBJECT(s_wsec), - NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - wep_passphrase ? NM_WEP_KEY_TYPE_PASSPHRASE : NM_WEP_KEY_TYPE_KEY, - NULL); - } else if ((ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { - /* WPA PSK */ - g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL); - } - } - } - // FIXME: Creating WPA-Enterprise connections is not supported yet. - // We are not able to determine and fill all the parameters for - // 802.1X authentication automatically without user providing - // the data. Adding nmcli options for the 8021x setting would - // clutter the command. However, that could be solved later by - // implementing add/edit connections support for nmcli. - - /* nowait_flag indicates user input. should_wait says whether quit in start(). - * We have to delay exit after add_and_activate_cb() is called, even if - * the user doesn't want to wait, in order to give NM time to check our - * permissions. */ - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - save_and_activate_connection(nmc, device, connection, FALSE, nm_object_get_path(NM_OBJECT(ap))); - -finish: - if (bssid1_arr) - g_byte_array_free(bssid1_arr, TRUE); - if (bssid2_arr) - g_byte_array_free(bssid2_arr, TRUE); - g_free(ssid_ask); - nm_free_secret(passwd_ask); -} - -static GBytes * -generate_ssid_for_hotspot(void) -{ - GBytes *ssid_bytes; - char * ssid = NULL; - - ssid = g_strdup_printf("Hotspot-%s", g_get_host_name()); - if (strlen(ssid) > 32) - ssid[32] = '\0'; - ssid_bytes = g_bytes_new(ssid, strlen(ssid)); - g_free(ssid); - - return ssid_bytes; -} - -#define WPA_PASSKEY_SIZE 8 -static void -generate_wpa_key(char *key, size_t len) -{ - guint i; - - g_return_if_fail(key); - g_return_if_fail(len > WPA_PASSKEY_SIZE); - - /* generate a 8-chars ASCII WPA key */ - for (i = 0; i < WPA_PASSKEY_SIZE; i++) { - int c; - c = g_random_int_range(33, 126); - /* too many non alphanumeric characters are hard to remember for humans */ - while (!g_ascii_isalnum(c)) - c = g_random_int_range(33, 126); - - key[i] = (char) c; - } - key[WPA_PASSKEY_SIZE] = '\0'; -} - -static void -generate_wep_key(char *key, size_t len) -{ - int i; - const char *hexdigits = "0123456789abcdef"; - - g_return_if_fail(key); - g_return_if_fail(len > 10); - - /* generate a 10-digit hex WEP key */ - for (i = 0; i < 10; i++) { - int digit; - digit = g_random_int_range(0, 16); - key[i] = hexdigits[digit]; - } - key[10] = '\0'; -} - -static gboolean -set_wireless_security_for_hotspot(NMSettingWirelessSecurity *s_wsec, - const char * wifi_mode, - NMDeviceWifiCapabilities caps, - const char * password, - gboolean show_password, - GError ** error) -{ - char generated_key[11]; - const char *key; - const char *key_mgmt; - - if (g_strcmp0(wifi_mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - if (caps & NM_WIFI_DEVICE_CAP_RSN) { - nm_setting_wireless_security_add_proto(s_wsec, "rsn"); - nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp"); - nm_setting_wireless_security_add_group(s_wsec, "ccmp"); - key_mgmt = "wpa-psk"; - } else if (caps & NM_WIFI_DEVICE_CAP_WPA) { - nm_setting_wireless_security_add_proto(s_wsec, "wpa"); - nm_setting_wireless_security_add_pairwise(s_wsec, "tkip"); - nm_setting_wireless_security_add_group(s_wsec, "tkip"); - key_mgmt = "wpa-psk"; - } else - key_mgmt = "none"; - } else - key_mgmt = "none"; - - if (g_strcmp0(key_mgmt, "wpa-psk") == 0) { - /* use WPA */ - if (password) { - if (!nm_utils_wpa_psk_valid(password)) { - g_set_error(error, NMCLI_ERROR, 0, _("'%s' is not valid WPA PSK"), password); - return FALSE; - } - key = password; - } else { - generate_wpa_key(generated_key, sizeof(generated_key)); - key = generated_key; - } - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - key_mgmt, - NM_SETTING_WIRELESS_SECURITY_PSK, - key, - NULL); - } else { - /* use WEP */ - if (password) { - if (!nm_utils_wep_key_valid(password, NM_WEP_KEY_TYPE_KEY)) { - g_set_error(error, - NMCLI_ERROR, - 0, - _("'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)"), - password); - return FALSE; - } - key = password; - } else { - generate_wep_key(generated_key, sizeof(generated_key)); - key = generated_key; - } - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - key_mgmt, - NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, - key, - NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - NM_WEP_KEY_TYPE_KEY, - NULL); - } - if (show_password) - g_print(_("Hotspot password: %s\n"), key); - - return TRUE; -} - -static NMConnection * -find_hotspot_conn(NMDevice * device, - const GPtrArray *connections, - const char * con_name, - GBytes * ssid_bytes, - const char * wifi_mode, - const char * band, - gint64 channel_int) -{ - NMConnection * connection; - NMSettingWireless *s_wifi; - int i; - - for (i = 0; i < connections->len; i++) { - connection = NM_CONNECTION(connections->pdata[i]); - - s_wifi = nm_connection_get_setting_wireless(connection); - if (!s_wifi) - continue; - - if (channel_int != -1 && nm_setting_wireless_get_channel(s_wifi) != channel_int) - continue; - - if (g_strcmp0(nm_setting_wireless_get_mode(s_wifi), wifi_mode) != 0) - continue; - - if (band && g_strcmp0(nm_setting_wireless_get_band(s_wifi), band) != 0) - continue; - - if (ssid_bytes && !g_bytes_equal(nm_setting_wireless_get_ssid(s_wifi), ssid_bytes)) - continue; - - if (!nm_device_connection_compatible(device, connection, NULL)) - continue; - - return g_object_ref(connection); - } - - return NULL; -} - -static NMConnection * -create_hotspot_conn(const GPtrArray *connections, - const char * con_name, - GBytes * ssid_bytes, - const char * wifi_mode, - const char * band, - gint64 channel_int) -{ - char * default_name = NULL; - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingWireless * s_wifi; - NMSettingWirelessSecurity *s_wsec; - NMSettingIPConfig * s_ip4, *s_ip6; - NMSettingProxy * s_proxy; - - connection = nm_simple_connection_new(); - s_con = (NMSettingConnection *) nm_setting_connection_new(); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - if (!con_name) - con_name = default_name = nmc_unique_connection_name(connections, "Hotspot"); - g_object_set(s_con, - NM_SETTING_CONNECTION_ID, - con_name, - NM_SETTING_CONNECTION_AUTOCONNECT, - FALSE, - NULL); - g_free(default_name); - - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - - g_object_set(s_wifi, - NM_SETTING_WIRELESS_MODE, - wifi_mode, - NM_SETTING_WIRELESS_SSID, - ssid_bytes, - NULL); - - if (channel_int != -1) { - g_object_set(s_wifi, - NM_SETTING_WIRELESS_CHANNEL, - (guint32) channel_int, - NM_SETTING_WIRELESS_BAND, - band, - NULL); - } - - s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wsec)); - - s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new(); - nm_connection_add_setting(connection, NM_SETTING(s_ip4)); - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, NULL); - - s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new(); - nm_connection_add_setting(connection, NM_SETTING(s_ip6)); - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); - - s_proxy = (NMSettingProxy *) nm_setting_proxy_new(); - nm_connection_add_setting(connection, NM_SETTING(s_proxy)); - g_object_set(s_proxy, NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, NULL); - - return connection; -} - -static void -do_device_wifi_hotspot(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - const char * ifname = NULL; - const char * con_name = NULL; - gs_unref_bytes GBytes *ssid_bytes = NULL; - const char * wifi_mode; - const char * band = NULL; - const char * channel = NULL; - gint64 channel_int = -1; - const char * password = NULL; - gboolean show_password = FALSE; - NMDevice * device = NULL; - gs_free NMDevice ** devices = NULL; - NMDeviceWifiCapabilities caps; - gs_unref_object NMConnection *connection = NULL; - const GPtrArray * connections; - NMSettingWirelessSecurity * s_wsec; - GError * error = NULL; - - /* Set default timeout waiting for operation completion. */ - if (nmc->timeout == -1) - nmc->timeout = 60; - - devices = nmc_get_devices_sorted(nmc->client); - - next_arg(nmc, &argc, &argv, NULL); - while (argc > 0) { - if (argc == 1 && nmc->complete) { - nmc_complete_strings(*argv, - "ifname", - "con-name", - "ssid", - "band", - "channel", - "password"); - } - - if (strcmp(*argv, "ifname") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - ifname = *argv; - if (argc == 1 && nmc->complete) - complete_device(devices, ifname, TRUE); - } else if (strcmp(*argv, "con-name") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - con_name = *argv; - } else if (strcmp(*argv, "ssid") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - if (strlen(*argv) > 32) { - g_string_printf(nmc->return_text, _("Error: ssid is too long.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - ssid_bytes = g_bytes_new(*argv, strlen(*argv)); - } else if (strcmp(*argv, "band") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - band = *argv; - if (argc == 1 && nmc->complete) - nmc_complete_strings(band, "a", "bg"); - if (strcmp(band, "a") && strcmp(band, "bg")) { - g_string_printf(nmc->return_text, - _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."), - band); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - } else if (strcmp(*argv, "channel") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - channel = *argv; - } else if (strcmp(*argv, "password") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - password = *argv; - /* --show-password is deprecated in favour of global --show-secrets option */ - /* Keep it here for backwards compatibility */ - } else if (nmc_arg_is_option(*argv, "show-password")) { - show_password = TRUE; - } else { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - next_arg(nmc, &argc, &argv, NULL); - } - show_password = nmc->nmc_config.show_secrets || show_password; - - if (nmc->complete) - return; - - /* Verify band and channel parameters */ - if (!channel) { - if (g_strcmp0(band, "bg") == 0) - channel = "1"; - if (g_strcmp0(band, "a") == 0) - channel = "7"; - } - if (channel) { - unsigned long int value; - - if (!band) { - g_string_printf(nmc->return_text, _("Error: channel requires band too.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - if (!nmc_string_to_uint(channel, TRUE, 1, 5825, &value) - || !nm_utils_wifi_is_channel_valid(value, band)) { - g_string_printf(nmc->return_text, - _("Error: channel '%s' not valid for band '%s'."), - channel, - band); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - channel_int = value; - } - - /* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */ - device = find_wifi_device_by_iface(devices, ifname, NULL); - if (!device) { - if (ifname) - g_string_printf(nmc->return_text, - _("Error: Device '%s' is not a Wi-Fi device."), - ifname); - else - g_string_printf(nmc->return_text, _("Error: No Wi-Fi device found.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } - - /* Check device supported mode */ - caps = nm_device_wifi_get_capabilities(NM_DEVICE_WIFI(device)); - if (caps & NM_WIFI_DEVICE_CAP_AP) - wifi_mode = NM_SETTING_WIRELESS_MODE_AP; - else if (caps & NM_WIFI_DEVICE_CAP_ADHOC) - wifi_mode = NM_SETTING_WIRELESS_MODE_ADHOC; - else { - g_string_printf(nmc->return_text, - _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."), - nm_device_get_iface(device)); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } - - connections = nm_client_get_connections(nmc->client); - connection = - find_hotspot_conn(device, connections, con_name, ssid_bytes, wifi_mode, band, channel_int); - if (!connection) { - /* Create a connection with appropriate parameters */ - if (!ssid_bytes) - ssid_bytes = generate_ssid_for_hotspot(); - connection = - create_hotspot_conn(connections, con_name, ssid_bytes, wifi_mode, band, channel_int); - } - - if (password || !NM_IS_REMOTE_CONNECTION(connection)) { - s_wsec = nm_connection_get_setting_wireless_security(connection); - g_return_if_fail(s_wsec); - - if (!set_wireless_security_for_hotspot(s_wsec, - wifi_mode, - caps, - password, - show_password, - &error)) { - g_string_printf(nmc->return_text, _("Error: Invalid 'password': %s."), error->message); - g_clear_error(&error); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } - } - - /* Activate the connection now */ - nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait++; - - save_and_activate_connection(nmc, device, connection, TRUE, NULL); -} - -static void -request_rescan_cb(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NmCli * nmc = (NmCli *) user_data; - GError *error = NULL; - - nm_device_wifi_request_scan_finish(NM_DEVICE_WIFI(object), result, &error); - if (error) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - g_error_free(error); - } - quit(); -} - -static void -do_device_wifi_rescan(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device; - const char * ifname = NULL; - gs_unref_ptrarray GPtrArray *ssids = NULL; - gs_free NMDevice **devices = NULL; - GVariantBuilder builder, array_builder; - GVariant * options; - int i; - - ssids = g_ptr_array_new(); - devices = nmc_get_devices_sorted(nmc->client); - - next_arg(nmc, &argc, &argv, NULL); - /* Get the parameters */ - while (argc > 0) { - if (argc == 1 && nmc->complete) - nmc_complete_strings(*argv, "ifname", "ssid"); - - if (strcmp(*argv, "ifname") == 0) { - if (ifname) { - g_string_printf(nmc->return_text, _("Error: '%s' cannot repeat."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - ifname = *argv; - if (argc == 1 && nmc->complete) - complete_device(devices, ifname, TRUE); - } else if (strcmp(*argv, "ssid") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - g_ptr_array_add(ssids, (gpointer) *argv); - } else if (!nmc->complete) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - next_arg(nmc, &argc, &argv, NULL); - } - - if (nmc->complete) - return; - - /* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */ - device = find_wifi_device_by_iface(devices, ifname, NULL); - - if (!device) { - if (ifname) - g_string_printf(nmc->return_text, - _("Error: Device '%s' is not a Wi-Fi device."), - ifname); - else - g_string_printf(nmc->return_text, _("Error: No Wi-Fi device found.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } - - if (ssids->len) { - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aay")); - - for (i = 0; i < ssids->len; i++) { - const char *ssid = g_ptr_array_index(ssids, i); - - g_variant_builder_add( - &array_builder, - "@ay", - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, ssid, strlen(ssid), 1)); - } - - g_variant_builder_add(&builder, "{sv}", "ssids", g_variant_builder_end(&array_builder)); - options = g_variant_builder_end(&builder); - - nm_device_wifi_request_scan_options_async(NM_DEVICE_WIFI(device), - options, - NULL, - request_rescan_cb, - nmc); - } else - nm_device_wifi_request_scan_async(NM_DEVICE_WIFI(device), NULL, request_rescan_cb, nmc); - - nmc->should_wait++; -} - -static void -string_append_mecard(GString *string, const char *tag, const char *text) -{ - const char *p; - bool is_hex = TRUE; - int start; - - if (!text) - return; - - g_string_append(string, tag); - start = string->len; - - for (p = text; *p; p++) { - if (!g_ascii_isxdigit(*p)) - is_hex = FALSE; - if (strchr("\\\":;,", *p)) - g_string_append_c(string, '\\'); - g_string_append_c(string, *p); - } - - if (is_hex) { - g_string_insert_c(string, start, '\"'); - g_string_append_c(string, '\"'); - } - g_string_append_c(string, ';'); -} - -static void -print_wifi_connection(const NmcConfig *nmc_config, NMConnection *connection) -{ - NMSettingWireless * s_wireless; - NMSettingWirelessSecurity *s_wsec; - const char * key_mgmt = NULL; - const char * psk = NULL; - const char * type = NULL; - GBytes * ssid_bytes; - gs_free char * ssid = NULL; - GString * string; - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_if_fail(s_wireless); - - ssid_bytes = nm_setting_wireless_get_ssid(s_wireless); - g_return_if_fail(ssid_bytes); - ssid = nm_utils_ssid_to_utf8(g_bytes_get_data(ssid_bytes, NULL), g_bytes_get_size(ssid_bytes)); - g_return_if_fail(ssid); - g_print("SSID: %s\n", ssid); - - string = g_string_sized_new(64); - g_string_append(string, "WIFI:"); - - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (s_wsec) { - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - psk = nm_setting_wireless_security_get_psk(s_wsec); - } - - if (key_mgmt == NULL) { - type = "nopass"; - g_print("%s: %s\n", _("Security"), _("None")); - } else if (strcmp(key_mgmt, "none") == 0 || strcmp(key_mgmt, "ieee8021x") == 0) { - type = "WEP"; - g_print("%s: WEP\n", _("Security")); - } else if (strcmp(key_mgmt, "wpa-none") == 0 || strcmp(key_mgmt, "wpa-psk") == 0 - || strcmp(key_mgmt, "sae") == 0) { - type = "WPA"; - g_print("%s: WPA\n", _("Security")); - } else if (strcmp(key_mgmt, "owe") == 0) { - type = "nopass"; - g_print("%s: OWE\n", _("Security")); - } - - if (psk) - g_print("%s: %s\n", _("Password"), psk); - - string_append_mecard(string, "T:", type); - string_append_mecard(string, "S:", ssid); - string_append_mecard(string, "P:", psk); - - if (nm_setting_wireless_get_hidden(s_wireless)) - g_string_append(string, "H:true;"); - - g_string_append_c(string, ';'); - if (nmc_config->use_colors) - nmc_print_qrcode(string->str); - g_string_free(string, TRUE); - - g_print("\n"); -} - -static gboolean -wifi_show_device(const NmcConfig *nmc_config, NMDevice *device, GError **error) -{ - NMActiveConnection *active_conn; - gs_unref_object NMConnection *connection = NULL; - gs_unref_variant GVariant *secrets = NULL; - - if (!NM_IS_DEVICE_WIFI(device)) { - g_set_error(error, - NMCLI_ERROR, - 0, - _("Error: Device '%s' is not a Wi-Fi device."), - nm_device_get_iface(device)); - return FALSE; - } - - connection = nm_device_get_applied_connection(device, 0, NULL, NULL, error); - if (!connection) - return FALSE; - - active_conn = nm_device_get_active_connection(device); - if (!active_conn) { - g_set_error(error, - NMCLI_ERROR, - 0, - _("no active connection on device '%s'"), - nm_device_get_iface(device)); - return FALSE; - } - - secrets = nm_remote_connection_get_secrets(nm_active_connection_get_connection(active_conn), - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NULL, - NULL); - if (secrets - && !nm_connection_update_secrets(connection, - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - secrets, - error)) { - return FALSE; - } - - print_wifi_connection(nmc_config, connection); - - return TRUE; -} - -static void -do_device_wifi_show_password(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - const char *ifname = NULL; - gs_free NMDevice **devices = NULL; - gs_free_error GError *error = NULL; - gboolean found = FALSE; - int i; - - devices = nmc_get_devices_sorted(nmc->client); - - next_arg(nmc, &argc, &argv, NULL); - while (argc > 0) { - if (argc == 1 && nmc->complete) - nmc_complete_strings(*argv, "ifname"); - - if (strcmp(*argv, "ifname") == 0) { - if (ifname) { - g_string_printf(nmc->return_text, _("Error: '%s' cannot repeat."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - ifname = *argv; - if (argc == 1 && nmc->complete) - complete_device(devices, ifname, TRUE); - } else if (!nmc->complete) { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - next_arg(nmc, &argc, &argv, NULL); - } - - if (nmc->complete) - return; - - for (i = 0; devices[i]; i++) { - if (ifname && g_strcmp0(nm_device_get_iface(devices[i]), ifname) != 0) - continue; - - if (wifi_show_device(&nmc->nmc_config, devices[i], &error)) { - found = TRUE; - } else { - if (ifname) { - g_string_printf(nmc->return_text, _("%s"), error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } - g_clear_error(&error); - } - - if (ifname) - break; - } - - if (!found) { - g_string_printf(nmc->return_text, _("Error: No Wi-Fi device found.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - return; - } -} - -static NMCCommand device_wifi_cmds[] = { - {"list", do_device_wifi_list, NULL, TRUE, TRUE}, - {"connect", do_device_wifi_connect, NULL, TRUE, TRUE}, - {"hotspot", do_device_wifi_hotspot, NULL, TRUE, TRUE}, - {"rescan", do_device_wifi_rescan, NULL, TRUE, TRUE}, - {"show-password", do_device_wifi_show_password, NULL, TRUE, TRUE}, - {NULL, do_device_wifi_list, NULL, TRUE, TRUE}, -}; - -static void -do_device_wifi(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - next_arg(nmc, &argc, &argv, NULL); - nmc_do_cmd(nmc, device_wifi_cmds, *argv, argc, argv); -} - -static int -show_device_lldp_list(NMDevice *device, NmCli *nmc, const char *fields_str, int *counter) -{ - const NMMetaAbstractInfo *const *tmpl; - NmcOutputField * arr; - GPtrArray * neighbors; - const char * str; - int i; - NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - gs_free char *header_name = NULL; - - neighbors = nm_device_get_lldp_neighbors(device); - - if (!neighbors || !neighbors->len) - return 0; - - tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_lldp_list; - - /* Main header name */ - header_name = construct_header_name(_("Device LLDP neighbors"), nm_device_get_iface(device)); - out_indices = parse_output_fields(fields_str, - (const NMMetaAbstractInfo *const *) nmc_fields_dev_lldp_list, - FALSE, - NULL, - NULL); - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add(out.output_data, arr); - - for (i = 0; i < neighbors->len; i++) { - NMLldpNeighbor *neighbor = neighbors->pdata[i]; - guint value; - - arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_str(arr, 0, g_strdup_printf("NEIGHBOR[%d]", (*counter)++)); - - set_val_strc(arr, 1, nm_device_get_iface(device)); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_CHASSIS_ID, &str)) - set_val_strc(arr, 2, str); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_PORT_ID, &str)) - set_val_strc(arr, 3, str); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_PORT_DESCRIPTION, &str)) - set_val_strc(arr, 4, str); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_SYSTEM_NAME, &str)) - set_val_strc(arr, 5, str); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, &str)) - set_val_strc(arr, 6, str); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, - NM_LLDP_ATTR_SYSTEM_CAPABILITIES, - &value)) { - gs_free char *tmp = NULL; - - set_val_str( - arr, - 7, - g_strdup_printf("%u (%s)", value, (tmp = nmc_parse_lldp_capabilities(value)))); - } - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, &value)) - set_val_str(arr, 8, nm_strdup_int(value)); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID, &value)) - set_val_str(arr, 9, nm_strdup_int(value)); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, - NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, - &value)) - set_val_str(arr, 10, nm_strdup_int(value)); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_VID, &value)) - set_val_str(arr, 11, nm_strdup_int(value)); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, - NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, - &str)) - set_val_strc(arr, 12, str); - - if (nm_lldp_neighbor_get_attr_string_value(neighbor, NM_LLDP_ATTR_DESTINATION, &str)) - set_val_strc(arr, 13, str); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, NM_LLDP_ATTR_CHASSIS_ID_TYPE, &value)) - set_val_str(arr, 14, nm_strdup_int(value)); - - if (nm_lldp_neighbor_get_attr_uint_value(neighbor, NM_LLDP_ATTR_PORT_ID_TYPE, &value)) - set_val_str(arr, 15, nm_strdup_int(value)); - - g_ptr_array_add(out.output_data, arr); - } - - print_data_prepare_width(out.output_data); - print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); - - return neighbors->len; -} - -static void -do_device_lldp_list(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - NMDevice * device = NULL; - gs_free_error GError *error = NULL; - const char * fields_str = NULL; - int counter = 0; - gs_unref_array GArray *out_indices = NULL; - - next_arg(nmc, &argc, &argv, NULL); - while (argc > 0) { - if (argc == 1 && nmc->complete) - nmc_complete_strings(*argv, "ifname"); - - if (strcmp(*argv, "ifname") == 0) { - argc--; - argv++; - if (!argc) { - g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - device = get_device(nmc, &argc, &argv, &error); - if (!device) { - g_string_printf(nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - return; - } - } else { - g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - next_arg(nmc, &argc, &argv, NULL); - } - - if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "common") == 0) - fields_str = NMC_FIELDS_DEV_LLDP_LIST_COMMON; - else if (!nmc->required_fields || g_ascii_strcasecmp(nmc->required_fields, "all") == 0) { - /* pass */ - } else - fields_str = nmc->required_fields; - - out_indices = parse_output_fields(fields_str, - (const NMMetaAbstractInfo *const *) nmc_fields_dev_lldp_list, - FALSE, - NULL, - &error); - - if (error) { - g_string_printf(nmc->return_text, _("Error: 'device lldp list': %s"), error->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return; - } - - if (nmc->complete) - return; - - if (device) { - show_device_lldp_list(device, nmc, fields_str, &counter); - } else { - gs_free NMDevice **devices = nmc_get_devices_sorted(nmc->client); - guint i; - - for (i = 0; devices[i]; i++) - show_device_lldp_list(devices[i], nmc, fields_str, &counter); - } -} - -static NMCCommand device_lldp_cmds[] = { - {"list", do_device_lldp_list, NULL, TRUE, TRUE}, - {NULL, do_device_lldp_list, NULL, TRUE, TRUE}, -}; - -static void -do_device_lldp(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - if (!nmc->mode_specified) - nmc->nmc_config_mutable.multiline_output = - TRUE; /* multiline mode is default for 'device lldp' */ - - next_arg(nmc, &argc, &argv, NULL); - nmc_do_cmd(nmc, device_lldp_cmds, *argv, argc, argv); -} - -static gboolean -is_single_word(const char *line) -{ - size_t n1, n2, n3; - - n1 = strspn(line, " \t"); - n2 = strcspn(line + n1, " \t\0") + n1; - n3 = strspn(line + n2, " \t"); - - if (n3 == 0) - return TRUE; - else - return FALSE; -} - -static char ** -nmcli_device_tab_completion(const char *text, int start, int end) -{ - char ** match_array = NULL; - rl_compentry_func_t *generator_func = NULL; - - /* Disable readline's default filename completion */ - rl_attempted_completion_over = 1; - - if (g_strcmp0(rl_prompt, PROMPT_INTERFACE) == 0) { - /* Disable appending space after completion */ - rl_completion_append_character = '\0'; - - if (!is_single_word(rl_line_buffer)) - return NULL; - - generator_func = nmc_rl_gen_func_ifnames; - } else if (g_strcmp0(rl_prompt, PROMPT_INTERFACES) == 0) { - generator_func = nmc_rl_gen_func_ifnames; - } - - if (generator_func) - match_array = rl_completion_matches(text, generator_func); - - return match_array; -} - -void -nmc_command_func_device(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) -{ - static const NMCCommand cmds[] = { - {"status", do_devices_status, usage_device_status, TRUE, TRUE}, - {"show", do_device_show, usage_device_show, TRUE, TRUE}, - {"connect", do_device_connect, usage_device_connect, TRUE, TRUE}, - {"reapply", do_device_reapply, usage_device_reapply, TRUE, TRUE}, - {"disconnect", do_devices_disconnect, usage_device_disconnect, TRUE, TRUE}, - {"delete", do_devices_delete, usage_device_delete, TRUE, TRUE}, - {"set", do_device_set, usage_device_set, TRUE, TRUE}, - {"monitor", do_devices_monitor, usage_device_monitor, TRUE, TRUE}, - {"wifi", do_device_wifi, usage_device_wifi, FALSE, FALSE}, - {"lldp", do_device_lldp, usage_device_lldp, FALSE, FALSE}, - {"modify", do_device_modify, usage_device_modify, TRUE, TRUE}, - {NULL, do_devices_status, usage, TRUE, TRUE}, - }; - - next_arg(nmc, &argc, &argv, NULL); - - nmc_start_polkit_agent_start_try(nmc); - - rl_attempted_completion_function = (rl_completion_func_t *) nmcli_device_tab_completion; - - nmc_do_cmd(nmc, cmds, *argv, argc, argv); -} - -void -monitor_devices(NmCli *nmc) -{ - do_devices_monitor(NULL, nmc, 0, NULL); -} |