Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
178 commits
Select commit Hold shift + click to select a range
f376337
bye bye NetworkManager
adeebshihadeh Mar 12, 2026
83b33b7
wifi: fix bugs found during on-device testing, add CLI helper
adeebshihadeh Mar 12, 2026
2ec7273
wifi: add reproducible benchmark script
adeebshihadeh Mar 12, 2026
516a425
wifi: fix security and parsing bugs found during red team testing
adeebshihadeh Mar 12, 2026
8e03893
wifi: remove temporary benchmark and CLI debug tools
adeebshihadeh Mar 12, 2026
1ada6be
wifi: fix UI state gaps on panel open and after connect
adeebshihadeh Mar 12, 2026
eb398f3
wifi: populate networks before state to avoid disconnected icon flash
adeebshihadeh Mar 12, 2026
2982680
wifi: populate network list from cache on panel open
adeebshihadeh Mar 12, 2026
fee6315
wifi: always process scan results, decouple from UI active state
adeebshihadeh Mar 13, 2026
b2eedec
wifi: fix bugs and reduce duplication from code review
adeebshihadeh Mar 13, 2026
11abd51
wifi: fix remaining code review issues (round 2)
adeebshihadeh Mar 13, 2026
d6feae7
hardware: break circular import with wifi_manager
adeebshihadeh Mar 13, 2026
c4caa13
wifi: code review cleanup (simplify round 3)
adeebshihadeh Mar 13, 2026
b447882
simplify
adeebshihadeh Mar 13, 2026
8155b84
rm that
adeebshihadeh Mar 13, 2026
81053af
move conf to tmp
adeebshihadeh Mar 13, 2026
7057ebe
move that to ui
adeebshihadeh Mar 13, 2026
ef203d5
wifi: detach manager from UI lifecycle
andiradulescu Apr 1, 2026
df775af
wifi: recover stale bad-password connects
andiradulescu Apr 1, 2026
3e2550b
wifi: persist nmconnection files via sudo
andiradulescu Apr 1, 2026
ebc83c1
wifi: persist credentials after auth succeeds
andiradulescu Apr 1, 2026
9d0f868
tools: restore wifi test checkpoint runner
andiradulescu Apr 2, 2026
1499b54
wifi: use nmcli dev set instead of writing to readonly conf.d
andiradulescu Apr 6, 2026
32381f4
wifi: bump wpa_ctrl recv buffer to 32768 to avoid truncating scan res…
andiradulescu Apr 6, 2026
550ba88
wifi: remove dead code (normalize_ssid, _active field)
andiradulescu Apr 6, 2026
4776ac5
wifi: fix NetworkStore.remove exception type and add tests
andiradulescu Apr 6, 2026
7389596
wifi: clean up tethering state on stop()
andiradulescu Apr 6, 2026
1880c2d
wifi: deduplicate CONNECTED transition into _handle_connected()
andiradulescu Apr 6, 2026
01d40ac
wifi: guard daemon cleanup against double invocation
andiradulescu Apr 6, 2026
5930d02
wifi: add lock to WifiManagerClient callback queue for thread safety
andiradulescu Apr 6, 2026
f45ee40
wifi: keep udhcpc running for DHCP lease renewal
andiradulescu Apr 6, 2026
92975cb
wifi: expand service client tests (snapshot, events, event broker)
andiradulescu Apr 6, 2026
2cf02f1
wifi: restore normalize_ssid, used by UI widgets
andiradulescu Apr 6, 2026
9aabc2d
wifi: unmanage wlan0 before connecting to wpa_supplicant, add log
andiradulescu Apr 6, 2026
06d43de
wifi: run nmcli unmanage after wlan0 is up, not before
andiradulescu Apr 6, 2026
d1881ef
wifi: kill NM wpa_supplicant and start our own on first boot
andiradulescu Apr 6, 2026
70fec72
wifi: run nmcli unmanage after wlan0 is up, not before
andiradulescu Apr 6, 2026
8866d86
wifi: wait for wlan0, unmanage, start our wpa_supplicant (no killall)
andiradulescu Apr 6, 2026
da60d58
wifi: always REASSOCIATE after forget so wpa_supplicant fails over
andiradulescu Apr 6, 2026
eaf5db5
wifi: use /tmp for dnsmasq lease file since /var/lib/misc doesn't exist
andiradulescu Apr 7, 2026
15d073c
wifi: re-enable tethering toggle on activated/disconnected events
andiradulescu Apr 7, 2026
1418c6e
wifi: ignore network connect taps while tethering is active
andiradulescu Apr 7, 2026
2b51a5a
wifi: ENABLE_NETWORK all on startup to clear TEMP-DISABLED state
andiradulescu Apr 7, 2026
3f6cabf
wifi: clean up stale AP mode and dnsmasq on daemon startup
andiradulescu Apr 7, 2026
9b82a4f
wifi: set tethering_active immediately to prevent toggle bounce
andiradulescu Apr 7, 2026
020db8c
wifi: keep tethering toggle disabled during transition, set client st…
andiradulescu Apr 7, 2026
a43a138
wifi: prevent poll snapshot from overriding client tethering state
andiradulescu Apr 7, 2026
0415e14
wifi: block network taps in legacy UI while tethering is active
andiradulescu Apr 7, 2026
76107ac
wifi: reconcile disconnected state when wpa_supplicant is already con…
andiradulescu Apr 7, 2026
0484157
wifi: fire activated callback from snapshot and reset seq on daemon r…
andiradulescu Apr 7, 2026
f5d6c58
wifi: force monitor reconnect when wpa_supplicant is restarted
andiradulescu Apr 7, 2026
a18ebf6
wifi: extract _WpaCtrlBase to fix socket leak, counter race, and assert
andiradulescu Apr 12, 2026
18c5cb6
wifi: add _callback_lock to WifiManager backend
andiradulescu Apr 12, 2026
c8d5f6c
wifi: guard against CONNECTED with no SSID and DISCONNECTED race
andiradulescu Apr 12, 2026
c44a2c8
wifi: add tethering rollback on failure and reap zombie udhcpc
andiradulescu Apr 12, 2026
8bf54f4
wifi: deduplicate activated/disconnected callbacks in client
andiradulescu Apr 12, 2026
06600cc
wifi: rollback optimistic client state on RPC failure
andiradulescu Apr 12, 2026
49a80d9
wifi: remove dead code across wifi manager stack
andiradulescu Apr 12, 2026
881d88c
wifi: deduplicate network sort and cap wpa_supplicant retry loop
andiradulescu Apr 12, 2026
941e81e
wifi: expire tethering pending flag after 10s to prevent stuck state
andiradulescu Apr 12, 2026
e7ecfaa
wifi: escape quotes and backslashes in credentials instead of stripping
andiradulescu Apr 12, 2026
f54e1da
wifi: classify WEP networks as unsupported instead of open
andiradulescu Apr 12, 2026
87a67b4
wifi: fix lint — replace banned unittest.mock with pytest_mock, fix r…
andiradulescu Apr 12, 2026
0aa2243
wifi: mark wifi_test_checkpoints.py executable to match shebang
andiradulescu Apr 12, 2026
f3066a3
wifi: use sudo_read for nmconnection files in hardware metered check
andiradulescu Apr 12, 2026
1e46995
wifi: check for existing daemon before unlinking socket on startup
andiradulescu Apr 12, 2026
84f8bdd
wifi: probe socket before unlinking in _ensure_daemon to prevent clob…
andiradulescu Apr 12, 2026
544e152
wifi: use active upstream interface for tethering NAT instead of hard…
andiradulescu Apr 12, 2026
0972f43
wifi: only clear pending connection after SSID and epoch match
andiradulescu Apr 12, 2026
88ac126
wifi: write tethering AP config with 0600 permissions to protect PSK
andiradulescu Apr 12, 2026
c056cb1
wifi: re-enable tethering controls after password change when not tet…
andiradulescu Apr 12, 2026
78a358f
wifi: skip stale need_auth events when snapshot shows already connected
andiradulescu Apr 12, 2026
5dd8f27
wifi: register wifi_manager as managed service in process_config
andiradulescu Apr 12, 2026
fa5b855
wifi: flush stale MASQUERADE rules on tethering start
andiradulescu Apr 12, 2026
e569d26
wifi: remove vestigial socket probe in daemon startup
andiradulescu Apr 12, 2026
a6e0388
wifi: drop _tethering_pending flag by flipping backend state immediately
andiradulescu Apr 12, 2026
1906a23
wifi: inline _find_network_id into its sole caller
andiradulescu Apr 12, 2026
33f4180
wifi: consolidate test fixtures into conftest.py
andiradulescu Apr 12, 2026
fceb2c6
wifi: gracefully degrade when daemon is unreachable on construction
andiradulescu Apr 12, 2026
ffa0e43
wifi: rate-limit client poll failure logs to transitions
andiradulescu Apr 12, 2026
909f474
wifi: swallow client RPC errors when daemon unreachable
andiradulescu Apr 12, 2026
febe1e9
wifi: import WifiManager directly, drop WifiManagerClient alias
andiradulescu Apr 13, 2026
0cb4cb2
wifi: unregister wifi_manager managed service
andiradulescu Apr 13, 2026
82ef542
wifi: delete vestigial RPC daemon and client-snapshot tests
andiradulescu Apr 13, 2026
b23399c
wifi: skip monitor reconnect loop when wpa_supplicant is absent
andiradulescu Apr 13, 2026
2a6de0a
wifi: log initialization worker exceptions instead of dying silently
andiradulescu Apr 13, 2026
a28adad
wifi: drop stale managed-service comments
andiradulescu Apr 13, 2026
6e485f4
wifi: attach-first bringup, never kill a daemon we didn't spawn
andiradulescu Apr 13, 2026
5b9208b
wifi: refresh ctrl socket when monitor reconnects after wpa_supplican…
andiradulescu Apr 13, 2026
c15850f
wifi: add tests pinning attach-first bringup contract
andiradulescu Apr 13, 2026
41ddb54
wifi: prevent bringup test fixture leak into __del__ on GC
andiradulescu Apr 13, 2026
7c3bbb9
wifi: drop empty show_event/hide_event stubs in network widget
andiradulescu Apr 13, 2026
4d5d5c0
wifi: drop RECONFIGURE from attach path
andiradulescu Apr 13, 2026
1d3a700
wifi: narrow wpa_supplicant pkill to our config paths
andiradulescu Apr 13, 2026
bc49df7
wifi: start DHCP when init adopts an already-connected daemon
andiradulescu Apr 13, 2026
ba3097d
wifi: gate tethering CONNECTED state on ctrl socket bringup
andiradulescu Apr 13, 2026
31ec6c4
wifi: update bringup tests for dropped RECONFIGURE and escaped pkill
andiradulescu Apr 13, 2026
d275265
utils: drop shell=True from sudo_read to block command injection
andiradulescu Apr 13, 2026
eb92ffd
wifi: keep _tethering_active set across password-triggered restart
andiradulescu Apr 13, 2026
8880cf0
wifi: use lossless SSID-to-filename encoding, remember legacy paths
andiradulescu Apr 13, 2026
7ba23ee
hw: look up metered .nmconnection by SSID field, not derived filename
andiradulescu Apr 13, 2026
edf4233
wifi: allow _reconcile_connecting_state to run with ssid=None
andiradulescu Apr 13, 2026
1d5412c
wifi: roll back tethering on password-restart bringup failure
andiradulescu Apr 13, 2026
85178c4
wifi: self-heal monitor thread by retrying ctrl attach on each iteration
andiradulescu Apr 13, 2026
146b3c8
wifi: serialize WpaCtrl.request to pair replies with commands
andiradulescu Apr 13, 2026
ea0daec
wifi: parse SSID from WRONG_KEY event to ignore stale auth failures
andiradulescu Apr 13, 2026
27d867c
wifi: verify AP mode after tethering bringup to reject stale STA daemon
andiradulescu Apr 13, 2026
83c6c91
wifi: coalesce networks_updated callbacks to bound queue growth
andiradulescu Apr 13, 2026
d2e1ebd
wifi: defer reconcile failure on SCANNING so slow hidden joins survive
andiradulescu Apr 13, 2026
7d22c15
wifi: skip password button debounce when tethering is off
andiradulescu Apr 13, 2026
392f03f
wifi: refresh stale NM reference in network item comment
andiradulescu Apr 13, 2026
32ed2a1
wifi: serialize WpaCtrl.close against in-flight request callers
andiradulescu Apr 13, 2026
ccb4167
wifi: make _handle_connected idempotent to coalesce reconcile+event r…
andiradulescu Apr 13, 2026
e7071fc
wifi: check wpa_supplicant responses and clean up orphan network ids …
andiradulescu Apr 13, 2026
e1c4353
wifi: re-enable all saved networks after connect so auto-roam works
andiradulescu Apr 13, 2026
e135352
wifi: decode wpa_supplicant printf_encode'd SSIDs in scan results so …
andiradulescu Apr 14, 2026
2f548f3
wifi: decode printf_encode'd SSIDs in STATUS and CTRL-EVENT-SSID-TEMP…
andiradulescu Apr 14, 2026
431bdc2
wifi: pass 64-hex raw PSKs unquoted so wpa_supplicant accepts pre-has…
andiradulescu Apr 14, 2026
8be0446
wifi: reuse _ensure_wpa_supplicant for tethering rollback so we don't…
andiradulescu Apr 14, 2026
dca54e5
wifi: note the long-term same-daemon tethering refactor needed to run…
andiradulescu Apr 14, 2026
f17bc42
wifi: decode escaped SSID bytes as UTF-8 instead of one-codepoint-per…
andiradulescu Apr 14, 2026
82b4662
wifi: adopt running hotspot in _init_wifi_state instead of routing it…
andiradulescu Apr 14, 2026
a42b8af
wifi: unmanage wlan0 up-front in _ensure_wpa_supplicant so the attach…
andiradulescu Apr 14, 2026
e71c299
wifi: wait for wlan0 before nmcli unmanage so NM actually releases it…
andiradulescu Apr 15, 2026
1ad06c6
wifi: never attach to NM's wpa_supplicant, fast-path via pgrep on our…
andiradulescu Apr 15, 2026
da7cfbf
wifi: factor pgrep/pkill wpa_supplicant regex into module-level helpers
andiradulescu Apr 15, 2026
85dfd9b
wifi: bump wlan0 default route to metric 600 after udhcpc bind so eth…
andiradulescu Apr 15, 2026
c0c5bd6
wifi: reconcile stale CONNECTED and keep pending creds on persist fai…
andiradulescu Apr 15, 2026
74ce403
wifi_test_checkpoints: read daemon state via wpa_cli instead of spawn…
andiradulescu Apr 15, 2026
26e1585
wpa_ctrl: split semicolon-joined statements to satisfy ruff E702
andiradulescu Apr 15, 2026
aadb4ff
wifi: refuse foreign daemon after NM teardown timeout and restore ups…
andiradulescu Apr 15, 2026
95657ee
wifi: keep tethering_active True until _stop_tethering actually switc…
andiradulescu Apr 15, 2026
fbdae57
lint: whitelist 'iff' and 'caf' in codespell (math shorthand and UTF-…
andiradulescu Apr 15, 2026
6152a2f
Merge remote-tracking branch 'origin/master' into nonetworkmanager
andiradulescu Apr 15, 2026
ebee922
wifi: decode LIST_NETWORKS SSIDs and accept WRONG_KEY when connecting…
andiradulescu Apr 15, 2026
0798826
wifi: source-subnet MASQUERADE so tethering survives uplink changes (…
andiradulescu Apr 15, 2026
d4ba89a
system/ui/lib: add CLAUDE.md with wifi_manager gotchas and invariants
andiradulescu Apr 15, 2026
17da4fb
wifi: adopt running hotspot daemon before STA cleanup on UI restart
andiradulescu Apr 15, 2026
41578bf
wifi: treat SCANNING and AUTHENTICATING as CONNECTING on init
andiradulescu Apr 15, 2026
09132c7
wifi: adopt roamed SSID in stale CONNECTED recheck instead of synthes…
andiradulescu Apr 15, 2026
8f4b211
wifi: debounce WRONG_KEY events so a fast retry doesn't lose fresh cr…
andiradulescu Apr 15, 2026
1a1c950
wifi: block station connect_to_network / activate_connection while te…
andiradulescu Apr 15, 2026
315e7bd
wifi: extract _GsmManager into its own module
andiradulescu Apr 16, 2026
059d522
wifi: extract NetworkStore into its own module
andiradulescu Apr 16, 2026
173c278
wifi: extract DhcpClient into its own module
andiradulescu Apr 16, 2026
9d3527f
wifi: move wpa_supplicant text-interface helpers into wpa_ctrl
andiradulescu Apr 16, 2026
dd25d74
wifi: rearrange imports as master
andiradulescu Apr 16, 2026
fc73053
wifi: compress verbose comments, drop section dividers
andiradulescu Apr 16, 2026
5f7b06a
wifi: extract wpa_supplicant bringup into wpa_ctrl module
andiradulescu Apr 16, 2026
3104157
wifi: restore set_current_network_metered position from master
andiradulescu Apr 16, 2026
7877db1
wifi: compress multi-line comments in bringup and init paths
andiradulescu Apr 16, 2026
46a39ef
wifi: re-enable saved networks after WRONG_KEY so auto-fallback works
andiradulescu Apr 16, 2026
76217aa
wifi: key WRONG_KEY debounce by SSID so unrelated auth failures aren'…
andiradulescu Apr 16, 2026
2ba742c
wifi: fail tethering bringup when dnsmasq exits so clients don't see …
andiradulescu Apr 16, 2026
a3ab0fb
Merge branch 'master' into nonetworkmanager
andiradulescu Apr 16, 2026
49a0634
wifi: match NetworkManager's dBm-to-quality formula so bucket thresho…
andiradulescu Apr 16, 2026
72c9c06
wifi: gate monitor attach retries on pgrep so we don't latch onto NM'…
andiradulescu Apr 24, 2026
c34121f
wifi: bail out of bringup wait loop on stop() so early-boot teardown …
andiradulescu Apr 24, 2026
d99b487
wifi_test_checkpoints: classify ASSOCIATED as CONNECTING so pre-hands…
andiradulescu Apr 24, 2026
6fe037f
wifi: honor stop() before unmanage/pkill when wlan0 is already present
andiradulescu Apr 24, 2026
f2a6309
wifi: re-enable saved networks on stale-connect DISCONNECTED/INACTIVE…
andiradulescu Apr 24, 2026
2b2bec6
wifi: skip station recovery when STATUS reports AP mode so hotspot is…
andiradulescu Apr 24, 2026
be21ed1
wifi: respawn wpa_supplicant from monitor when no owned daemon is run…
andiradulescu Apr 24, 2026
74f03ad
wifi: skip .nmconnection profiles with malformed values so one bad fi…
andiradulescu Apr 24, 2026
049d50c
wifi: tear down DHCP/IP state on WRONG_KEY since DISCONNECTED is igno…
andiradulescu Apr 24, 2026
0829b0d
Merge branch 'master' into nonetworkmanager
andiradulescu Apr 24, 2026
6066e25
wifi: drop ctrl handle on monitor error so daemon-crash recovery actu…
andiradulescu Apr 24, 2026
078c958
wifi: route all ctrl requests through _request so SIGKILL on wpa_supp…
andiradulescu Apr 24, 2026
09657a1
wifi: reset CONNECTING state when connect is requested while _ctrl is…
andiradulescu Apr 24, 2026
8f2b915
tici: skip malformed metered= per-profile so one bad nmconnection doe…
andiradulescu Apr 24, 2026
a0c8172
gsm_manager: preserve comments/breadcrumbs from extracted code and mo…
andiradulescu Apr 25, 2026
7b75c97
gsm_manager: inline NM constants since networkmanager.py is gone on t…
andiradulescu Apr 25, 2026
1620048
wifi: gate fast-path daemon attach on should_exit so teardown can't b…
andiradulescu Apr 25, 2026
9cda265
dhcp_client: keep polling on ip query failure instead of aborting the…
andiradulescu Apr 25, 2026
6da5632
test_wifi_manager_bringup: update fast-attach fixtures for the should…
andiradulescu Apr 25, 2026
ed9ad0d
wifi: persist tethering password before mutating runtime state so a f…
andiradulescu Apr 25, 2026
cb6206b
wpa_ctrl: drop "iff" math idiom from docstring; reads fine as "if"
andiradulescu Apr 25, 2026
0fac556
pyproject: drop iff from codespell ignore list, no longer used in tree
andiradulescu Apr 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def sudo_write(val: str, path: str) -> None:

def sudo_read(path: str) -> str:
try:
return subprocess.check_output(f"sudo cat {path}", shell=True, encoding='utf8').strip()
return subprocess.check_output(["sudo", "cat", path], encoding='utf8').strip()
except Exception:
return ""

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ testpaths = [
[tool.codespell]
quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite,ser"
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite,ser,caf"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.po, uv.lock, *.onnx, *.pem, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*, selfdrive/assets/offroad/mici_fcc.html"

Expand Down
1 change: 0 additions & 1 deletion selfdrive/ui/layouts/settings/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def __init__(self):

# Panel configuration
wifi_manager = WifiManager()
wifi_manager.set_active(False)

self._panels = {
PanelType.DEVICE: PanelInfo(tr_noop("Device"), DeviceLayout()),
Expand Down
3 changes: 2 additions & 1 deletion selfdrive/ui/mici/layouts/settings/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from openpilot.selfdrive.ui.mici.layouts.settings.network.wifi_ui import WifiIcon
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.wifi_manager import WifiManager, ConnectStatus, SecurityType, normalize_ssid
from openpilot.system.ui.lib.wifi_manager import WifiManager, ConnectStatus, SecurityType
from openpilot.system.ui.lib.wpa_ctrl import normalize_ssid


class WifiNetworkButton(BigButton):
Expand Down
23 changes: 14 additions & 9 deletions selfdrive/ui/mici/layouts/settings/network/network_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ def __init__(self):
super().__init__()

self._wifi_manager = WifiManager()
self._wifi_manager.set_active(False)
self._wifi_ui = WifiUIMici(self._wifi_manager)

self._wifi_manager.add_callbacks(
networks_updated=self._on_network_updated,
activated=lambda: self._on_tethering_finished(),
disconnected=lambda: self._on_tethering_finished(),
)

# ******** Tethering ********
Expand All @@ -32,9 +33,13 @@ def tethering_toggle_callback(checked: bool):

def tethering_password_callback(password: str):
if password:
self._tethering_toggle_btn.set_enabled(False)
self._tethering_password_btn.set_enabled(False)
self._wifi_manager.set_tethering_password(password)
if self._wifi_manager.is_tethering_active():
self._tethering_toggle_btn.set_enabled(False)
self._tethering_password_btn.set_enabled(False)
else:
self._tethering_toggle_btn.set_enabled(True)
self._tethering_password_btn.set_enabled(True)

def tethering_password_clicked():
tethering_password = self._wifi_manager.tethering_password
Expand Down Expand Up @@ -105,14 +110,12 @@ def _update_state(self):

def show_event(self):
super().show_event()
self._wifi_manager.set_active(True)

# Process wifi callbacks while at any point in the nav stack
gui_app.add_nav_stack_tick(self._wifi_manager.process_callbacks)

def hide_event(self):
super().hide_event()
self._wifi_manager.set_active(False)

gui_app.remove_nav_stack_tick(self._wifi_manager.process_callbacks)

Expand All @@ -136,14 +139,16 @@ def update_apn(apn: str):
def _toggle_cellular_metered(self, checked: bool):
self._wifi_manager.update_gsm_settings(ui_state.params.get_bool("GsmRoaming"), ui_state.params.get("GsmApn") or "", checked)

def _on_network_updated(self, networks: list[Network]):
# Update tethering state
def _on_tethering_finished(self):
tethering_active = self._wifi_manager.is_tethering_active()
# TODO: use real signals (like activated/settings changed, etc.) to speed up re-enabling buttons
self._tethering_toggle_btn.set_enabled(True)
self._tethering_password_btn.set_enabled(True)
self._network_metered_btn.set_enabled(lambda: not tethering_active and bool(self._wifi_manager.ipv4_address))
self._tethering_toggle_btn.set_checked(tethering_active)
self._on_network_updated(self._wifi_manager.networks)

def _on_network_updated(self, networks: list[Network]):
tethering_active = self._wifi_manager.is_tethering_active()
self._network_metered_btn.set_enabled(lambda: not tethering_active and bool(self._wifi_manager.ipv4_address))

# Update network metered
self._network_metered_btn.set_value(
Expand Down
14 changes: 10 additions & 4 deletions selfdrive/ui/mici/layouts/settings/network/wifi_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from openpilot.system.ui.lib.application import gui_app, MousePos, FontWeight
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.system.ui.lib.wifi_manager import WifiManager, Network, SecurityType, normalize_ssid
from openpilot.system.ui.lib.wifi_manager import WifiManager, Network, SecurityType
from openpilot.system.ui.lib.wpa_ctrl import normalize_ssid


class LoadingAnimation(Widget):
Expand Down Expand Up @@ -220,7 +221,7 @@ def _update_state(self):
elif self._is_connected:
self.set_value("tethering" if self._network.is_tethering else "connected")
elif self._network_missing:
# after connecting/connected since NM will still attempt to connect/stay connected for a while
# after connecting/connected since wpa_supplicant will still attempt to connect/stay connected for a while
self.set_value("not in range")
else:
self.set_value("unsupported")
Expand Down Expand Up @@ -297,7 +298,6 @@ def any_network_forgetting(self) -> bool:
def show_event(self):
# Re-sort scroller items and update from latest scan results
super().show_event()
self._wifi_manager.set_active(True)
self._networks = {n.ssid: n for n in self._wifi_manager.networks}
self._update_buttons(re_sort=True)

Expand Down Expand Up @@ -339,6 +339,9 @@ def _connect_with_password(self, ssid: str, password: str):
self._move_network_to_front(ssid, scroll=True)

def _connect_to_network(self, ssid: str):
if self._wifi_manager.is_tethering_active():
return

network = self._networks.get(ssid)
if network is None:
cloudlog.warning(f"Trying to connect to unknown network: {ssid}")
Expand All @@ -356,11 +359,14 @@ def _connect_to_network(self, ssid: str):

def _on_need_auth(self, ssid, incorrect_password=True):
if incorrect_password:
found = False
for btn in self._scroller.items:
if isinstance(btn, WifiButton) and btn.network.ssid == ssid:
btn.set_wrong_password()
found = True
break
return
if found:
return

dlg = BigInputDialog("enter password...", "", minimum_length=8,
confirm_callback=lambda _password: self._connect_with_password(ssid, _password))
Expand Down
116 changes: 70 additions & 46 deletions system/hardware/tici/hardware.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import configparser
import math
import os
import subprocess
Expand All @@ -15,13 +16,14 @@
from openpilot.system.hardware.tici.lpa import TiciLPA
from openpilot.system.hardware.tici.pins import GPIO
from openpilot.system.hardware.tici.amplifier import Amplifier
from openpilot.system.ui.lib.wpa_ctrl import parse_status, dbm_to_percent

NM_CONNECTIONS_DIR = "/data/etc/NetworkManager/system-connections"

NM = 'org.freedesktop.NetworkManager'
NM_CON_ACT = NM + '.Connection.Active'
NM_DEV = NM + '.Device'
NM_DEV_WL = NM + '.Device.Wireless'
NM_DEV_STATS = NM + '.Device.Statistics'
NM_AP = NM + '.AccessPoint'
DBUS_PROPS = 'org.freedesktop.DBus.Properties'

MM = 'org.freedesktop.ModemManager1'
Expand Down Expand Up @@ -138,28 +140,26 @@ def set_ir_power(self, percent: int):

def get_network_type(self):
try:
primary_connection = self.nm.Get(NM, 'PrimaryConnection', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
primary_connection = self.bus.get_object(NM, primary_connection)
primary_type = primary_connection.Get(NM_CON_ACT, 'Type', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)

if primary_type == '802-3-ethernet':
return NetworkType.ethernet
elif primary_type == '802-11-wireless':
return NetworkType.wifi
else:
active_connections = self.nm.Get(NM, 'ActiveConnections', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
for conn in active_connections:
c = self.bus.get_object(NM, conn)
tp = c.Get(NM_CON_ACT, 'Type', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if tp == 'gsm':
modem = self.get_modem()
access_t = modem.Get(MM_MODEM, 'AccessTechnologies', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if access_t >= MM_MODEM_ACCESS_TECHNOLOGY_LTE:
return NetworkType.cell4G
elif access_t >= MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
return NetworkType.cell3G
else:
return NetworkType.cell2G
result = subprocess.run(["ip", "route", "show", "default"], capture_output=True, text=True, timeout=2)
for line in result.stdout.strip().split("\n"):
if "dev" not in line:
continue
parts = line.split()
dev_idx = parts.index("dev")
dev = parts[dev_idx + 1]
if dev == "wlan0":
return NetworkType.wifi
elif dev in ("eth0", "usb0"):
return NetworkType.ethernet
elif dev in ("wwan0", "rmnet_data0"):
modem = self.get_modem()
access_t = modem.Get(MM_MODEM, 'AccessTechnologies', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if access_t >= MM_MODEM_ACCESS_TECHNOLOGY_LTE:
return NetworkType.cell4G
elif access_t >= MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
return NetworkType.cell3G
else:
return NetworkType.cell2G
except Exception:
pass

Expand All @@ -170,10 +170,6 @@ def get_modem(self):
modem_path = list(objects.keys())[0]
return self.bus.get_object(MM, modem_path)

def get_wlan(self):
wlan_path = self.nm.GetDeviceByIpIface('wlan0', dbus_interface=NM, timeout=TIMEOUT)
return self.bus.get_object(NM, wlan_path)

def get_wwan(self):
wwan_path = self.nm.GetDeviceByIpIface('wwan0', dbus_interface=NM, timeout=TIMEOUT)
return self.bus.get_object(NM, wwan_path)
Expand Down Expand Up @@ -258,12 +254,11 @@ def get_network_strength(self, network_type):
if network_type == NetworkType.none:
pass
elif network_type == NetworkType.wifi:
wlan = self.get_wlan()
active_ap_path = wlan.Get(NM_DEV_WL, 'ActiveAccessPoint', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if active_ap_path != "/":
active_ap = self.bus.get_object(NM, active_ap_path)
strength = int(active_ap.Get(NM_AP, 'Strength', dbus_interface=DBUS_PROPS, timeout=TIMEOUT))
network_strength = self.parse_strength(strength)
result = subprocess.run(["wpa_cli", "-i", "wlan0", "signal_poll"],
capture_output=True, text=True, timeout=2)
status = parse_status(result.stdout)
if "RSSI" in status:
network_strength = self.parse_strength(dbm_to_percent(int(status["RSSI"])))
else: # Cellular
modem = self.get_modem()
strength = int(modem.Get(MM_MODEM, 'SignalQuality', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)[0])
Expand All @@ -275,18 +270,47 @@ def get_network_strength(self, network_type):

def get_network_metered(self, network_type) -> bool:
try:
primary_connection = self.nm.Get(NM, 'PrimaryConnection', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
primary_connection = self.bus.get_object(NM, primary_connection)
primary_devices = primary_connection.Get(NM_CON_ACT, 'Devices', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)

for dev in primary_devices:
dev_obj = self.bus.get_object(NM, str(dev))
metered_prop = dev_obj.Get(NM_DEV, 'Metered', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)

if network_type == NetworkType.wifi:
if metered_prop in [NMMetered.NM_METERED_YES, NMMetered.NM_METERED_GUESS_YES]:
return True
elif network_type in [NetworkType.cell2G, NetworkType.cell3G, NetworkType.cell4G, NetworkType.cell5G]:
if network_type == NetworkType.wifi:
result = subprocess.run(["wpa_cli", "-i", "wlan0", "status"],
capture_output=True, text=True, timeout=2)
ssid = parse_status(result.stdout).get("ssid")
if ssid:
# NetworkStore in wifi_manager.py owns the SSID-to-filename
# encoding (percent-encoded, lossless). Rather than duplicating
# that encoding here (and drifting out of sync again), match by
# the ssid field inside each .nmconnection file.
try:
filenames = os.listdir(NM_CONNECTIONS_DIR)
except OSError:
filenames = []
for fname in filenames:
if not fname.endswith(".nmconnection"):
continue
fpath = os.path.join(NM_CONNECTIONS_DIR, fname)
raw = sudo_read(fpath)
if not raw:
continue
cp = configparser.ConfigParser(interpolation=None)
try:
cp.read_string(raw)
if cp.get("wifi", "ssid", fallback="") != ssid:
continue
metered = cp.getint("connection", "metered", fallback=0)
except (configparser.Error, ValueError):
continue
if metered == 1: # YES
return True
if metered == 2: # NO
return False
break
elif network_type in [NetworkType.cell2G, NetworkType.cell3G, NetworkType.cell4G, NetworkType.cell5G]:
# Cellular metered check still via NM (NM still manages cellular)
primary_connection = self.nm.Get(NM, 'PrimaryConnection', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
primary_connection = self.bus.get_object(NM, primary_connection)
primary_devices = primary_connection.Get(NM_CON_ACT, 'Devices', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
for dev in primary_devices:
dev_obj = self.bus.get_object(NM, str(dev))
metered_prop = dev_obj.Get(NM_DEV, 'Metered', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if metered_prop == NMMetered.NM_METERED_NO:
return False
except Exception:
Expand Down
Loading
Loading