diff options
author | Thomas Haller <thaller@redhat.com> | 2023-02-09 14:38:26 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2023-02-13 10:32:45 +0100 |
commit | 004ffb91cfaedfa2e2d7fdf38f65231f45e66845 (patch) | |
tree | 86a7ff8be5e639bd9d433d435ddc555d137b54e0 | |
parent | a798b4f3f6e0f77dd9019178fff48beefa5c7dc9 (diff) | |
download | NetworkManager-004ffb91cfaedfa2e2d7fdf38f65231f45e66845.tar.gz |
examples: rework "python/gi/show-wifi-networks.py" example
- only printing the scan list is not gonna cut it. It's usually stale,
and we need to request a new scan.
- don't hard-code the GEnum and GFlags values that we understand. We
have libnm, which provides us some meta information about the data.
Use it.
- Some code cleanup.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1531
-rwxr-xr-x | examples/python/gi/show-wifi-networks.py | 249 |
1 files changed, 159 insertions, 90 deletions
diff --git a/examples/python/gi/show-wifi-networks.py b/examples/python/gi/show-wifi-networks.py index eb71c4c441..edc712a041 100755 --- a/examples/python/gi/show-wifi-networks.py +++ b/examples/python/gi/show-wifi-networks.py @@ -5,10 +5,17 @@ # import locale +import math +import os +import re +import time + import gi gi.require_version("NM", "1.0") -from gi.repository import NM +from gi.repository import NM, GLib, Gio + +SCAN_THRESHOLD_MSEC = 10000 # # This example lists Wi-Fi access points NetworkManager scanned on Wi-Fi devices. @@ -19,116 +26,165 @@ from gi.repository import NM # an error without it: http://www.python.org/dev/peps/pep-0263/ # +NM80211Mode = getattr(NM, "80211Mode") +NM80211ApFlags = getattr(NM, "80211ApFlags") +NM80211ApSecurityFlags = getattr(NM, "80211ApSecurityFlags") -def clamp(value, minvalue, maxvalue): - return max(minvalue, min(value, maxvalue)) - - -def ssid_to_utf8(ap): - ssid = ap.get_ssid() - if not ssid: - return "" - return NM.utils_ssid_to_utf8(ap.get_ssid().get_data()) - - -def print_device_info(device): - active_ap = dev.get_active_access_point() - ssid = None - if active_ap is not None: - ssid = ssid_to_utf8(active_ap) - info = "Device: %s | Driver: %s | Active AP: %s" % ( - dev.get_iface(), - dev.get_driver(), - ssid, - ) - print(info) - print("=" * len(info)) - - -def mode_to_string(mode): - if mode == getattr(NM, "80211Mode").INFRA: - return "INFRA" - if mode == getattr(NM, "80211Mode").ADHOC: - return "ADHOC" - if mode == getattr(NM, "80211Mode").AP: - return "AP" - return "UNKNOWN" +main_loop = GLib.MainLoop() -def flags_to_string(flags): - if flags & getattr(NM, "80211ApFlags").PRIVACY: - return "PRIVACY" - return "NONE" +def gflags_to_str(flags_type, value): + if value == 0: + return "none" + str = "" + for n in sorted(dir(flags_type)): + if not re.search("^[A-Z0-9_]+$", n): + continue + flag_value = getattr(flags_type, n) + if value & flag_value: + value &= ~flag_value + str += " " + n + if value == 0: + break + if value: + str += " (0x%0x)" % (value,) + return str.lstrip() -def security_flags_to_string(flags): - NM_AP_FLAGS = getattr(NM, "80211ApSecurityFlags") - str = "" - if flags & NM_AP_FLAGS.PAIR_WEP40: - str = str + " PAIR_WEP40" - if flags & NM_AP_FLAGS.PAIR_WEP104: - str = str + " PAIR_WEP104" - if flags & NM_AP_FLAGS.PAIR_TKIP: - str = str + " PAIR_TKIP" - if flags & NM_AP_FLAGS.PAIR_CCMP: - str = str + " PAIR_CCMP" - if flags & NM_AP_FLAGS.GROUP_WEP40: - str = str + " GROUP_WEP40" - if flags & NM_AP_FLAGS.GROUP_WEP104: - str = str + " GROUP_WEP104" - if flags & NM_AP_FLAGS.GROUP_TKIP: - str = str + " GROUP_TKIP" - if flags & NM_AP_FLAGS.GROUP_CCMP: - str = str + " GROUP_CCMP" - if flags & NM_AP_FLAGS.KEY_MGMT_PSK: - str = str + " KEY_MGMT_PSK" - if flags & NM_AP_FLAGS.KEY_MGMT_802_1X: - str = str + " KEY_MGMT_802_1X" - if str: - return str.lstrip() - else: - return "NONE" +def genum_to_str(enum_type, value): + for n in sorted(dir(enum_type)): + if not re.search("^[A-Z0-9_]+$", n): + continue + enum_value = getattr(enum_type, n) + if value == enum_value: + return n + return "(%d" % (value,) -def flags_to_security(flags, wpa_flags, rsn_flags): +def ap_security_flags_to_security(flags, wpa_flags, rsn_flags): str = "" - if ( - (flags & getattr(NM, "80211ApFlags").PRIVACY) - and (wpa_flags == 0) - and (rsn_flags == 0) - ): + if (flags & NM80211ApFlags.PRIVACY) and (wpa_flags == 0) and (rsn_flags == 0): str = str + " WEP" if wpa_flags != 0: str = str + " WPA1" if rsn_flags != 0: str = str + " WPA2" - if (wpa_flags & getattr(NM, "80211ApSecurityFlags").KEY_MGMT_802_1X) or ( - rsn_flags & getattr(NM, "80211ApSecurityFlags").KEY_MGMT_802_1X + if (wpa_flags & NM80211ApSecurityFlags.KEY_MGMT_802_1X) or ( + rsn_flags & NM80211ApSecurityFlags.KEY_MGMT_802_1X ): str = str + " 802.1X" return str.lstrip() +def ap_get_ssid(ap): + if ap is None: + return "not connected" + ssid = ap.get_ssid() + if ssid is None: + return "no ssid" + return '"%s"' % (NM.utils_ssid_to_utf8(ssid.get_data()),) + + +def print_device_info(device): + if device.get_client() is None: + last_scan = "device disappeared" + else: + t = device.get_last_scan() + if t == 0: + last_scan = "no scan completed" + else: + t = (NM.utils_get_timestamp_msec() - t) / 1000.0 + last_scan = "%0.2f sec ago" % (t,) + if device_needs_scan(device): + last_scan += " (stale)" + + ap = device.get_active_access_point() + if ap is None: + active_ap = "none" + else: + active_ap = "%s (%s)" % (ap_get_ssid(ap), ap.get_path()) + + print("Device: %s" % (device.get_iface(),)) + print("D-Bus path: %s" % (NM.Object.get_path(device),)) + print("Driver: %s" % (device.get_driver(),)) + print("Active AP: %s" % (active_ap,)) + print("Last scan: %s" % (last_scan,)) + + def print_ap_info(ap): strength = ap.get_strength() frequency = ap.get_frequency() flags = ap.get_flags() wpa_flags = ap.get_wpa_flags() rsn_flags = ap.get_rsn_flags() - print("SSID: %s" % (ssid_to_utf8(ap))) - print("BSSID: %s" % (ap.get_bssid())) - print("Frequency: %s" % (frequency)) - print("Channel: %s" % (NM.utils_wifi_freq_to_channel(frequency))) - print("Mode: %s" % (mode_to_string(ap.get_mode()))) - print("Flags: %s" % (flags_to_string(flags))) - print("WPA flags: %s" % (security_flags_to_string(wpa_flags))) - print("RSN flags: %s" % (security_flags_to_string(rsn_flags))) - print("Security: %s" % (flags_to_security(flags, wpa_flags, rsn_flags))) - print("Strength: %s %s%%" % (NM.utils_wifi_strength_bars(strength), strength)) - print + + t = ap.get_last_seen() + if t < 0: + last_seen = "never" + else: + t = time.clock_gettime(time.CLOCK_BOOTTIME) - t + last_seen = "%s sec ago" % (math.ceil(t),) + + print(" - D-Bus path: %s" % (ap.get_path(),)) + print(" SSID: %s" % (ap_get_ssid(ap),)) + print(" BSSID: %s" % (ap.get_bssid(),)) + print(" Last seen: %s" % (last_seen,)) + print(" Frequency: %s" % (frequency,)) + print(" Channel: %s" % (NM.utils_wifi_freq_to_channel(frequency),)) + print(" Mode: %s" % (genum_to_str(NM80211Mode, ap.get_mode()),)) + print(" Flags: %s" % (gflags_to_str(NM80211ApFlags, flags),)) + print(" WPA flags: %s" % (gflags_to_str(NM80211ApSecurityFlags, wpa_flags),)) + print(" RSN flags: %s" % (gflags_to_str(NM80211ApSecurityFlags, rsn_flags),)) + print( + " Security: %s" + % (ap_security_flags_to_security(flags, wpa_flags, rsn_flags),) + ) + print( + " Strength: %s%% : %s" + % ( + strength, + NM.utils_wifi_strength_bars(strength), + ) + ) -if __name__ == "__main__": +def device_needs_scan(device): + if device.get_client() is None: + # the device got deleted. We can forget about it. + return False + t = device.get_last_scan() + return t == 0 or t < NM.utils_get_timestamp_msec() - SCAN_THRESHOLD_MSEC + + +def device_ensure_scanned(device): + if os.getenv("NO_SCAN") == "1": + return + + if not device_needs_scan(device): + return + + # kick off a new scan. + device.request_scan_async(None) + + def cb(): + main_loop.quit() + + timeout_source = GLib.timeout_source_new(10 * 1000) + timeout_source.set_callback(cb) + timeout_source.attach(main_loop.get_context()) + + def cb(device, prop): + if not device_needs_scan(device): + main_loop.quit() + + device.connect("notify", cb) + + main_loop.run() + + timeout_source.destroy() + + +def main(): # Python apparently doesn't call setlocale() on its own? We have to call this or else # NM.utils_wifi_strength_bars() will think the locale is ASCII-only, and return the # fallback characters rather than the unicode bars @@ -137,8 +193,21 @@ if __name__ == "__main__": nmc = NM.Client.new(None) devs = nmc.get_devices() - for dev in devs: - if dev.get_device_type() == NM.DeviceType.WIFI: - print_device_info(dev) - for ap in dev.get_access_points(): - print_ap_info(ap) + is_first = True + for device in devs: + if device.get_device_type() != NM.DeviceType.WIFI: + continue + + if not is_first: + print("") + else: + is_first = False + + device_ensure_scanned(device) + print_device_info(device) + for ap in device.get_access_points(): + print_ap_info(ap) + + +if __name__ == "__main__": + main() |