Skip to content

Commit 49f636a

Browse files
Merge pull request #1545 from Bastian-Krause/bst/agent-network-hidden-ssid
util/agents/network_interface: handle wifis without SSID
2 parents 0f7f4ca + 7f8381b commit 49f636a

File tree

2 files changed

+92
-70
lines changed

2 files changed

+92
-70
lines changed

labgrid/util/agents/network_interface.py

Lines changed: 91 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
from time import monotonic, sleep
55

66
import gi
7-
gi.require_version('NM', '1.0')
7+
8+
gi.require_version("NM", "1.0")
89
from gi.repository import GLib, NM
910

1011
# ensure all wrapper objects for Settings types are created
1112
for _name in dir(NM):
12-
if _name.startswith('Setting'):
13+
if _name.startswith("Setting"):
1314
getattr(NM, _name)
1415

16+
1517
class Future:
1618
def __init__(self):
1719
self._event = threading.Event()
@@ -38,6 +40,7 @@ def run(self):
3840
GLib.MainLoop(None).run()
3941
except Exception:
4042
import traceback
43+
4144
traceback.print_exc(file=sys.stderr)
4245
sys.exit(1)
4346

@@ -53,13 +56,11 @@ def cb(data):
5356
done.wait()
5457
return result[0]
5558

59+
5660
def address_from_str(s):
57-
assert '/' in s, "IP address must be in the form address/prefix"
58-
(addr, prefix) = s.split('/', 1)
59-
return NM.IPAddress.new(
60-
socket.AF_INET6 if ':' in addr else socket.AF_INET,
61-
addr,
62-
int(prefix))
61+
assert "/" in s, "IP address must be in the form address/prefix"
62+
(addr, prefix) = s.split("/", 1)
63+
return NM.IPAddress.new(socket.AF_INET6 if ":" in addr else socket.AF_INET, addr, int(prefix))
6364

6465

6566
def connection_from_dict(data):
@@ -71,13 +72,13 @@ def connection_from_dict(data):
7172
if not v:
7273
continue
7374

74-
if k == 'mac-address':
75-
v = ':'.join(f"{x:02X}" for x in v)
76-
elif k == 'ssid':
75+
if k == "mac-address":
76+
v = ":".join(f"{x:02X}" for x in v)
77+
elif k == "ssid":
7778
if isinstance(v, str):
7879
v = v.encode()
7980
v = GLib.Bytes(v)
80-
elif k == 'addresses':
81+
elif k == "addresses":
8182
# setting addresses via the property doesn't seem to work
8283
for x in v:
8384
setting.add_address(address_from_str(x))
@@ -92,13 +93,15 @@ def connection_from_dict(data):
9293
con.add_setting(setting)
9394
return con
9495

96+
9597
class NMDev:
9698
def __init__(self, interface):
9799
self._interface = interface
98-
self._nm_dev = nm.get_device_by_iface(interface) # pylint: disable=possibly-used-before-assignment
100+
self._nm_dev = nm.get_device_by_iface(interface) # pylint: disable=possibly-used-before-assignment
99101

100102
def _delete_connection(self, con):
101103
future = Future()
104+
102105
def cb(con, res, error):
103106
assert error is None
104107
try:
@@ -114,7 +117,7 @@ def cb(con, res, error):
114117
)
115118

116119
def get_settings(self):
117-
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
120+
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
118121
if lg_con:
119122
return dict(lg_con.to_dbus(NM.ConnectionSerializationFlags.ALL))
120123

@@ -125,26 +128,29 @@ def get_active_settings(self):
125128
return dict(con.to_dbus(NM.ConnectionSerializationFlags.ALL))
126129

127130
def configure(self, data):
128-
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
131+
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
129132
if lg_con:
130133
self._delete_connection(lg_con)
131-
data['connection'].update({
132-
'id': f"labgrid-{self._interface}",
133-
'autoconnect': False,
134-
'interface-name': self._interface,
135-
})
134+
data["connection"].update(
135+
{
136+
"id": f"labgrid-{self._interface}",
137+
"autoconnect": False,
138+
"interface-name": self._interface,
139+
}
140+
)
136141
con = connection_from_dict(data)
137142

138143
future = Future()
144+
139145
def cb(dev, res, error):
140146
assert error is None
141147
try:
142-
res = nm.add_and_activate_connection_finish(res) # pylint: disable=possibly-used-before-assignment
148+
res = nm.add_and_activate_connection_finish(res) # pylint: disable=possibly-used-before-assignment
143149
future.set(res)
144150
except Exception as e:
145151
future.set(e)
146152

147-
nm.add_and_activate_connection_async( # pylint: disable=possibly-used-before-assignment
153+
nm.add_and_activate_connection_async( # pylint: disable=possibly-used-before-assignment
148154
con,
149155
self._nm_dev,
150156
None, # specific_object
@@ -172,7 +178,7 @@ def wait_state(self, expected, timeout):
172178
)
173179

174180
def disable(self):
175-
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
181+
lg_con = nm.get_connection_by_id(f"labgrid-{self._interface}") # pylint: disable=possibly-used-before-assignment
176182
if lg_con:
177183
self._delete_connection(lg_con)
178184

@@ -182,58 +188,60 @@ def _flags_to_str(self, flags):
182188
def _accesspoint_to_dict(self, ap):
183189
res = {}
184190

185-
res['flags'] = self._flags_to_str(ap.get_flags())
186-
res['wpa-flags'] = self._flags_to_str(ap.get_wpa_flags())
187-
res['rsn-flags'] = self._flags_to_str(ap.get_rsn_flags())
188-
res['bssid'] = ap.get_bssid()
189-
res['ssid'] = ap.get_ssid().get_data().decode(errors='surrogateescape')
190-
res['frequency'] = ap.get_frequency()
191-
res['mode'] = self._flags_to_str(ap.get_mode())
192-
res['max-bitrate'] = ap.get_max_bitrate()
193-
res['strength'] = ap.get_strength()
191+
res["flags"] = self._flags_to_str(ap.get_flags())
192+
res["wpa-flags"] = self._flags_to_str(ap.get_wpa_flags())
193+
res["rsn-flags"] = self._flags_to_str(ap.get_rsn_flags())
194+
res["bssid"] = ap.get_bssid()
195+
if ap.get_ssid():
196+
res["ssid"] = ap.get_ssid().get_data().decode(errors="surrogateescape")
197+
res["frequency"] = ap.get_frequency()
198+
res["mode"] = self._flags_to_str(ap.get_mode())
199+
res["max-bitrate"] = ap.get_max_bitrate()
200+
res["strength"] = ap.get_strength()
194201

195202
return res
196203

197204
def get_state(self):
198205
state = {}
199206

200207
device = {}
201-
device['capabilities'] = self._flags_to_str(self._nm_dev.get_capabilities())
202-
device['device-type'] = self._flags_to_str(self._nm_dev.get_device_type())
203-
device['state'] = self._flags_to_str(self._nm_dev.get_state())
204-
device['state-reason'] = self._flags_to_str(self._nm_dev.get_state_reason())
205-
device['hw-address'] = self._nm_dev.get_hw_address()
206-
device['driver'] = self._nm_dev.get_driver()
207-
device['udi'] = self._nm_dev.get_udi()
208-
device['mtu'] = self._nm_dev.get_mtu()
209-
device['vendor'] = self._nm_dev.get_vendor()
210-
device['product'] = self._nm_dev.get_product()
211-
state['device'] = device
208+
device["capabilities"] = self._flags_to_str(self._nm_dev.get_capabilities())
209+
device["device-type"] = self._flags_to_str(self._nm_dev.get_device_type())
210+
device["state"] = self._flags_to_str(self._nm_dev.get_state())
211+
device["state-reason"] = self._flags_to_str(self._nm_dev.get_state_reason())
212+
device["hw-address"] = self._nm_dev.get_hw_address()
213+
device["driver"] = self._nm_dev.get_driver()
214+
device["udi"] = self._nm_dev.get_udi()
215+
device["mtu"] = self._nm_dev.get_mtu()
216+
device["vendor"] = self._nm_dev.get_vendor()
217+
device["product"] = self._nm_dev.get_product()
218+
state["device"] = device
212219

213220
for name, ip_cfg in (
214-
('ip4-config', self._nm_dev.get_ip4_config()),
215-
('ip6-config', self._nm_dev.get_ip6_config()),
216-
):
221+
("ip4-config", self._nm_dev.get_ip4_config()),
222+
("ip6-config", self._nm_dev.get_ip6_config()),
223+
):
217224
if ip_cfg is None:
218225
continue
219226
cfg = {}
220-
cfg['addresses'] = []
227+
cfg["addresses"] = []
221228
for address in ip_cfg.get_addresses():
222-
cfg['addresses'].append(f"{address.get_address()}/{address.get_prefix()}")
223-
cfg['gateway'] = ip_cfg.get_gateway()
229+
cfg["addresses"].append(f"{address.get_address()}/{address.get_prefix()}")
230+
cfg["gateway"] = ip_cfg.get_gateway()
224231
state[name] = cfg
225232

226233
try:
227234
ap = self._nm_dev.get_active_access_point()
228235
except AttributeError:
229236
ap = None
230237
if ap:
231-
state['active-access-point'] = self._accesspoint_to_dict(ap)
238+
state["active-access-point"] = self._accesspoint_to_dict(ap)
232239

233240
return state
234241

235242
def request_scan(self):
236243
future = Future()
244+
237245
def cb(dev, res, error):
238246
assert error is None
239247
try:
@@ -251,7 +259,7 @@ def cb(dev, res, error):
251259
future.wait() # we must wait, but don't need to return it here
252260

253261
def get_access_points(self, scan):
254-
if scan is None: # automatically scan if needed
262+
if scan is None: # automatically scan if needed
255263
age = NM.utils_get_timestamp_msec() - self._nm_dev.get_last_scan()
256264
scan = bool(age > 30_000)
257265

@@ -275,80 +283,93 @@ def get_dhcpd_leases(self):
275283
with open(f"/var/lib/NetworkManager/dnsmasq-{self._interface}.leases") as f:
276284
for line in f:
277285
line = line.strip().split()
278-
if line[3] == '*':
286+
if line[3] == "*":
279287
line[3] = None
280-
if line[4] == '*':
288+
if line[4] == "*":
281289
line[4] = None
282-
leases.append({
283-
'expire': int(line[0]),
284-
'mac': line[1],
285-
'ip': line[2],
286-
'hostname': line[3],
287-
'id': line[4],
288-
})
290+
leases.append(
291+
{
292+
"expire": int(line[0]),
293+
"mac": line[1],
294+
"ip": line[2],
295+
"hostname": line[3],
296+
"id": line[4],
297+
}
298+
)
289299
return leases
290300

291-
if getattr(NM.Client, '__gtype__', None):
301+
302+
if getattr(NM.Client, "__gtype__", None):
292303
# hide this from sphinx autodoc
293304
bl = BackgroundLoop()
294305
bl.start()
295306
nm = bl.block_on(NM.Client.new, None)
296307

297308
_nmdevs = {}
298309

310+
299311
def _get_nmdev(interface):
300312
if interface not in _nmdevs:
301313
_nmdevs[interface] = NMDev(interface)
302314
return _nmdevs[interface]
303315

316+
304317
def handle_configure(interface, settings):
305318
nmdev = _get_nmdev(interface)
306319
return nmdev.configure(settings)
307320

321+
308322
def handle_wait_state(interface, expected, timeout=60):
309323
nmdev = _get_nmdev(interface)
310324
return nmdev.wait_state(expected, timeout)
311325

326+
312327
def handle_disable(interface):
313328
nmdev = _get_nmdev(interface)
314329
return nmdev.disable()
315330

331+
316332
def handle_get_active_settings(interface):
317333
nmdev = _get_nmdev(interface)
318334
return nmdev.get_active_settings()
319335

336+
320337
def handle_get_settings(interface):
321338
nmdev = _get_nmdev(interface)
322339
return nmdev.get_settings()
323340

341+
324342
def handle_get_state(interface):
325343
nmdev = _get_nmdev(interface)
326344
return nmdev.get_state()
327345

346+
328347
def handle_get_dhcpd_leases(interface):
329348
nmdev = _get_nmdev(interface)
330349
return nmdev.get_dhcpd_leases()
331350

351+
332352
def handle_request_scan(interface):
333353
nmdev = _get_nmdev(interface)
334354
return nmdev.request_scan()
335355

356+
336357
def handle_get_access_points(interface, scan=None):
337358
nmdev = _get_nmdev(interface)
338359
return nmdev.get_access_points(scan)
339360

340361

341362
methods = {
342363
# basic
343-
'configure': handle_configure,
344-
'wait_state': handle_wait_state,
345-
'disable': handle_disable,
346-
'get_active_settings': handle_get_active_settings,
347-
'get_settings': handle_get_settings,
348-
'get_state': handle_get_state,
364+
"configure": handle_configure,
365+
"wait_state": handle_wait_state,
366+
"disable": handle_disable,
367+
"get_active_settings": handle_get_active_settings,
368+
"get_settings": handle_get_settings,
369+
"get_state": handle_get_state,
349370
# dhcpd
350-
'get_dhcpd_leases': handle_get_dhcpd_leases,
371+
"get_dhcpd_leases": handle_get_dhcpd_leases,
351372
# wireless
352-
'request_scan': handle_request_scan,
353-
'get_access_points': handle_get_access_points,
373+
"request_scan": handle_request_scan,
374+
"get_access_points": handle_get_access_points,
354375
}

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ include = [
224224
"labgrid/remote/**/*.py",
225225
"labgrid/resource/httpvideostream.py",
226226
"labgrid/resource/provider.py",
227+
"labgrid/util/agents/network_interface.py",
227228
"labgrid/util/agents/usb_hid_relay.py",
228229
"labgrid/util/exceptions.py",
229230
]

0 commit comments

Comments
 (0)