// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of libnymea-networkmanager. * * libnymea-networkmanager is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * libnymea-networkmanager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libnymea-networkmanager. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! \class WirelessNetworkDevice \brief Represents a wireless network device. \inmodule nymea-networkmanager \ingroup networkmanager */ /*! \enum WirelessNetworkDevice::Mode \value ModeUnknown \value ModeAdhoc \value ModeInfrastructure \value ModeAccessPoint */ /*! \fn void WirelessNetworkDevice::bitRateChanged(int bitRate); This signal will be emitted when the \a bitRate of this \l{WirelessNetworkDevice} has changed. */ /*! \fn void WirelessNetworkDevice::modeChanged(Mode mode); This signal will be emitted when the current \a mode of this \l{WirelessNetworkDevice} has changed. \sa WirelessNetworkDevice::Mode */ #include "networkmanagerutils.h" #include "wirelessnetworkdevice.h" #include #include #include /*! Constructs a new \l{WirelessNetworkDevice} with the given dbus \a objectPath and \a parent. */ WirelessNetworkDevice::WirelessNetworkDevice(const QDBusObjectPath &objectPath, QObject *parent) : NetworkDevice(objectPath, parent), m_activeAccessPoint(nullptr) { QDBusConnection systemBus = QDBusConnection::systemBus(); if (!systemBus.isConnected()) { qCWarning(dcNetworkManager()) << "WirelessNetworkDevice: System DBus not connected"; return; } m_wirelessInterface = new QDBusInterface(NetworkManagerUtils::networkManagerServiceString(), this->objectPath().path(), NetworkManagerUtils::wirelessInterfaceString(), systemBus, this); if (!m_wirelessInterface->isValid()) { qCWarning(dcNetworkManager()) << "WirelessNetworkDevice: Invalid wireless dbus interface"; return; } QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), this->objectPath().path(), NetworkManagerUtils::wirelessInterfaceString(), "AccessPointAdded", this, SLOT(accessPointAdded(QDBusObjectPath))); QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), this->objectPath().path(), NetworkManagerUtils::wirelessInterfaceString(), "AccessPointRemoved", this, SLOT(accessPointRemoved(QDBusObjectPath))); // org.freedesktop.NetworkManager.Device.Wireless.PropertiesChanged(QVariantMap) is used in older versions of NetworkManager instead of the standard D-Bus properties changed signal QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), this->objectPath().path(), NetworkManagerUtils::wirelessInterfaceString(), "PropertiesChanged", this, SLOT(processProperties(QVariantMap))); // Newer versions of NetworkManager dropped the other and switched to the D-Bus standard PropertiesChanged QDBusConnection::systemBus().connect(NetworkManagerUtils::networkManagerServiceString(), this->objectPath().path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); readAccessPoints(); m_macAddress = m_wirelessInterface->property("HwAddress").toString(); m_wirelessCapabilities = static_cast(m_wirelessInterface->property("WirelessCapabilities").toUInt()); m_wirelessMode = static_cast(m_wirelessInterface->property("Mode").toUInt()); m_bitRate = m_wirelessInterface->property("Bitrate").toInt() / 1000; setActiveAccessPoint(qdbus_cast(m_wirelessInterface->property("ActiveAccessPoint"))); } /*! Returns the mac address of this \l{WirelessNetworkDevice}. */ QString WirelessNetworkDevice::macAddress() const { return m_macAddress; } /*! Returns the bit rate [Mb/s] of this \l{WirelessNetworkDevice}. */ int WirelessNetworkDevice::bitRate() const { return m_bitRate; } WirelessNetworkDevice::WirelessCapabilities WirelessNetworkDevice::wirelessCapabilities() const { return m_wirelessCapabilities; } WirelessNetworkDevice::WirelessMode WirelessNetworkDevice::wirelessMode() const { return m_wirelessMode; } /*! Returns the current active \l{WirelessAccessPoint} of this \l{WirelessNetworkDevice}. */ WirelessAccessPoint *WirelessNetworkDevice::activeAccessPoint() { return m_activeAccessPoint; } /*! Perform a wireless network scan on this \l{WirelessNetworkDevice}. */ void WirelessNetworkDevice::scanWirelessNetworks() { qCDebug(dcNetworkManager()) << "Request scan" << this; QDBusMessage query = m_wirelessInterface->call("RequestScan", QVariantMap()); if (query.type() != QDBusMessage::ReplyMessage) { qCWarning(dcNetworkManager()) << "Scan error:" << query.errorName() << query.errorMessage(); return; } } /*! Returns the list of all \l{WirelessAccessPoint}{WirelessAccessPoints} of this \l{WirelessNetworkDevice}. */ QList WirelessNetworkDevice::accessPoints() { return m_accessPointsTable.values(); } /*! Returns the \l{WirelessAccessPoint} with the given \a ssid. If the \l{WirelessAccessPoint} could not be found, return nullptr. */ WirelessAccessPoint *WirelessNetworkDevice::getAccessPoint(const QString &ssid) { foreach (WirelessAccessPoint *accessPoint, m_accessPointsTable.values()) { if (accessPoint->ssid() == ssid) return accessPoint; } return nullptr; } /*! Returns the \l{WirelessAccessPoint} with the given \a objectPath. If the \l{WirelessAccessPoint} could not be found, return nullptr. */ WirelessAccessPoint *WirelessNetworkDevice::getAccessPoint(const QDBusObjectPath &objectPath) { return m_accessPointsTable.value(objectPath); } void WirelessNetworkDevice::readAccessPoints() { QDBusMessage query = m_wirelessInterface->call("GetAccessPoints"); if(query.type() != QDBusMessage::ReplyMessage) { qCWarning(dcNetworkManager()) << query.errorName() << query.errorMessage(); return; } if (query.arguments().isEmpty()) return; const QDBusArgument &argument = query.arguments().at(0).value(); argument.beginArray(); while (!argument.atEnd()) { QDBusObjectPath accessPointObjectPath = qdbus_cast(argument); accessPointAdded(accessPointObjectPath); } argument.endArray(); } void WirelessNetworkDevice::setActiveAccessPoint(const QDBusObjectPath &activeAccessPointObjectPath) { if (m_activeAccessPointObjectPath != activeAccessPointObjectPath) { m_activeAccessPointObjectPath = activeAccessPointObjectPath; if (m_accessPointsTable.contains(m_activeAccessPointObjectPath)) { if (m_activeAccessPoint) disconnect(m_activeAccessPoint, &WirelessAccessPoint::signalStrengthChanged, this, &WirelessNetworkDevice::deviceChanged); // Set new access point object m_activeAccessPoint = m_accessPointsTable.value(activeAccessPointObjectPath); // Update the device when the signalstrength changed connect(m_activeAccessPoint, &WirelessAccessPoint::signalStrengthChanged, this, &WirelessNetworkDevice::deviceChanged); } else { m_activeAccessPoint = nullptr; } emit deviceChanged(); } } void WirelessNetworkDevice::accessPointAdded(const QDBusObjectPath &objectPath) { QDBusInterface accessPointInterface(NetworkManagerUtils::networkManagerServiceString(), objectPath.path(), NetworkManagerUtils::accessPointInterfaceString(), QDBusConnection::systemBus()); if (!accessPointInterface.isValid()) { qCWarning(dcNetworkManager()) << this << "Invalid access point dbus interface"; return; } if (m_accessPointsTable.keys().contains(objectPath)) { qCWarning(dcNetworkManager()) << this << "Access point already added" << objectPath.path(); return; } WirelessAccessPoint *accessPoint = new WirelessAccessPoint(objectPath, this); qCDebug(dcNetworkManager()) << interface() << "[+]" << accessPoint; m_accessPointsTable.insert(objectPath, accessPoint); } void WirelessNetworkDevice::accessPointRemoved(const QDBusObjectPath &objectPath) { if (!m_accessPointsTable.keys().contains(objectPath)) return; WirelessAccessPoint *accessPoint = m_accessPointsTable.take(objectPath); if (accessPoint == m_activeAccessPoint) m_activeAccessPoint = nullptr; qCDebug(dcNetworkManager()) << interface() << "[-]" << accessPoint; accessPoint->deleteLater(); } void WirelessNetworkDevice::processProperties(const QVariantMap &properties) { //qCDebug(dcNetworkManager()) << "WirelessNetworkDevice: Property changed" << properties; if (properties.contains("Bitrate")) { m_bitRate = properties.value("Bitrate").toInt() / 1000; emit bitRateChanged(m_bitRate); } if (properties.contains("Mode")) { m_wirelessMode = static_cast(m_wirelessInterface->property("Mode").toUInt()); emit wirelessModeChanged(m_wirelessMode); } if (properties.contains("WirelessCapabilities")) { m_wirelessCapabilities = static_cast(m_wirelessInterface->property("WirelessCapabilities").toUInt()); emit wirelessCapabilitiesChanged(m_wirelessCapabilities); } // Note: available since 1.12 (-1 means never scanned) if (properties.contains("LastScan")) { m_lastScan = m_wirelessInterface->property("LastScan").toInt(); emit lastScanChanged(m_lastScan); } if (properties.contains("ActiveAccessPoint")) { setActiveAccessPoint(qdbus_cast(properties.value("ActiveAccessPoint"))); } emit deviceChanged(); } void WirelessNetworkDevice::onPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) { Q_UNUSED(interface) Q_UNUSED(invalidatedProperties) //qCDebug(dcNetworkManager()) << "WirelessNetworkDevice: Properties changed" << interface << changedProperties << invalidatedProperties; processProperties(changedProperties); } /*! Writes the given \a device to the given to \a debug. \sa WirelessNetworkDevice, */ QDebug operator<<(QDebug debug, WirelessNetworkDevice *device) { debug.nospace() << "WirelessNetworkDevice(" << device->interface() << ", "; debug.nospace() << device->macAddress() << ", "; debug.nospace() << device->wirelessCapabilities() << ", "; debug.nospace() << device->wirelessMode() << ", "; debug.nospace() << device->bitRate() << " [Mb/s], "; debug.nospace() << device->deviceStateString() << ") "; return debug.space(); }