Device Management

nmrs provides methods to list, inspect, and control network devices managed by NetworkManager.

Listing All Devices

use nmrs::NetworkManager;

#[tokio::main]
async fn main() -> nmrs::Result<()> {
    let nm = NetworkManager::new().await?;

    let devices = nm.list_devices().await?;
    for device in &devices {
        println!("{}", device); // "wlan0 (Wi-Fi) [Activated]"
    }

    Ok(())
}

The Device Struct

Each device provides the following information:

FieldTypeDescription
pathStringD-Bus object path
interfaceStringInterface name (e.g., wlan0, eth0)
identityDeviceIdentityMAC addresses (permanent and current)
device_typeDeviceTypeType of device
stateDeviceStateCurrent operational state
managedOption<bool>Whether NetworkManager manages this device
driverOption<String>Kernel driver name
ip4_addressOption<String>IPv4 address with CIDR (when connected)
ip6_addressOption<String>IPv6 address with CIDR (when connected)

Device Types

#![allow(unused)]
fn main() {
use nmrs::DeviceType;
}
VariantDescription
DeviceType::WifiWi-Fi (802.11) wireless adapter
DeviceType::EthernetWired Ethernet interface
DeviceType::BluetoothBluetooth network device
DeviceType::WifiP2PWi-Fi Direct (peer-to-peer)
DeviceType::LoopbackLoopback interface (localhost)
DeviceType::Other(u32)Unknown type with raw code

Type Helper Methods

#![allow(unused)]
fn main() {
let device = &devices[0];

if device.is_wireless() {
    println!("{} is a Wi-Fi adapter", device.interface);
}

if device.is_wired() {
    println!("{} is an Ethernet interface", device.interface);
}

if device.is_bluetooth() {
    println!("{} is a Bluetooth device", device.interface);
}
}

DeviceType also provides capability queries:

#![allow(unused)]
fn main() {
let dt = &device.device_type;

dt.supports_scanning();         // true for Wifi, WifiP2P
dt.requires_specific_object();  // true for Wifi, WifiP2P
dt.has_global_enabled_state();  // true for Wifi
dt.connection_type_str();       // "802-11-wireless", "802-3-ethernet", etc.
dt.to_code();                   // raw NM type code (2 for Wifi, 1 for Ethernet)
}

Device States

#![allow(unused)]
fn main() {
use nmrs::DeviceState;
}
StateDescription
UnmanagedNot managed by NetworkManager
UnavailableManaged but not ready (e.g., Wi-Fi disabled)
DisconnectedAvailable but not connected
PreparePreparing to connect
ConfigBeing configured
NeedAuthWaiting for credentials
IpConfigRequesting IP configuration
IpCheckVerifying IP connectivity
SecondariesWaiting for secondary connections
ActivatedFully connected and operational
DeactivatingDisconnecting
FailedConnection failed
Other(u32)Unknown state with raw code

Transitional States

Use is_transitional() to check if a device is in a connecting or disconnecting state:

#![allow(unused)]
fn main() {
if device.state.is_transitional() {
    println!("{} is in a transitional state: {}", device.interface, device.state);
}
}

Transitional states include: Prepare, Config, NeedAuth, IpConfig, IpCheck, Secondaries, and Deactivating.

Filtered Device Lists

#![allow(unused)]
fn main() {
let nm = NetworkManager::new().await?;

// Only wireless devices
let wireless = nm.list_wireless_devices().await?;

// Only wired devices
let wired = nm.list_wired_devices().await?;

// Only Bluetooth devices (returns BluetoothDevice, not Device)
let bluetooth = nm.list_bluetooth_devices().await?;
}

Wi-Fi Radio Control

Enable or disable the Wi-Fi radio globally:

#![allow(unused)]
fn main() {
let nm = NetworkManager::new().await?;

// Check current state
let enabled = nm.wifi_enabled().await?;
println!("Wi-Fi enabled: {}", enabled);

// Check hardware switch (rfkill)
let hw_enabled = nm.wifi_hardware_enabled().await?;
println!("Wi-Fi hardware enabled: {}", hw_enabled);

// Toggle Wi-Fi
nm.set_wifi_enabled(false).await?; // Disable
nm.set_wifi_enabled(true).await?;  // Enable
}

Note: wifi_hardware_enabled() reflects the rfkill state. If the hardware switch is off, enabling Wi-Fi via software will have no effect.

Waiting for Wi-Fi Ready

After enabling Wi-Fi, the device may take a moment to become ready:

#![allow(unused)]
fn main() {
let nm = NetworkManager::new().await?;

nm.set_wifi_enabled(true).await?;
nm.wait_for_wifi_ready().await?;

// Now safe to scan and connect
nm.scan_networks().await?;
}

Finding a Device by Interface Name

#![allow(unused)]
fn main() {
let nm = NetworkManager::new().await?;

let device_path = nm.get_device_by_interface("wlan0").await?;
println!("D-Bus path: {}", device_path.as_str());
}

Device Identity

Each device has both a permanent (factory) and current MAC address:

#![allow(unused)]
fn main() {
for device in nm.list_devices().await? {
    println!("{}: permanent={}, current={}",
        device.interface,
        device.identity.permanent_mac,
        device.identity.current_mac,
    );
}
}

If MAC randomization is enabled, the current MAC will differ from the permanent one.

Checking Connection Progress

Before starting a new connection, check if any device is currently connecting:

#![allow(unused)]
fn main() {
if nm.is_connecting().await? {
    println!("A connection operation is in progress");
}
}

Next Steps