Skip to content

net: add IWD backend with passphrase agent support#2735

Draft
rXelelo wants to merge 1 commit into
noctalia-dev:v5from
rXelelo:v5
Draft

net: add IWD backend with passphrase agent support#2735
rXelelo wants to merge 1 commit into
noctalia-dev:v5from
rXelelo:v5

Conversation

@rXelelo
Copy link
Copy Markdown
Contributor

@rXelelo rXelelo commented May 19, 2026

Pull Request

If this PR is not ready for review yet, please mark it as Draft until it's good to be reviewed.

Motivation

Provide a clear and concise explanation of what this PR does and why it is needed.

Type of Change

Mark the relevant option with an "x".

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring

Related Issue

  • Closes #(issue number) (if any)

Testing

Describe how you tested your changes and mark the relevant items.

  • Tested on niri
  • Tested on Hyprland
  • Tested on sway
  • Tested with different bar positions and density settings
  • Tested at different interface scaling values
  • Tested with multiple monitors (if applicable)

Screenshots / Videos

If applicable, include screenshots or videos to help illustrate your changes.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my code
  • No new warnings or errors
  • Documentation or comments updated (if relevant)

Additional Notes

Add any additional context or follow-up notes for reviewers.

@ItsLemmy
Copy link
Copy Markdown
Collaborator

wirelessEnabled is wrong when the adapter is powered off

next.wirelessEnabled = !m_stations.empty();

This returns true as long as any station object exists, regardless of whether the device is actually powered on. A station object persists even when Device.Powered is false. This should check the Powered property on the device interface:

  bool anyPowered = false;
  for (const auto& [path, proxy] : m_stations) {
      anyPowered = anyPowered || getPropertyOr(*proxy, k_deviceInterface, "Powered", false);
  }
  next.wirelessEnabled = anyPowered;

Without this, setWirelessEnabled(false) will toggle the device off, but wirelessEnabled will still report true on the next rebuildState().

submitPasswordPrompt has incorrect dispatch when both agents exist

The diff in network_tab.cpp adds:

    } else if (m_iwdAgent != nullptr) {
      m_iwdAgent->submitSecret(value);
    } 

But this branch is only reached when m_pendingAccessPoint has no value AND m_secrets is null. In practice, if iwd is active, m_secrets should be null (NetworkSecretAgent is only created when supportsSecretAgent() returns true, which IwdService doesn't). So the logic happens to work — but it's fragile. If someone adds supportsSecretAgent() to IwdService later, the m_secrets branch would swallow iwd agent requests.

A clearer approach: check which agent actually has a pending request:

    } else if (m_secrets != nullptr && m_secrets->hasPendingRequest()) {
      m_secrets->submitSecret(value);
    } else if (m_iwdAgent != nullptr && m_iwdAgent->hasPendingRequest()) {
      m_iwdAgent->submitSecret(value);
    } 

cancelPasswordPrompt has the same fragility

Same else if chain — m_iwdAgent->cancelSecret() is only reached if m_secrets is null.

Synchronous GetOrderedNetworks in rebuildState()

rebuildState() is called on every PropertiesChanged signal from every station. Each call does a synchronous GetOrderedNetworks() D-Bus method call for each station. On systems with many visible networks or multiple adapters, this could cause noticeable latency on the main loop. The other backends (NM,
wpa_supplicant) use cached/signal-driven data. Consider debouncing or caching.

Synchronous Connect call in activateAccessPoint

  it->second->callMethod("Connect").onInterface(k_networkInterface);

Network.Connect() in iwd can block for several seconds (especially when the agent prompt is involved). This is a synchronous call on the main thread. The other backends may have the same issue, but it's worth noting — this will freeze the UI during connection attempts.

rebuildState() clears m_knownNetworks on every call

  m_knownNetworks.clear();

This rebuilds known networks from network objects only. But network objects for out-of-range saved networks won't be present, so hasSavedConnection() will return false for any saved network that isn't currently visible. forgetSsid() won't work for those either. To properly enumerate saved networks, you'd need to query net.connman.iwd.KnownNetwork objects separately.

Logging SSID in onRequestPassphrase

  kLog.info("RequestPassphrase for ssid=\"{}\" path={}", ssid, std::string(netPath));

We try to avoid login any sensible/private data in the log.

Missing InterfacesRemoved cleanup for networks used by known networks

When InterfacesRemoved fires, both m_stations and m_networks are cleaned, but m_knownNetworks entries referencing removed network paths are left dangling until the next rebuildState(). This is benign since rebuildState() clears + rebuilds, but the ordering in the signal handler (erase then rebuildState) means it's fine.

Minor Style Notes

  • k_iwdBusName, k_agentManagerPath etc..., should be kIwdBusName per project's convention
  • ifaces.count() → ifaces.contains() (C++20 is available).

@rXelelo rXelelo marked this pull request as draft May 20, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants