Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions mmrs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

All notable changes to the `mmrs` crate will be documented in this file.

## [Unreleased]
23 changes: 23 additions & 0 deletions mmrs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# mmrs

Rust bindings for [ModemManager](https://modemmanager.org/) over D-Bus.

> **Status:** Early development. Tracking issue [#398](https://github.com/networkmanager-rs/nmrs/issues/398).
Comment thread
cachebag marked this conversation as resolved.

## Requirements

- Linux with ModemManager running
- Rust 1.90.0+

## Contributing

Contributions welcome — see the [contributing guide](../docs/src/development/contributing.md). In short:

- Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) (`type(#issue): description`)
- Run `cargo +nightly fmt`, `cargo clippy -- -D warnings`, and `cargo test -p mmrs` before submitting
Comment thread
cachebag marked this conversation as resolved.
- Attach a relevant [issue](https://github.com/cachebag/nmrs/issues) when possible
- All tests must pass before merge

## License

Licensed under either of [MIT](../LICENSE-MIT) or [Apache-2.0](../LICENSE-APACHE), at your option.
46 changes: 46 additions & 0 deletions mmrs/src/dbus/bearer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! ModemManager Bearer proxy.

use std::collections::HashMap;

use zbus::proxy;
use zvariant::OwnedValue;

/// Proxy for the ModemManager1 Bearer interface.
///
/// Represents a packet data connection. Provides methods to connect
/// and disconnect, plus properties for IP configuration and statistics.
#[proxy(
interface = "org.freedesktop.ModemManager1.Bearer",
default_service = "org.freedesktop.ModemManager1"
)]
pub trait MMBearer {
/// Activate the bearer and bring up the data connection.
fn connect(&self) -> zbus::Result<()>;

/// Deactivate the bearer and tear down the data connection.
fn disconnect(&self) -> zbus::Result<()>;

/// Network interface name for this bearer (e.g., "wwan0").
#[zbus(property)]
fn interface(&self) -> zbus::Result<String>;

/// Whether the bearer is currently connected.
#[zbus(property)]
fn connected(&self) -> zbus::Result<bool>;

/// Whether the bearer connection is suspended.
#[zbus(property)]
fn suspended(&self) -> zbus::Result<bool>;

/// IPv4 configuration dictionary.
#[zbus(property)]
fn ip4_config(&self) -> zbus::Result<HashMap<String, OwnedValue>>;

/// IPv6 configuration dictionary.
#[zbus(property)]
fn ip6_config(&self) -> zbus::Result<HashMap<String, OwnedValue>>;

/// Connection statistics (bytes tx/rx, duration, etc.).
#[zbus(property)]
fn stats(&self) -> zbus::Result<HashMap<String, OwnedValue>>;
}
30 changes: 30 additions & 0 deletions mmrs/src/dbus/manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! ModemManager manager proxy.

use zbus::proxy;

/// Proxy for the main ModemManager1 interface.
///
/// Provides methods for scanning devices, configuring logging,
/// and inhibiting device management.
#[proxy(
interface = "org.freedesktop.ModemManager1",
default_service = "org.freedesktop.ModemManager1",
default_path = "/org/freedesktop/ModemManager1"
)]
pub trait MMManager {
/// Re-scan for available modem devices.
fn scan_devices(&self) -> zbus::Result<()>;

/// Set the logging verbosity level.
fn set_logging(&self, level: &str) -> zbus::Result<()>;

/// Inhibit a modem device by its UID and return the inhibition cookie.
fn inhibit_device(&self, uid: &str) -> zbus::Result<u32>;

/// Release a previously acquired device inhibition cookie.
fn uninhibit_device(&self, cookie: u32) -> zbus::Result<()>;

/// ModemManager version string.
#[zbus(property)]
fn version(&self) -> zbus::Result<String>;
}
18 changes: 18 additions & 0 deletions mmrs/src/dbus/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
//! D-Bus proxy interfaces for ModemManager.
//!
//! This module contains low-level D-Bus proxy definitions for communicating
//! with ModemManager over the system bus.

// Re-exports are consumed by core/api layers that are not yet implemented.
#![allow(unused_imports)]

Comment thread
cachebag marked this conversation as resolved.
mod bearer;
mod manager;
mod modem;
mod modem_simple;
mod sim;

pub(crate) use bearer::MMBearerProxy;
pub(crate) use manager::MMManagerProxy;
pub(crate) use modem::MMModemProxy;
pub(crate) use modem_simple::MMModemSimpleProxy;
pub(crate) use sim::MMSimProxy;
110 changes: 110 additions & 0 deletions mmrs/src/dbus/modem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! ModemManager Modem proxy.

use std::collections::HashMap;

use zbus::proxy;
use zvariant::OwnedObjectPath;

/// Proxy for the ModemManager1 Modem interface.
///
/// Provides methods for enabling/disabling the modem, managing bearers,
/// resetting, and querying modem properties like signal quality and state.
///
/// # Signals
///
/// The `StateChanged` signal is emitted whenever the modem state changes.
/// Use `receive_modem_state_changed()` to get a stream of state change events:
///
/// ```ignore
/// let mut stream = modem_proxy.receive_modem_state_changed().await?;
/// while let Some(signal) = stream.next().await {
/// let args = signal.args()?;
/// println!("Old: {}, New: {}, Reason: {}", args.old, args.new, args.reason);
/// }
/// ```
#[proxy(
interface = "org.freedesktop.ModemManager1.Modem",
default_service = "org.freedesktop.ModemManager1"
)]
pub trait MMModem {
/// Enable or disable the modem.
fn enable(&self, enable: bool) -> zbus::Result<()>;

/// List paths to all bearer objects owned by this modem.
fn list_bearers(&self) -> zbus::Result<Vec<OwnedObjectPath>>;

/// Create a new packet data bearer from the given properties.
fn create_bearer(
&self,
properties: HashMap<&str, zvariant::Value<'_>>,
) -> zbus::Result<OwnedObjectPath>;

/// Delete an existing bearer.
fn delete_bearer(&self, bearer: OwnedObjectPath) -> zbus::Result<()>;

/// Reset the modem to its factory state.
fn reset(&self) -> zbus::Result<()>;

/// Set the power state of the modem.
fn set_power_state(&self, state: u32) -> zbus::Result<()>;

/// Send an AT command to the modem (direct AT channel access).
fn command(&self, cmd: &str, timeout: u32) -> zbus::Result<String>;

/// Path to the primary SIM object.
#[zbus(property)]
fn sim(&self) -> zbus::Result<OwnedObjectPath>;

/// Current modem state as the raw numeric ModemManager D-Bus value.
#[zbus(property)]
fn state(&self) -> zbus::Result<i32>;

/// Current power state of the modem.
#[zbus(property)]
fn power_state(&self) -> zbus::Result<u32>;

/// Bitmask of current access technologies in use.
#[zbus(property)]
fn access_technologies(&self) -> zbus::Result<u32>;

/// Signal quality (percentage, recently-updated flag).
#[zbus(property)]
fn signal_quality(&self) -> zbus::Result<(u32, bool)>;

/// Modem manufacturer name.
#[zbus(property)]
fn manufacturer(&self) -> zbus::Result<String>;

/// Modem model name.
#[zbus(property)]
fn model(&self) -> zbus::Result<String>;

/// Equipment identifier (IMEI for GSM, ESN/MEID for CDMA).
#[zbus(property)]
fn equipment_identifier(&self) -> zbus::Result<String>;

/// Maximum number of bearers this modem supports.
#[zbus(property)]
fn max_bearers(&self) -> zbus::Result<u32>;

/// Maximum number of simultaneously active bearers.
#[zbus(property)]
fn max_active_bearers(&self) -> zbus::Result<u32>;

/// Paths to all bearer objects owned by this modem.
#[zbus(property)]
fn bearers(&self) -> zbus::Result<Vec<OwnedObjectPath>>;

/// Signal emitted when the modem state changes.
///
/// Named `modem_state_changed` to avoid conflict with the `state`
/// property's change stream. Use `receive_modem_state_changed()` to
/// subscribe to this signal.
///
/// Arguments:
/// - `old`: The previous modem state
/// - `new`: The new modem state
/// - `reason`: The reason code for the state transition
#[zbus(signal, name = "StateChanged")]
fn modem_state_changed(&self, old: i32, new: i32, reason: u32);
}
30 changes: 30 additions & 0 deletions mmrs/src/dbus/modem_simple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! ModemManager Modem.Simple proxy.

use std::collections::HashMap;

use zbus::proxy;
use zvariant::{OwnedObjectPath, OwnedValue};

/// Proxy for the ModemManager1 Modem.Simple interface.
///
/// Provides a simplified API for connecting, disconnecting,
/// and querying modem status in a single call.
#[proxy(
interface = "org.freedesktop.ModemManager1.Modem.Simple",
default_service = "org.freedesktop.ModemManager1"
)]
pub trait MMModemSimple {
/// Simple connect with the given connection properties.
///
/// Returns the path to the connected bearer.
fn connect(
&self,
properties: HashMap<&str, zvariant::Value<'_>>,
) -> zbus::Result<OwnedObjectPath>;

/// Disconnect a specific bearer, or all if `"/"` is passed.
fn disconnect(&self, bearer: OwnedObjectPath) -> zbus::Result<()>;

/// Get the overall modem status as a property dictionary.
fn get_status(&self) -> zbus::Result<HashMap<String, OwnedValue>>;
}
41 changes: 41 additions & 0 deletions mmrs/src/dbus/sim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! ModemManager SIM proxy.

use zbus::proxy;

/// Proxy for the ModemManager1 SIM interface.
///
/// Provides methods for PIN/PUK management and access
/// to SIM identification properties.
#[proxy(
interface = "org.freedesktop.ModemManager1.Sim",
default_service = "org.freedesktop.ModemManager1"
)]
pub trait MMSim {
/// Send the SIM PIN to unlock the modem.
fn send_pin(&self, pin: &str) -> zbus::Result<()>;

/// Send the PUK and set a new PIN.
fn send_puk(&self, puk: &str, pin: &str) -> zbus::Result<()>;

/// Enable or disable PIN checking on the SIM.
fn enable_pin(&self, pin: &str, enabled: bool) -> zbus::Result<()>;

/// Change the SIM PIN.
fn change_pin(&self, old_pin: &str, new_pin: &str) -> zbus::Result<()>;

/// Whether this SIM slot is currently active.
#[zbus(property)]
fn active(&self) -> zbus::Result<bool>;

/// SIM identifier (ICCID).
#[zbus(property)]
fn sim_identifier(&self) -> zbus::Result<String>;

/// International Mobile Subscriber Identity.
#[zbus(property)]
fn imsi(&self) -> zbus::Result<String>;

/// Name of the operator this SIM is registered with.
#[zbus(property)]
fn operator_name(&self) -> zbus::Result<String>;
}