Files
NetworkManager/examples/python/gi/show-wifi-networks.py
Thomas Haller 004ffb91cf 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
2023-02-13 10:32:45 +01:00

214 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2013 Red Hat, Inc.
#
import locale
import math
import os
import re
import time
import gi
gi.require_version("NM", "1.0")
from gi.repository import NM, GLib, Gio
SCAN_THRESHOLD_MSEC = 10000
#
# This example lists Wi-Fi access points NetworkManager scanned on Wi-Fi devices.
# It calls libnm functions using GObject introspection.
#
# Note the second line of the file: coding=utf-8
# It is necessary because we use unicode characters and python would produce
# an error without it: http://www.python.org/dev/peps/pep-0263/
#
NM80211Mode = getattr(NM, "80211Mode")
NM80211ApFlags = getattr(NM, "80211ApFlags")
NM80211ApSecurityFlags = getattr(NM, "80211ApSecurityFlags")
main_loop = GLib.MainLoop()
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 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 ap_security_flags_to_security(flags, wpa_flags, rsn_flags):
str = ""
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 & 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()
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),
)
)
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
locale.setlocale(locale.LC_ALL, "")
nmc = NM.Client.new(None)
devs = nmc.get_devices()
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()