D-Bus Architecture

nmrs communicates with NetworkManager over the D-Bus system bus. Understanding this architecture helps with debugging and explains why certain operations work the way they do.

Overview

┌─────────────┐     D-Bus (system bus)     ┌──────────────────┐
│   Your App  │ ◄────────────────────────► │  NetworkManager  │
│   (nmrs)    │                            │    Daemon        │
└─────────────┘                            └──────────────────┘
       │                                          │
       │  zbus (Rust D-Bus library)               │
       │                                          │
       ▼                                          ▼
  nmrs::dbus module                    D-Bus interfaces:
  (proxy types)                        - org.freedesktop.NetworkManager
                                       - org.freedesktop.NetworkManager.Device
                                       - org.freedesktop.NetworkManager.Device.Wireless
                                       - org.freedesktop.NetworkManager.AccessPoint
                                       - org.freedesktop.NetworkManager.Connection.Active
                                       - org.freedesktop.NetworkManager.Settings
                                       - ...

How nmrs Uses D-Bus

Connection Establishment

When you call NetworkManager::new(), nmrs connects to the system D-Bus using zbus:

#![allow(unused)]
fn main() {
let nm = NetworkManager::new().await?;
// Internally: zbus::Connection::system().await
}

This creates a persistent D-Bus connection that's shared across all operations.

Method Calls

API methods like list_devices() translate to D-Bus method calls:

nmrs: nm.list_devices()
  → D-Bus: GetDevices() on org.freedesktop.NetworkManager
  ← D-Bus: Array of device object paths
  → D-Bus: Get properties for each device path
  ← D-Bus: Device properties (interface, type, state, etc.)
  → nmrs: Vec<Device>

Signal Monitoring

monitor_network_changes() subscribes to D-Bus signals:

nmrs: nm.monitor_network_changes(callback)
  → D-Bus: Subscribe to AccessPointAdded/Removed signals
  ← D-Bus: Signal whenever an AP appears or disappears
  → nmrs: Invoke callback

Connection Settings

When connecting to a network, nmrs builds a settings dictionary and sends it via D-Bus:

nmrs: nm.connect("MyWiFi", WifiSecurity::WpaPsk { psk: "..." })
  → Build settings HashMap
  → D-Bus: AddAndActivateConnection(settings, device_path, specific_object)
  ← D-Bus: Active connection path
  → D-Bus: Monitor StateChanged signal
  ← D-Bus: State transitions until Activated or Failed
  → nmrs: Ok(()) or Err(ConnectionError)

D-Bus Proxy Types

nmrs wraps D-Bus interfaces in typed proxy structs (defined in nmrs::dbus):

ProxyD-Bus InterfacePurpose
NMProxyorg.freedesktop.NetworkManagerMain NM interface
NMDeviceProxyorg.freedesktop.NetworkManager.DeviceDevice properties and control
NMWirelessProxyorg.freedesktop.NetworkManager.Device.WirelessWi-Fi scanning, AP list
NMAccessPointProxyorg.freedesktop.NetworkManager.AccessPointAP signal, SSID, security
NMActiveConnectionProxyorg.freedesktop.NetworkManager.Connection.ActiveActive connection state
NMWiredProxyorg.freedesktop.NetworkManager.Device.WiredWired device properties
NMBluetoothProxyorg.freedesktop.NetworkManager.Device.BluetoothBluetooth properties

These are internal types — you interact with them through the high-level NetworkManager API.

D-Bus Errors

D-Bus communication errors surface as ConnectionError::Dbus or ConnectionError::DbusOperation:

#![allow(unused)]
fn main() {
use nmrs::ConnectionError;

match result {
    Err(ConnectionError::Dbus(e)) => {
        eprintln!("D-Bus error: {}", e);
    }
    Err(ConnectionError::DbusOperation { context, source }) => {
        eprintln!("{}: {}", context, source);
    }
    _ => {}
}
}

Common causes:

  • NetworkManager is not running
  • D-Bus system bus is not available
  • Insufficient permissions (PolicyKit)

Permissions

NetworkManager uses PolicyKit for authorization. Most operations require the user to be in the network group or to have appropriate PolicyKit rules. See Requirements for setup details.

Debugging D-Bus

Monitor D-Bus Traffic

Use dbus-monitor to see raw D-Bus messages:

sudo dbus-monitor --system "interface='org.freedesktop.NetworkManager'"

Check NetworkManager State

nmcli general status
nmcli device status
nmcli connection show

Verify D-Bus Service

busctl list | grep NetworkManager

Next Steps