diff options
Diffstat (limited to 'clients/cli/devices.c')
| -rw-r--r-- | clients/cli/devices.c | 1657 |
1 files changed, 1149 insertions, 508 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 70c8d5d5..c1df7fee 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -25,9 +25,7 @@ #include <errno.h> #include <readline/readline.h> -#include <glib.h> -#include <glib/gi18n.h> - +#include "nm-default.h" #include "nm-secret-agent-simple.h" #include "polkit-agent.h" #include "utils.h" @@ -40,14 +38,14 @@ /* Available fields for 'device status' */ static NmcOutputField nmc_fields_dev_status[] = { - {"DEVICE", N_("DEVICE"), 10}, /* 0 */ - {"TYPE", N_("TYPE"), 17}, /* 1 */ - {"STATE", N_("STATE"), 13}, /* 2 */ - {"DBUS-PATH", N_("DBUS-PATH"), 43}, /* 3 */ - {"CONNECTION", N_("CONNECTION"), 20}, /* 4 */ - {"CON-UUID", N_("CON-UUID"), 38}, /* 5 */ - {"CON-PATH", N_("CON-PATH"), 51}, /* 6 */ - {NULL, NULL, 0} + {"DEVICE", N_("DEVICE")}, /* 0 */ + {"TYPE", N_("TYPE")}, /* 1 */ + {"STATE", N_("STATE")}, /* 2 */ + {"DBUS-PATH", N_("DBUS-PATH")}, /* 3 */ + {"CONNECTION", N_("CONNECTION")}, /* 4 */ + {"CON-UUID", N_("CON-UUID")}, /* 5 */ + {"CON-PATH", N_("CON-PATH")}, /* 6 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_STATUS_ALL "DEVICE,TYPE,STATE,DBUS-PATH,CONNECTION,CON-UUID,CON-PATH" #define NMC_FIELDS_DEV_STATUS_COMMON "DEVICE,TYPE,STATE,CONNECTION" @@ -55,117 +53,119 @@ static NmcOutputField nmc_fields_dev_status[] = { /* Available fields for 'device show' - GENERAL part */ static NmcOutputField nmc_fields_dev_show_general[] = { - {"NAME", N_("NAME"), 10}, /* 0 */ - {"DEVICE", N_("DEVICE"), 10}, /* 1 */ - {"TYPE", N_("TYPE"), 17}, /* 2 */ - {"NM-TYPE", N_("NM-TYPE"), 17}, /* 3 */ - {"VENDOR", N_("VENDOR"), 20}, /* 4 */ - {"PRODUCT", N_("PRODUCT"), 50}, /* 5 */ - {"DRIVER", N_("DRIVER"), 9}, /* 6 */ - {"DRIVER-VERSION", N_("DRIVER-VERSION"), 18}, /* 7 */ - {"FIRMWARE-VERSION", N_("FIRMWARE-VERSION"), 18}, /* 8 */ - {"HWADDR", N_("HWADDR"), 19}, /* 9 */ - {"MTU", N_("MTU"), 10}, /* 10 */ - {"STATE", N_("STATE"), 14}, /* 11 */ - {"REASON", N_("REASON"), 25}, /* 12 */ - {"UDI", N_("UDI"), 64}, /* 13 */ - {"IP-IFACE", N_("IP-IFACE"), 10}, /* 14 */ - {"IS-SOFTWARE", N_("IS-SOFTWARE"), 15}, /* 15 */ - {"NM-MANAGED", N_("NM-MANAGED"), 15}, /* 16 */ - {"AUTOCONNECT", N_("AUTOCONNECT"), 15}, /* 17 */ - {"FIRMWARE-MISSING", N_("FIRMWARE-MISSING"), 18}, /* 18 */ - {"PHYS-PORT-ID", N_("PHYS-PORT-ID"), 18}, /* 19 */ - {"CONNECTION", N_("CONNECTION"), 20}, /* 20 */ - {"CON-UUID", N_("CON-UUID"), 38}, /* 21 */ - {"CON-PATH", N_("CON-PATH"), 51}, /* 22 */ - {"METERED", N_("METERED"), 10}, /* 23 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"DEVICE", N_("DEVICE")}, /* 1 */ + {"TYPE", N_("TYPE")}, /* 2 */ + {"NM-TYPE", N_("NM-TYPE")}, /* 3 */ + {"VENDOR", N_("VENDOR")}, /* 4 */ + {"PRODUCT", N_("PRODUCT")}, /* 5 */ + {"DRIVER", N_("DRIVER")}, /* 6 */ + {"DRIVER-VERSION", N_("DRIVER-VERSION")}, /* 7 */ + {"FIRMWARE-VERSION", N_("FIRMWARE-VERSION")}, /* 8 */ + {"HWADDR", N_("HWADDR")}, /* 9 */ + {"MTU", N_("MTU")}, /* 10 */ + {"STATE", N_("STATE")}, /* 11 */ + {"REASON", N_("REASON")}, /* 12 */ + {"UDI", N_("UDI")}, /* 13 */ + {"IP-IFACE", N_("IP-IFACE")}, /* 14 */ + {"IS-SOFTWARE", N_("IS-SOFTWARE")}, /* 15 */ + {"NM-MANAGED", N_("NM-MANAGED")}, /* 16 */ + {"AUTOCONNECT", N_("AUTOCONNECT")}, /* 17 */ + {"FIRMWARE-MISSING", N_("FIRMWARE-MISSING")}, /* 18 */ + {"NM-PLUGIN-MISSING", N_("NM-PLUGIN-MISSING")}, /* 19 */ + {"PHYS-PORT-ID", N_("PHYS-PORT-ID")}, /* 20 */ + {"CONNECTION", N_("CONNECTION")}, /* 21 */ + {"CON-UUID", N_("CON-UUID")}, /* 22 */ + {"CON-PATH", N_("CON-PATH")}, /* 23 */ + {"METERED", N_("METERED")}, /* 24 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_GENERAL_ALL "NAME,DEVICE,TYPE,NM-TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,MTU,"\ - "STATE,REASON,UDI,IP-IFACE,IS-SOFTWARE,NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,PHYS-PORT-ID,"\ - "CONNECTION,CON-UUID,CON-PATH,METERED" + "STATE,REASON,UDI,IP-IFACE,IS-SOFTWARE,NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,NM-PLUGIN-MISSING,"\ + "PHYS-PORT-ID,CONNECTION,CON-UUID,CON-PATH,METERED" #define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE" /* Available fields for 'device show' - CONNECTIONS part */ static NmcOutputField nmc_fields_dev_show_connections[] = { - {"NAME", N_("NAME"), 10}, /* 0 */ - {"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS"), 80}, /* 1 */ - {"AVAILABLE-CONNECTIONS", N_("AVAILABLE-CONNECTIONS"), 80}, /* 2 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS")}, /* 1 */ + {"AVAILABLE-CONNECTIONS", N_("AVAILABLE-CONNECTIONS")}, /* 2 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_CONNECTIONS_ALL "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS" #define NMC_FIELDS_DEV_SHOW_CONNECTIONS_COMMON "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS" /* Available fields for 'device show' - CAPABILITIES part */ static NmcOutputField nmc_fields_dev_show_cap[] = { - {"NAME", N_("NAME"), 13}, /* 0 */ - {"CARRIER-DETECT", N_("CARRIER-DETECT"), 16}, /* 1 */ - {"SPEED", N_("SPEED"), 10}, /* 2 */ - {"IS-SOFTWARE", N_("IS-SOFTWARE"), 12}, /* 3 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"CARRIER-DETECT", N_("CARRIER-DETECT")}, /* 1 */ + {"SPEED", N_("SPEED")}, /* 2 */ + {"IS-SOFTWARE", N_("IS-SOFTWARE")}, /* 3 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_CAP_ALL "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE" #define NMC_FIELDS_DEV_SHOW_CAP_COMMON "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE" /* Available fields for 'device show' - wired properties part */ static NmcOutputField nmc_fields_dev_show_wired_prop[] = { - {"NAME", N_("NAME"), 18}, /* 0 */ - {"CARRIER", N_("CARRIER"), 10}, /* 1 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"CARRIER", N_("CARRIER")}, /* 1 */ + {"S390-SUBCHANNELS", N_("S390-SUBCHANNELS")}, /* 2 */ + {NULL, NULL} }; -#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_ALL "NAME,CARRIER" -#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON "NAME,CARRIER" +#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_ALL "NAME,CARRIER,S390-SUBCHANNELS" +#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON "NAME,CARRIER,S390-SUBCHANNELS" /* Available fields for 'device show' - wireless properties part */ static NmcOutputField nmc_fields_dev_show_wifi_prop[] = { - {"NAME", N_("NAME"), 18}, /* 0 */ - {"WEP", N_("WEP"), 5}, /* 1 */ - {"WPA", N_("WPA"), 5}, /* 2 */ - {"WPA2", N_("WPA2"), 6}, /* 3 */ - {"TKIP", N_("TKIP"), 6}, /* 4 */ - {"CCMP", N_("CCMP"), 6}, /* 5 */ - {"AP", N_("AP"), 6}, /* 6 */ - {"ADHOC", N_("ADHOC"), 6}, /* 7 */ - {"2GHZ", N_("2GHZ"), 10}, /* 8 */ - {"5GHZ", N_("5GHZ"), 10}, /* 9 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"WEP", N_("WEP")}, /* 1 */ + {"WPA", N_("WPA")}, /* 2 */ + {"WPA2", N_("WPA2")}, /* 3 */ + {"TKIP", N_("TKIP")}, /* 4 */ + {"CCMP", N_("CCMP")}, /* 5 */ + {"AP", N_("AP")}, /* 6 */ + {"ADHOC", N_("ADHOC")}, /* 7 */ + {"2GHZ", N_("2GHZ")}, /* 8 */ + {"5GHZ", N_("5GHZ")}, /* 9 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_WIFI_PROP_ALL "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC,2GHZ,5GHZ" #define NMC_FIELDS_DEV_SHOW_WIFI_PROP_COMMON "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC" /* Available fields for 'device show' - wimax properties part */ static NmcOutputField nmc_fields_dev_show_wimax_prop[] = { - {"NAME", N_("NAME"), 18}, /* 0 */ - {"CTR-FREQ", N_("CTR-FREQ"), 7}, /* 1 */ - {"RSSI", N_("RSSI"), 5}, /* 2 */ - {"CINR", N_("CINR"), 5}, /* 3 */ - {"TX-POW", N_("TX-POW"), 5}, /* 4 */ - {"BSID", N_("BSID"), 18}, /* 5 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"CTR-FREQ", N_("CTR-FREQ")}, /* 1 */ + {"RSSI", N_("RSSI")}, /* 2 */ + {"CINR", N_("CINR")}, /* 3 */ + {"TX-POW", N_("TX-POW")}, /* 4 */ + {"BSID", N_("BSID")}, /* 5 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_ALL "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID" #define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_COMMON "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID" /* Available fields for 'device wifi list' */ static NmcOutputField nmc_fields_dev_wifi_list[] = { - {"NAME", N_("NAME"), 15}, /* 0 */ - {"SSID", N_("SSID"), 33}, /* 1 */ - {"SSID-HEX", N_("SSID-HEX"), 66}, /* 2 */ - {"BSSID", N_("BSSID"), 19}, /* 3 */ - {"MODE", N_("MODE"), 16}, /* 4 */ - {"CHAN", N_("CHAN"), 6}, /* 5 */ - {"FREQ", N_("FREQ"), 10}, /* 6 */ - {"RATE", N_("RATE"), 10}, /* 7 */ - {"SIGNAL", N_("SIGNAL"), 8}, /* 8 */ - {"BARS", N_("BARS"), 6}, /* 9 */ - {"SECURITY", N_("SECURITY"), 10}, /* 10 */ - {"WPA-FLAGS", N_("WPA-FLAGS"), 25}, /* 11 */ - {"RSN-FLAGS", N_("RSN-FLAGS"), 25}, /* 12 */ - {"DEVICE", N_("DEVICE"), 10}, /* 13 */ - {"ACTIVE", N_("ACTIVE"), 8}, /* 14 */ - {"IN-USE", N_("*"), 1}, /* 15 */ - {"DBUS-PATH", N_("DBUS-PATH"), 46}, /* 16 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"SSID", N_("SSID")}, /* 1 */ + {"SSID-HEX", N_("SSID-HEX")}, /* 2 */ + {"BSSID", N_("BSSID")}, /* 3 */ + {"MODE", N_("MODE")}, /* 4 */ + {"CHAN", N_("CHAN")}, /* 5 */ + {"FREQ", N_("FREQ")}, /* 6 */ + {"RATE", N_("RATE")}, /* 7 */ + {"SIGNAL", N_("SIGNAL")}, /* 8 */ + {"BARS", N_("BARS")}, /* 9 */ + {"SECURITY", N_("SECURITY")}, /* 10 */ + {"WPA-FLAGS", N_("WPA-FLAGS")}, /* 11 */ + {"RSN-FLAGS", N_("RSN-FLAGS")}, /* 12 */ + {"DEVICE", N_("DEVICE")}, /* 13 */ + {"ACTIVE", N_("ACTIVE")}, /* 14 */ + {"IN-USE", N_("*")}, /* 15 */ + {"DBUS-PATH", N_("DBUS-PATH")}, /* 16 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_WIFI_LIST_ALL "SSID,SSID-HEX,BSSID,MODE,CHAN,FREQ,RATE,SIGNAL,BARS,SECURITY,"\ "WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE,IN-USE,DBUS-PATH" @@ -174,14 +174,14 @@ static NmcOutputField nmc_fields_dev_wifi_list[] = { /* Available fields for 'device wimax list' */ static NmcOutputField nmc_fields_dev_wimax_list[] = { - {"NAME", N_("NAME"), 15}, /* 0 */ - {"NSP", N_("NSP"), 33}, /* 1 */ - {"SIGNAL", N_("SIGNAL"), 8}, /* 2 */ - {"TYPE", N_("TYPE"), 16}, /* 3 */ - {"DEVICE", N_("DEVICE"), 10}, /* 4 */ - {"ACTIVE", N_("ACTIVE"), 8}, /* 5 */ - {"DBUS-PATH", N_("DBUS-PATH"), 46}, /* 6 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"NSP", N_("NSP")}, /* 1 */ + {"SIGNAL", N_("SIGNAL")}, /* 2 */ + {"TYPE", N_("TYPE")}, /* 3 */ + {"DEVICE", N_("DEVICE")}, /* 4 */ + {"ACTIVE", N_("ACTIVE")}, /* 5 */ + {"DBUS-PATH", N_("DBUS-PATH")}, /* 6 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_WIMAX_LIST_ALL "NSP,SIGNAL,TYPE,DEVICE,ACTIVE,DBUS-PATH" #define NMC_FIELDS_DEV_WIMAX_LIST_COMMON "NSP,SIGNAL,TYPE,DEVICE,ACTIVE" @@ -189,28 +189,28 @@ static NmcOutputField nmc_fields_dev_wimax_list[] = { /* Available fields for 'device show' - BOND, TEAM, BRIDGE part */ static NmcOutputField nmc_fields_dev_show_master_prop[] = { - {"NAME", N_("NAME"), 18}, /* 0 */ - {"SLAVES", N_("SLAVES"), 20}, /* 1 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"SLAVES", N_("SLAVES")}, /* 1 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_ALL "NAME,SLAVES" #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_COMMON "NAME,SLAVES" /* Available fields for 'device show' - VLAN part */ static NmcOutputField nmc_fields_dev_show_vlan_prop[] = { - {"NAME", N_("NAME"), 18}, /* 0 */ - {"PARENT", N_("PARENT"), 10}, /* 1 */ - {"ID", N_("ID"), 5}, /* 2 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"PARENT", N_("PARENT")}, /* 1 */ + {"ID", N_("ID")}, /* 2 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_VLAN_PROP_ALL "NAME,PARENT,ID" #define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON "NAME,PARENT,ID" /* Available fields for 'device show' - BLUETOOTH part */ static NmcOutputField nmc_fields_dev_show_bluetooth[] = { - {"NAME", N_("NAME"), 0}, /* 0 */ - {"CAPABILITIES", N_("CAPABILITIES"), 0}, /* 1 */ - {NULL, NULL, 0} + {"NAME", N_("NAME")}, /* 0 */ + {"CAPABILITIES", N_("CAPABILITIES")}, /* 1 */ + {NULL, NULL} }; #define NMC_FIELDS_DEV_SHOW_BLUETOOTH_ALL "NAME,CAPABILITIES" #define NMC_FIELDS_DEV_SHOW_BLUETOOTH_COMMON "NAME,CAPABILITIES" @@ -242,18 +242,36 @@ static NmcOutputField nmc_fields_dev_show_sections[] = { {"CONNECTIONS", N_("CONNECTIONS"), 0, nmc_fields_dev_show_connections + 1 }, /* 16 */ {NULL, NULL, 0, NULL } }; -#if WITH_WIMAX -#define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL "GENERAL,CAPABILITIES,BOND,TEAM,BRIDGE,VLAN,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,"\ - "WIMAX-PROPERTIES,NSP,BLUETOOTH,CONNECTIONS,IP4,DHCP4,IP6,DHCP6" -#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" -#else #define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL "GENERAL,CAPABILITIES,BOND,TEAM,BRIDGE,VLAN,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,"\ "BLUETOOTH,CONNECTIONS,IP4,DHCP4,IP6,DHCP6" #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" -#endif +/* Available fields for 'device lldp' */ +static NmcOutputField nmc_fields_dev_lldp_list[] = { + {"NAME", N_("NAME")}, /* 0 */ + {"DEVICE", N_("DEVICE")}, /* 1 */ + {"CHASSIS-ID", N_("CHASSIS-ID")}, /* 2 */ + {"PORT-ID", N_("PORT-ID")}, /* 3 */ + {"PORT-DESCRIPTION", N_("PORT-DESCRIPTION")}, /* 4 */ + {"SYSTEM-NAME", N_("SYSTEM-NAME")}, /* 5 */ + {"SYSTEM-DESCRIPTION", N_("SYSTEM-DESCRIPTION")}, /* 6 */ + {"SYSTEM-CAPABILITIES", N_("SYSTEM-CAPABILITIES")}, /* 7 */ + {"IEEE-802-1-PVID", N_("IEEE-802-1-PVID")}, /* 8 */ + {"IEEE-802-1-PPVID", N_("IEEE-802-1-PPVID")}, /* 9 */ + {"IEEE-802-1-PPVID-FLAGS", N_("IEEE-802-1-PPVID-FLAGS")}, /* 10 */ + {"IEEE-802-1-VID", N_("IEEE-802-1-VID")}, /* 11 */ + {"IEEE-802-1-VLAN-NAME", N_("IEEE-802-1-VLAN-NAME")}, /* 12 */ + {"DESTINATION", N_("DESTINATION")}, /* 13 */ + {"CHASSIS-ID-TYPE", N_("CHASSIS-ID-TYPE")}, /* 14 */ + {"PORT-ID-TYPE", N_("PORT-ID-TYPE")}, /* 15 */ + {NULL, NULL} +}; +#define NMC_FIELDS_DEV_LLDP_LIST_ALL "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \ + "SYSTEM-CAPABILITIES,IEEE-802-1-PVID,IEEE-802-1-PPVID,IEEE-802-1-PPVID-FLAGS," \ + "IEEE-802-1-VID,IEEE-802-1-VLAN-NAME,DESTINATION,CHASSIS-ID-TYPE,PORT-ID-TYPE" +#define NMC_FIELDS_DEV_LLDP_LIST_COMMON "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \ + "SYSTEM-CAPABILITIES" /* glib main loop variable - defined in nmcli.c */ extern GMainLoop *loop; @@ -264,23 +282,21 @@ static void usage (void) { g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n" -#if WITH_WIMAX - "COMMAND := { status | show | connect | disconnect | delete | wifi | wimax }\n\n" -#else - "COMMAND := { status | show | connect | disconnect | delete | wifi }\n\n" -#endif + "COMMAND := { status | show | connect | reapply | 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" " disconnect <ifname> ...\n\n" " delete <ifname> ...\n\n" + " monitor <ifname> ...\n\n" " wifi [list [ifname <ifname>] [bssid <BSSID>]]\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" -#if WITH_WIMAX - " wimax [list [ifname <ifname>] [nsp <name>]]\n\n" -#endif + " lldp [list [ifname <ifname>]]\n\n" )); } @@ -323,6 +339,17 @@ usage_device_connect (void) } 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_disconnect (void) { g_printerr (_("Usage: nmcli device disconnect { ARGUMENTS | help }\n" @@ -348,6 +375,31 @@ usage_device_delete (void) } 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" @@ -371,6 +423,19 @@ usage_device_wifi (void) "only open, WEP and WPA-PSK networks are supported at the moment. It is also\n" "assumed that IP configuration is obtained via DHCP.\n" "\n" + "ARGUMENTS := wifi 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" @@ -381,20 +446,16 @@ usage_device_wifi (void) "use 'nmcli device wifi list' for that.\n\n")); } -#if WITH_WIMAX static void -usage_device_wimax (void) +usage_device_lldp (void) { - g_printerr (_("Usage: nmcli device wimax { ARGUMENTS | help }\n" + g_printerr (_("Usage: nmcli device lldp { ARGUMENTS | help }\n" "\n" - "Perform operation on WiMAX devices.\n" + "ARGUMENTS := [list [ifname <ifname>]]\n" "\n" - "ARGUMENTS := [list [ifname <ifname>] [nsp <name>]]\n" - "\n" - "List available WiMAX NSPs. The 'ifname' and 'nsp' options can be used to\n" - "list networks for a particular interface, or with a specific NSP.\n\n")); + "List neighboring devices discovered through LLDP. The 'ifname' option can be\n" + "used to list neighbors for a particular interface.\n\n")); } -#endif /* quit main loop */ static void @@ -445,6 +506,117 @@ get_devices_sorted (NMClient *client) return sorted; } +static GSList * +device_list (NmCli *nmc, int argc, char **argv) +{ + int arg_num = argc; + char **arg_arr = NULL; + char **arg_ptr = argv; + NMDevice **devices; + GSList *queue = NULL; + NMDevice *device; + int i; + + if (argc == 0) { + if (nmc->ask) { + char *line = nmc_readline (PROMPT_INTERFACES); + nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num); + g_free (line); + arg_ptr = 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 = get_devices_sorted (nmc->client); + while (arg_num > 0) { + 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 { + 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 (&arg_num, &arg_ptr); + } + g_free (devices); + +error: + g_strfreev (arg_arr); + + return queue; +} + +static int +compare_aps (gconstpointer a, gconstpointer b, gpointer user_data) +{ + NMAccessPoint *apa = *(NMAccessPoint **)a; + NMAccessPoint *apb = *(NMAccessPoint **)b; + int cmp; + + cmp = nm_access_point_get_strength (apb) - nm_access_point_get_strength (apa); + if (cmp != 0) + return cmp; + + cmp = nm_access_point_get_frequency (apa) - nm_access_point_get_frequency (apb); + if (cmp != 0) + return cmp; + + return nm_access_point_get_max_bitrate (apb) - nm_access_point_get_max_bitrate (apa); +} + +static GPtrArray * +sort_access_points (const GPtrArray *aps) +{ + GPtrArray *sorted; + int i; + + sorted = g_ptr_array_sized_new (aps->len); + for (i = 0; aps && i < aps->len; i++) + g_ptr_array_add (sorted, aps->pdata[i]); + g_ptr_array_sort_with_data (sorted, compare_aps, NULL); + return sorted; +} + +typedef struct { + NmcTermColor color; + NmcTermFormat color_fmt; +} ColorInfo; + +static ColorInfo +wifi_signal_to_color (guint8 strength) +{ + ColorInfo color_info = { NMC_TERM_COLOR_NORMAL, NMC_TERM_FORMAT_NORMAL }; + + if (strength > 80) + color_info.color = NMC_TERM_COLOR_GREEN; + else if (strength > 55) + color_info.color = NMC_TERM_COLOR_YELLOW; + else if (strength > 30) + color_info.color = NMC_TERM_COLOR_MAGENTA; + else if (strength > 5) + color_info.color = NMC_TERM_COLOR_CYAN; + else + color_info.color_fmt = NMC_TERM_FORMAT_DIM; + return color_info; +} + static char * ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags) { @@ -514,6 +686,7 @@ fill_output_access_point (gpointer data, gpointer user_data) GString *security_str; char *ap_name; const char *sig_bars; + ColorInfo color_info; if (info->active_bssid) { const char *current_bssid = nm_access_point_get_bssid (ap); @@ -599,59 +772,18 @@ fill_output_access_point (gpointer data, gpointer user_data) set_val_strc (arr, 15, active ? "*" : " "); set_val_strc (arr, 16, nm_object_get_path (NM_OBJECT (ap))); + /* Set colors */ + color_info = wifi_signal_to_color (strength); + set_val_color_all (arr, color_info.color); + set_val_color_fmt_all (arr, color_info.color_fmt); + if (active) + arr[15].color = NMC_TERM_COLOR_GREEN; + g_ptr_array_add (info->nmc->output_data, arr); g_string_free (security_str, FALSE); } -#if WITH_WIMAX -static void -fill_output_wimax_nsp (NMWimaxNsp *nsp, NmCli *nmc, NMDevice *dev, int idx, guint32 o_flags) -{ - NMDeviceWimax *wimax = NM_DEVICE_WIMAX (dev); - char *nsp_name, *quality_str; - const char *ntype; - gboolean active = FALSE; - NmcOutputField *arr; - - switch (nm_wimax_nsp_get_network_type (nsp)) { - case NM_WIMAX_NSP_NETWORK_TYPE_HOME: - ntype = _("Home"); - break; - case NM_WIMAX_NSP_NETWORK_TYPE_PARTNER: - ntype = _("Partner"); - break; - case NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER: - ntype = _("Roaming"); - break; - default: - ntype = _("Unknown"); - break; - } - - if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) { - if (nsp == nm_device_wimax_get_active_nsp (wimax)) - active = TRUE; - } - - quality_str = g_strdup_printf ("%u", nm_wimax_nsp_get_signal_quality (nsp)); - nsp_name = g_strdup_printf ("NSP[%d]", idx); /* NSP */ - - arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list, - sizeof (nmc_fields_dev_wimax_list), - o_flags); - set_val_str (arr, 0, nsp_name); - set_val_strc (arr, 1, nm_wimax_nsp_get_name (nsp)); - set_val_str (arr, 2, quality_str); - set_val_strc (arr, 3, ntype); - set_val_strc (arr, 4, nm_device_get_iface (dev)); - set_val_strc (arr, 5, active ? _("yes") : _("no")); - set_val_strc (arr, 6, nm_object_get_path (NM_OBJECT (nsp))); - - g_ptr_array_add (nmc->output_data, arr); -} -#endif - static char * bluetooth_caps_to_string (NMBluetoothCapabilities caps) { @@ -857,12 +989,12 @@ show_device_info (NMDevice *device, NmCli *nmc) set_val_strc (arr, 16, nm_device_get_managed (device) ? _("yes") : _("no")); set_val_strc (arr, 17, nm_device_get_autoconnect (device) ? _("yes") : _("no")); set_val_strc (arr, 18, nm_device_get_firmware_missing (device) ? _("yes") : _("no")); - set_val_strc (arr, 19, nm_device_get_physical_port_id (device)); - set_val_strc (arr, 20, get_active_connection_id (device)); - set_val_strc (arr, 21, acon ? nm_active_connection_get_uuid (acon) : NULL); - set_val_strc (arr, 22, acon ? nm_object_get_path (NM_OBJECT (acon)) : NULL); - set_val_strc (arr, 23, nmc_device_metered_to_string (nm_device_get_metered (device))); - + set_val_strc (arr, 19, nm_device_get_nm_plugin_missing (device) ? _("yes") : _("no")); + set_val_strc (arr, 20, nm_device_get_physical_port_id (device)); + set_val_strc (arr, 21, get_active_connection_id (device)); + set_val_strc (arr, 22, acon ? nm_active_connection_get_uuid (acon) : NULL); + set_val_strc (arr, 23, acon ? nm_object_get_path (NM_OBJECT (acon)) : NULL); + set_val_strc (arr, 24, nmc_device_metered_to_string (nm_device_get_metered (device))); g_ptr_array_add (nmc->output_data, arr); print_data (nmc); /* Print all data */ @@ -906,7 +1038,7 @@ show_device_info (NMDevice *device, NmCli *nmc) NMDeviceWifiCapabilities wcaps; NMAccessPoint *active_ap = NULL; const char *active_bssid = NULL; - const GPtrArray *aps; + GPtrArray *aps; /* section WIFI-PROPERTIES */ if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[2].name)) { @@ -959,8 +1091,9 @@ show_device_info (NMDevice *device, NmCli *nmc) info->output_flags = NMC_OF_FLAG_SECTION_PREFIX; info->active_bssid = active_bssid; info->device = nm_device_get_iface (device); - aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + aps = sort_access_points (nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device))); g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info); + g_ptr_array_free (aps, FALSE); g_free (info); print_data (nmc); /* Print all data */ was_output = TRUE; @@ -979,84 +1112,13 @@ show_device_info (NMDevice *device, NmCli *nmc) set_val_strc (arr, 0, nmc_fields_dev_show_sections[4].name); /* "WIRED-PROPERTIES" */ set_val_strc (arr, 1, (nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device))) ? _("on") : _("off")); + set_val_arrc (arr, 2, ((const char **) nm_device_ethernet_get_s390_subchannels (NM_DEVICE_ETHERNET (device)))); g_ptr_array_add (nmc->output_data, arr); print_data (nmc); /* Print all data */ was_output = TRUE; } } -#if WITH_WIMAX - else if (NM_IS_DEVICE_WIMAX (device)) { - /* WIMAX-PROPERTIES */ - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[5].name)) { - char *cfreq = NULL, *rssi = NULL, *cinr = NULL, *txpow = NULL; - guint tmp_uint; - gint tmp_int; - - /* Field names */ - tmpl = nmc_fields_dev_show_wimax_prop; - tmpl_len = sizeof (nmc_fields_dev_show_wimax_prop); - nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_WIMAX_PROP_ALL, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); - - /* Center frequency */ - tmp_uint = nm_device_wimax_get_center_frequency (NM_DEVICE_WIMAX (device)); - if (tmp_uint) - cfreq = g_strdup_printf ("%'.1f MHz", (double) tmp_uint / 1000.0); - - /* RSSI */ - tmp_int = nm_device_wimax_get_rssi (NM_DEVICE_WIMAX (device)); - if (tmp_int) - rssi = g_strdup_printf ("%d dBm", tmp_int); - - /* CINR */ - tmp_int = nm_device_wimax_get_cinr (NM_DEVICE_WIMAX (device)); - if (tmp_int) - cinr = g_strdup_printf ("%d dB", tmp_int); - - /* TX Power */ - tmp_int = nm_device_wimax_get_tx_power (NM_DEVICE_WIMAX (device)); - if (tmp_int) - txpow = g_strdup_printf ("%'.2f dBm", (float) tmp_int / 2.0); - - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc (arr, 0, nmc_fields_dev_show_sections[5].name); /* "WIMAX-PROPERTIES" */ - set_val_str (arr, 1, cfreq); - set_val_str (arr, 2, rssi); - set_val_str (arr, 3, cinr); - set_val_str (arr, 4, txpow); - set_val_strc (arr, 5, nm_device_wimax_get_bsid (NM_DEVICE_WIMAX (device))); - g_ptr_array_add (nmc->output_data, arr); - - print_data (nmc); /* Print all data */ - was_output = TRUE; - } - - /* section NSP */ - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[6].name)) { - const GPtrArray *nsps; - int g, idx = 1; - - tmpl = nmc_fields_dev_wimax_list; - tmpl_len = sizeof (nmc_fields_dev_wimax_list); - nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); - - nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device)); - for (g = 0; g < nsps->len; g++) { - NMWimaxNsp *nsp = g_ptr_array_index (nsps, g); - - fill_output_wimax_nsp (nsp, nmc, device, idx++, NMC_OF_FLAG_SECTION_PREFIX); - } - print_data (nmc); /* Print all data */ - was_output = TRUE; - } - } -#endif /* IP configuration info */ cfg4 = nm_device_get_ip4_config (device); @@ -1201,19 +1263,43 @@ show_device_info (NMDevice *device, NmCli *nmc) return TRUE; } +static ColorInfo +device_state_to_color (NMDeviceState state) +{ + ColorInfo color_info = { NMC_TERM_COLOR_NORMAL, NMC_TERM_FORMAT_NORMAL }; + + if (state <= NM_DEVICE_STATE_UNAVAILABLE) + color_info.color_fmt= NMC_TERM_FORMAT_DIM; + else if (state == NM_DEVICE_STATE_DISCONNECTED) + color_info.color = NMC_TERM_COLOR_RED; + else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) + color_info.color = NMC_TERM_COLOR_YELLOW; + else if (state == NM_DEVICE_STATE_ACTIVATED) + color_info.color = NMC_TERM_COLOR_GREEN; + return color_info; +} + static void fill_output_device_status (NMDevice *device, NmCli *nmc) { NMActiveConnection *ac; + NMDeviceState state; + ColorInfo color_info; NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status, sizeof (nmc_fields_dev_status), 0); + state = nm_device_get_state (device); ac = nm_device_get_active_connection (device); + /* Show devices in color */ + color_info = device_state_to_color (state); + set_val_color_all (arr, color_info.color); + set_val_color_fmt_all (arr, color_info.color_fmt); + set_val_strc (arr, 0, nm_device_get_iface (device)); set_val_strc (arr, 1, nm_device_get_type_description (device)); - set_val_strc (arr, 2, nmc_device_state_to_string (nm_device_get_state (device))); + set_val_strc (arr, 2, nmc_device_state_to_string (state)); set_val_strc (arr, 3, nm_object_get_path (NM_OBJECT (device))); set_val_strc (arr, 4, get_active_connection_id (device)); set_val_strc (arr, 5, ac ? nm_active_connection_get_uuid (ac) : NULL); @@ -1408,6 +1494,7 @@ connected_state_cb (NMDevice *device, NMActiveConnection *active) typedef struct { NmCli *nmc; NMDevice *device; + gboolean hotspot; } AddAndActivateInfo; static void @@ -1425,8 +1512,12 @@ add_and_activate_cb (GObject *client, active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); if (error) { - g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"), - error->message); + if (info->hotspot) + g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"), + error->message); + else + g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"), + error->message); g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; quit (); @@ -1434,7 +1525,10 @@ add_and_activate_cb (GObject *client, state = nm_active_connection_get_state (active); if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { - g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error")); + if (info->hotspot) + g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot")); + else + g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error")); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; g_object_unref (active); quit (); @@ -1445,8 +1539,12 @@ add_and_activate_cb (GObject *client, if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { if (nmc->print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); - g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"), - nm_active_connection_get_uuid (active), nm_device_get_iface (device)); + if (info->hotspot) + g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"), + nm_active_connection_get_uuid (active), nm_device_get_iface (device)); + else + g_print (_("Hotspot '%s' activated on device '%s'\n"), + nm_active_connection_get_id (active), nm_device_get_iface (device)); } g_object_unref (active); quit (); @@ -1615,7 +1713,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv) * till connect_device_cb() is called, giving NM time to check our permissions. */ nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait = TRUE; + nmc->should_wait++; /* Create secret agent */ nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect"); @@ -1625,6 +1723,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv) info = g_malloc0 (sizeof (AddAndActivateInfo)); info->nmc = nmc; info->device = device; + info->hotspot = FALSE; nm_client_activate_connection_async (nmc->client, NULL, /* let NM find a connection automatically */ @@ -1727,17 +1826,16 @@ device_cb_info_finish (DeviceCbInfo *info, NMDevice *device) } static void -disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) +reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) { NMDevice *device = NM_DEVICE (object); DeviceCbInfo *info = (DeviceCbInfo *) user_data; NmCli *nmc = info->nmc; - NMDeviceState state; GError *error = NULL; - if (!nm_device_disconnect_finish (device, result, &error)) { - g_string_printf (nmc->return_text, _("Error: not all devices disconnected.")); - g_printerr (_("Error: Device '%s' (%s) disconnecting failed: %s\n"), + if (!nm_device_reapply_finish (device, result, &error)) { + g_string_printf (nmc->return_text, _("Error: not all connections reapplied.")); + g_printerr (_("Error: Reapplying connection to device '%s' (%s) failed: %s\n"), nm_device_get_iface (device), nm_object_get_path (NM_OBJECT (device)), error->message); @@ -1745,23 +1843,16 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; device_cb_info_finish (info, device); } else { - 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->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); - } + if (nmc->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 NMCResultCode -do_device_disconnect (NmCli *nmc, int argc, char **argv) +do_device_reapply (NmCli *nmc, int argc, char **argv) { NMDevice **devices; NMDevice *device; @@ -1772,7 +1863,7 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) int arg_num = argc; int i; - /* Set default timeout for disconnect operation. */ + /* Set default timeout for reapply operation. */ if (nmc->timeout == -1) nmc->timeout = 10; @@ -1825,6 +1916,76 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) info = g_slice_new0 (DeviceCbInfo); info->nmc = nmc; + + nmc->nowait_flag = (nmc->timeout == 0); + nmc->should_wait = TRUE; + + for (iter = queue; iter; iter = g_slist_next (iter)) { + device = iter->data; + + 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, NULL, reapply_device_cb, info); + } + +error: + g_strfreev (arg_arr); + g_slist_free (queue); + return nmc->return_value; +} + +static void +disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (object); + DeviceCbInfo *info = (DeviceCbInfo *) user_data; + NmCli *nmc = info->nmc; + NMDeviceState state; + GError *error = NULL; + + if (!nm_device_disconnect_finish (device, result, &error)) { + 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 { + 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->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 NMCResultCode +do_device_disconnect (NmCli *nmc, int argc, char **argv) +{ + NMDevice *device; + DeviceCbInfo *info = NULL; + GSList *queue, *iter; + + /* Set default timeout for disconnect operation. */ + if (nmc->timeout == -1) + nmc->timeout = 10; + + queue = device_list (nmc, argc, argv); + if (!queue) + goto error; + queue = g_slist_reverse (queue); + + info = g_slice_new0 (DeviceCbInfo); + info->nmc = nmc; info->cmd_disconnect = TRUE; if (nmc->timeout > 0) info->timeout_id = g_timeout_add_seconds (nmc->timeout, device_op_timeout_cb, info); @@ -1833,7 +1994,7 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) G_CALLBACK (device_removed_cb), info); nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait = TRUE; + nmc->should_wait++; for (iter = queue; iter; iter = g_slist_next (iter)) { device = iter->data; @@ -1847,7 +2008,6 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) } error: - g_strfreev (arg_arr); g_slist_free (queue); return nmc->return_value; } @@ -1878,71 +2038,17 @@ delete_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) static NMCResultCode do_device_delete (NmCli *nmc, int argc, char **argv) { - NMDevice **devices; NMDevice *device; DeviceCbInfo *info = NULL; - GSList *queue = NULL, *iter; - char **arg_arr = NULL; - char **arg_ptr = argv; - int arg_num = argc; - int i; + GSList *queue, *iter; /* Set default timeout for delete operation. */ if (nmc->timeout == -1) nmc->timeout = 10; - if (argc == 0) { - if (nmc->ask) { - char *line = nmc_readline (PROMPT_INTERFACES); - nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num); - g_free (line); - arg_ptr = 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 = get_devices_sorted (nmc->client); - while (arg_num > 0) { - 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)) { - if (nm_device_is_software (device)) - queue = g_slist_prepend (queue, device); - else { - g_printerr (_("Error: Device '%s' is a hardware device. It can't be deleted.\n"), - *arg_ptr); - g_string_printf (nmc->return_text, _("Error: not all devices valid.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - } - } else - g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr); - } else { - 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 (&arg_num, &arg_ptr); - } - g_free (devices); - - if (!queue) { - g_string_printf (nmc->return_text, _("Error: no valid device provided.")); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + queue = device_list (nmc, argc, argv); + if (!queue) goto error; - } queue = g_slist_reverse (queue); info = g_slice_new0 (DeviceCbInfo); @@ -1954,7 +2060,7 @@ do_device_delete (NmCli *nmc, int argc, char **argv) G_CALLBACK (device_removed_cb), info); nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait = TRUE; + nmc->should_wait++; for (iter = queue; iter; iter = g_slist_next (iter)) { device = iter->data; @@ -1966,17 +2072,225 @@ do_device_delete (NmCli *nmc, int argc, char **argv) } error: - g_strfreev (arg_arr); g_slist_free (queue); return nmc->return_value; } +static NMCResultCode +do_device_set (NmCli *nmc, int argc, char **argv) +{ +#define DEV_SET_AUTOCONNECT 0 +#define DEV_SET_MANAGED 1 + NMDevice **devices; + NMDevice *device = NULL; + const char *ifname = NULL; + int i; + struct { + int idx; + gboolean value; + } values[2] = { + [DEV_SET_AUTOCONNECT] = { -1 }, + [DEV_SET_MANAGED] = { -1 }, + }; + + if (argc >= 1 && g_strcmp0 (*argv, "ifname") == 0) { + argc--; + argv++; + } + + if (argc == 0) { + g_string_printf (nmc->return_text, _("Error: No interface specified.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } else + ifname = *argv; + + if (!ifname) { + g_string_printf (nmc->return_text, _("Error: No interface specified.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + + devices = get_devices_sorted (nmc->client); + for (i = 0; devices[i]; i++) { + NMDevice *candidate = devices[i]; + const char *dev_iface = nm_device_get_iface (candidate); + + if (!g_strcmp0 (dev_iface, ifname)) + device = candidate; + } + g_free (devices); + + if (!device) { + g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + goto error; + } + + if (argc == 1) { + g_string_printf (nmc->return_text, _("Error: No property specified.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + + i = 0; + while (next_arg (&argc, &argv) == 0) { + gboolean flag; + gs_free_error GError *tmp_err = NULL; + + if (matches (*argv, "managed") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + if (!nmc_string_to_bool (*argv, &flag, &tmp_err)) { + g_string_printf (nmc->return_text, _("Error: 'managed': %s."), + tmp_err->message); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + values[DEV_SET_MANAGED].idx = ++i; + values[DEV_SET_MANAGED].value = flag; + } + else if (matches (*argv, "autoconnect") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + if (!nmc_string_to_bool (*argv, &flag, &tmp_err)) { + g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."), + tmp_err->message); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + values[DEV_SET_AUTOCONNECT].idx = ++i; + values[DEV_SET_AUTOCONNECT].value = flag; + } + else { + usage_device_set (); + g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + } + + /* 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); + +error: + quit (); + return nmc->return_value; +} + +static void +device_state (NMDevice *device, GParamSpec *pspec, NmCli *nmc) +{ + NMDeviceState state = nm_device_get_state (device); + ColorInfo color = device_state_to_color (state); + char *str = nmc_colorize (nmc, color.color, color.color_fmt, "%s: %s\n", + nm_device_get_iface (device), + nmc_device_state_to_string (state)); + + g_print ("%s", str); + g_free (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 NMCResultCode +do_device_monitor (NmCli *nmc, int argc, char **argv) +{ + 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 { + /* Monitor just the specified devices. */ + GSList *queue = device_list (nmc, argc, argv); + GSList *iter; + + if (!queue) + return nmc->return_value; + + 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); + + return NMC_RESULT_SUCCESS; +} + static void show_access_point_info (NMDevice *device, NmCli *nmc) { NMAccessPoint *active_ap = NULL; const char *active_bssid = NULL; - const GPtrArray *aps; + GPtrArray *aps; APInfo *info; NmcOutputField *arr; @@ -1995,8 +2309,9 @@ show_access_point_info (NMDevice *device, NmCli *nmc) info->output_flags = 0; info->active_bssid = active_bssid; info->device = nm_device_get_iface (device); - aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + aps = sort_access_points (nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device))); g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info); + g_ptr_array_free (aps, FALSE); print_data (nmc); /* Print all data */ nmc_empty_output_fields (nmc); @@ -2566,7 +2881,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) { /* Ask for missing password when one is expected and '--ask' is used */ if (!password && nmc->ask) - password = passwd_ask = nmc_readline (_("Password: ")); + password = passwd_ask = nmc_readline_echo (nmc->show_secrets, _("Password: ")); if (password) { if (!connection) @@ -2600,11 +2915,12 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) * 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 = TRUE; + nmc->should_wait++; info = g_malloc0 (sizeof (AddAndActivateInfo)); info->nmc = nmc; info->device = device; + info->hotspot = FALSE; nm_client_add_and_activate_connection_async (nmc->client, connection, @@ -2625,6 +2941,345 @@ error: return nmc->return_value; } +static GBytes * +generate_ssid_for_hotspot (const char *ssid) +{ + GBytes *ssid_bytes; + char *hotspot_ssid = NULL; + + if (!ssid) { + hotspot_ssid = g_strdup_printf ("Hotspot-%s", g_get_host_name ()); + if (strlen (hotspot_ssid) > 32) + hotspot_ssid[32] = '\0'; + ssid = hotspot_ssid; + } + ssid_bytes = g_bytes_new (ssid, strlen (ssid)); + g_free (hotspot_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] = (gchar) 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 NMCResultCode +do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) +{ + AddAndActivateInfo *info; + const char *ifname = NULL; + const char *con_name = NULL; + char *default_name = NULL; + const char *ssid = NULL; + const char *wifi_mode; + const char *band = NULL; + const char *channel = NULL; + unsigned long channel_int; + const char *password = NULL; + gboolean show_password = FALSE; + NMDevice *device = NULL; + int devices_idx; + const GPtrArray *devices; + NMDeviceWifiCapabilities caps; + NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSettingIPConfig *s_ip4, *s_ip6; + GBytes *ssid_bytes; + GError *error = NULL; + + /* Set default timeout waiting for operation completion. */ + if (nmc->timeout == -1) + nmc->timeout = 60; + + while (argc > 0) { + if (strcmp (*argv, "ifname") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + ifname = *argv; + } else if (strcmp (*argv, "con-name") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + con_name = *argv; + } else if (strcmp (*argv, "ssid") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + ssid = *argv; + if (strlen (ssid) > 32) { + g_string_printf (nmc->return_text, _("Error: ssid is too long.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + } else if (strcmp (*argv, "band") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + band = *argv; + 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; + goto error; + } + } else if (strcmp (*argv, "channel") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + channel = *argv; + } else if (strcmp (*argv, "password") == 0) { + if (next_arg (&argc, &argv) != 0) { + g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + 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: Unknown parameter %s."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + + argc--; + argv++; + } + show_password = nmc->show_secrets || show_password; + + /* 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) { + if (!band) { + g_string_printf (nmc->return_text, _("Error: channel requires band too.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + if ( !nmc_string_to_uint (channel, TRUE, 1, 5825, &channel_int) + || !nm_utils_wifi_is_channel_valid (channel_int, 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; + goto error; + } + } + + /* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */ + devices = nm_client_get_devices (nmc->client); + 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 error; + } + + /* 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; + goto error; + } + + /* Create a connection with appropriate parameters */ + 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 (nm_client_get_connections (nmc->client), "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)); + ssid_bytes = generate_ssid_for_hotspot (ssid); + g_object_set (s_wifi, NM_SETTING_WIRELESS_MODE, wifi_mode, + NM_SETTING_WIRELESS_SSID, ssid_bytes, + NULL); + g_bytes_unref (ssid_bytes); + if (channel) + 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)); + if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) { + g_object_unref (connection); + g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + g_clear_error (&error); + goto error; + } + + 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); + + /* Activate the connection now */ + nmc->nowait_flag = (nmc->timeout == 0); + nmc->should_wait = TRUE; + + info = g_malloc0 (sizeof (AddAndActivateInfo)); + info->nmc = nmc; + info->device = device; + info->hotspot = TRUE; + + nm_client_add_and_activate_connection_async (nmc->client, + connection, + device, + NULL, + NULL, + add_and_activate_cb, + info); + +error: + return nmc->return_value; +} + static void request_rescan_cb (GObject *object, GAsyncResult *result, gpointer user_data) { @@ -2653,8 +3308,6 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) const char *ssid; int i; - nmc->should_wait = TRUE; - ssids = g_ptr_array_new (); /* Get the parameters */ @@ -2722,7 +3375,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) g_ptr_array_free (ssids, FALSE); return nmc->return_value; error: - nmc->should_wait = FALSE; + nmc->should_wait++; g_ptr_array_free (ssids, FALSE); return nmc->return_value; } @@ -2737,6 +3390,8 @@ do_device_wifi (NmCli *nmc, int argc, char **argv) nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1); } else if (matches (*argv, "connect") == 0) { nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1); + } else if (matches (*argv, "hotspot") == 0) { + nmc->return_value = do_device_wifi_hotspot (nmc, argc-1, argv+1); } else if (matches (*argv, "rescan") == 0) { nmc->return_value = do_device_wifi_rescan (nmc, argc-1, argv+1); } else { @@ -2748,46 +3403,98 @@ do_device_wifi (NmCli *nmc, int argc, char **argv) return nmc->return_value; } -#if WITH_WIMAX -static void -show_nsp_info (NMDevice *device, NmCli *nmc) +static int +show_device_lldp_list (NMDevice *device, NmCli *nmc, char *fields_str, int *counter) { - const GPtrArray *nsps; - int i, idx = 1; - NmcOutputField *arr; + NmcOutputField *tmpl, *arr; + GPtrArray *neighbors; + size_t tmpl_len; + const char *str; + int i; - /* Add headers (field names) */ - arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list, sizeof (nmc_fields_dev_wimax_list), - NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); + neighbors = nm_device_get_lldp_neighbors (device); + + if (!neighbors || !neighbors->len) + return 0; + + tmpl = nmc_fields_dev_lldp_list; + tmpl_len = sizeof (nmc_fields_dev_lldp_list); + + /* Main header name */ + nmc->print_fields.header_name = (char *) construct_header_name (_("Device LLDP neighbors"), + nm_device_get_iface (device)); + nmc->print_fields.indices = parse_output_fields (fields_str, nmc_fields_dev_lldp_list, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); g_ptr_array_add (nmc->output_data, arr); - nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device)); - for (i = 0; i < nsps->len; i++) { - NMWimaxNsp *nsp = g_ptr_array_index (nsps, i); + for (i = 0; i < neighbors->len; i++) { + NMLldpNeighbor *neighbor = neighbors->pdata[i]; + guint value; + + arr = nmc_dup_fields_array (tmpl, tmpl_len, 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); - fill_output_wimax_nsp (nsp, nmc, device, idx++, 0); + 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)) + set_val_str (arr, 7, g_strdup_printf ("%u (%s)", value, 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, g_strdup_printf ("%u", value)); + + if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID, &value)) + set_val_str (arr, 9, g_strdup_printf ("%u", value)); + + if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, &value)) + set_val_str (arr, 10, g_strdup_printf ("%u", value)); + + if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VID, &value)) + set_val_str (arr, 11, g_strdup_printf ("%u", 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_strc (arr, 14, g_strdup_printf ("%u", value)); + + if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_PORT_ID_TYPE, &value)) + set_val_strc (arr, 15, g_strdup_printf ("%u", value)); + + g_ptr_array_add (nmc->output_data, arr); } - print_data (nmc); /* Print all data */ + + print_data (nmc); nmc_empty_output_fields (nmc); + + return neighbors->len; } -static NMCResultCode -do_device_wimax_list (NmCli *nmc, int argc, char **argv) +static gboolean +do_device_lldp_list (NmCli *nmc, int argc, char **argv) { + NMDevice *device = NULL, **devices = NULL; GError *error = NULL; - NMDevice *device = NULL; - NMWimaxNsp *nsp = NULL; const char *ifname = NULL; - const char *nsp_user = NULL; - const GPtrArray *devices; - const GPtrArray *nsps; - int i, j; char *fields_str; - char *fields_all = NMC_FIELDS_DEV_WIMAX_LIST_ALL; - char *fields_common = NMC_FIELDS_DEV_WIMAX_LIST_COMMON; - NmcOutputField *tmpl, *arr; - size_t tmpl_len; - const char *base_hdr = _("WiMAX NSP list"); + int i, counter = 0; while (argc > 0) { if (strcmp (*argv, "ifname") == 0) { @@ -2797,44 +3504,43 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv) goto error; } ifname = *argv; - } else if (strcmp (*argv, "nsp") == 0) { - if (next_arg (&argc, &argv) != 0) { - g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } - nsp_user = *argv; } else { - g_printerr (_("Unknown parameter: %s\n"), *argv); + g_string_printf (nmc->return_text, _("Error: unknown parameter: %s"), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; } argc--; argv++; } + if (argc > 0) { + g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; + } + if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) - fields_str = fields_common; + fields_str = NMC_FIELDS_DEV_LLDP_LIST_COMMON; else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) - fields_str = fields_all; + fields_str = NMC_FIELDS_DEV_LLDP_LIST_ALL; else fields_str = nmc->required_fields; - tmpl = nmc_fields_dev_wimax_list; - tmpl_len = sizeof (nmc_fields_dev_wimax_list); - nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error); + nmc->print_fields.indices = parse_output_fields (fields_str, nmc_fields_dev_lldp_list, FALSE, NULL, &error); if (error) { - g_string_printf (nmc->return_text, _("Error: 'device wimax': %s"), error->message); + g_string_printf (nmc->return_text, _("Error: 'device lldp list': %s"), error->message); g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return nmc->return_value; } - devices = nm_client_get_devices (nmc->client); + devices = get_devices_sorted (nmc->client); + if (ifname) { - /* Device specified - list only NSPs of this interface */ - for (i = 0; i < devices->len; i++) { - NMDevice *candidate = g_ptr_array_index (devices, i); + for (i = 0; devices[i]; i++) { + NMDevice *candidate = devices[i]; const char *dev_iface = nm_device_get_iface (candidate); if (!g_strcmp0 (dev_iface, ifname)) { @@ -2849,126 +3555,34 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv) goto error; } - /* Main header name */ - nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname); - - if (NM_IS_DEVICE_WIMAX (device)) { - if (nsp_user) { - /* Specific NSP requested - list only that */ - nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device)); - for (j = 0, nsp = NULL; j < nsps->len; j++) { - NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j); - const char *candidate_name = nm_wimax_nsp_get_name (candidate_nsp); - char *nsp_up; - - nsp_up = g_ascii_strup (nsp_user, -1); - if (!strcmp (nsp_up, candidate_name)) - nsp = candidate_nsp; - g_free (nsp_up); - } - if (!nsp) { - g_string_printf (nmc->return_text, _("Error: NSP with name '%s' not found."), nsp_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; - } - /* Add headers (field names) */ - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); - fill_output_wimax_nsp (nsp, nmc, device, 1, 0); - print_data (nmc); /* Print all data */ - } else { - show_nsp_info (device, nmc); - } - } else { - g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), ifname); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; - } + nmc_empty_output_fields (nmc); + show_device_lldp_list (device, nmc, fields_str, &counter); } else { - gboolean empty_line = FALSE; - - /* List NSPs for all devices */ - if (nsp_user) { - /* Specific NSP requested - list only that */ - for (i = 0; i < devices->len; i++) { - NMDevice *dev = g_ptr_array_index (devices, i); - int idx = 1; - - if (!NM_IS_DEVICE_WIMAX (dev)) - continue; - - /* Main header name */ - nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (dev)); - nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, NULL); - - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); - - nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (dev)); - for (j = 0, nsp = NULL; j < nsps->len; j++) { - NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j); - const char *candidate_name = nm_wimax_nsp_get_name (candidate_nsp); - char *nsp_up; - - nsp_up = g_ascii_strup (nsp_user, -1); - if (!strcmp (nsp_up, candidate_name)) { - nsp = candidate_nsp; - fill_output_wimax_nsp (nsp, nmc, dev, idx, 0); - } - g_free (nsp_up); - } - if (empty_line) - g_print ("\n"); /* Empty line between devices' NSPs */ - print_data (nmc); /* Print all data */ - nmc_empty_output_fields (nmc); - empty_line = TRUE; - } - if (!nsp) { - g_string_printf (nmc->return_text, _("Error: Access point with nsp '%s' not found."), nsp_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; - } - } else { - for (i = 0; i < devices->len; i++) { - NMDevice *dev = g_ptr_array_index (devices, i); - - /* Main header name */ - nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, - nm_device_get_iface (dev)); - nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, NULL); - - if (NM_IS_DEVICE_WIMAX (dev)) { - if (empty_line) - g_print ("\n"); /* Empty line between devices' NSPs */ - show_nsp_info (dev, nmc); - empty_line = TRUE; - } - } + for (i = 0; devices[i]; i++) { + nmc_empty_output_fields (nmc); + show_device_lldp_list (devices[i], nmc, fields_str, &counter); } } error: + g_free (devices); return nmc->return_value; } static NMCResultCode -do_device_wimax (NmCli *nmc, int argc, char **argv) +do_device_lldp (NmCli *nmc, int argc, char **argv) { if (argc == 0) - nmc->return_value = do_device_wimax_list (nmc, argc-1, argv+1); - else if (argc > 0) { - if (matches (*argv, "list") == 0) { - nmc->return_value = do_device_wimax_list (nmc, argc-1, argv+1); - } - else { - g_string_printf (nmc->return_text, _("Error: 'device wimax' command '%s' is not valid."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - } + nmc->return_value = do_device_lldp_list (nmc, argc, argv); + else if (matches (*argv, "list") == 0) + nmc->return_value = do_device_lldp_list (nmc, argc-1, argv+1); + else { + g_string_printf (nmc->return_text, _("Error: 'device lldp' command '%s' is not valid."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; } return nmc->return_value; } -#endif static gboolean is_single_word (const char* line) @@ -3101,6 +3715,13 @@ do_devices (NmCli *nmc, int argc, char **argv) } nmc->return_value = do_device_connect (nmc, argc-1, argv+1); } + else if (matches (*argv, "reapply") == 0) { + if (nmc_arg_is_help (*(argv+1))) { + usage_device_reapply (); + goto usage_exit; + } + nmc->return_value = do_device_reapply (nmc, argc-1, argv+1); + } else if (matches (*argv, "disconnect") == 0) { if (nmc_arg_is_help (*(argv+1))) { usage_device_disconnect (); @@ -3115,6 +3736,20 @@ do_devices (NmCli *nmc, int argc, char **argv) } nmc->return_value = do_device_delete (nmc, argc-1, argv+1); } + else if (matches (*argv, "set") == 0) { + if (nmc_arg_is_help (*(argv+1))) { + usage_device_set (); + goto usage_exit; + } + nmc->return_value = do_device_set (nmc, argc-1, argv+1); + } + else if (matches (*argv, "monitor") == 0) { + if (nmc_arg_is_help (*(argv+1))) { + usage_device_monitor (); + goto usage_exit; + } + nmc->return_value = do_device_monitor (nmc, argc-1, argv+1); + } else if (matches (*argv, "wifi") == 0) { if (nmc_arg_is_help (*(argv+1))) { usage_device_wifi (); @@ -3124,17 +3759,17 @@ do_devices (NmCli *nmc, int argc, char **argv) goto opt_error; nmc->return_value = do_device_wifi (nmc, argc-1, argv+1); } -#if WITH_WIMAX - else if (matches (*argv, "wimax") == 0) { + else if (matches (*argv, "lldp") == 0) { if (nmc_arg_is_help (*(argv+1))) { - usage_device_wimax (); + usage_device_lldp (); goto usage_exit; } if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) goto opt_error; - nmc->return_value = do_device_wimax (nmc, argc-1, argv+1); + if (!nmc->mode_specified) + nmc->multiline_output = TRUE; /* multiline mode is default for 'device lldp' */ + nmc->return_value = do_device_lldp (nmc, argc-1, argv+1); } -#endif else { usage (); g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv); @@ -3151,3 +3786,9 @@ opt_error: g_error_free (error); return nmc->return_value; } + +void +monitor_devices (NmCli *nmc) +{ + do_device_monitor (nmc, 0, NULL); +} |