File indexing completed on 2024-04-21 03:59:59

0001 /*
0002     SPDX-FileCopyrightText: 2014 Jan Grulich <jgrulich@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "fakenetwork.h"
0008 #include "connection.h"
0009 #include "wireddevice.h"
0010 #include "wirelessdevice.h"
0011 
0012 #include <QDBusConnection>
0013 #include <QDBusMetaType>
0014 #include <QTimer>
0015 
0016 #include "../manager.h"
0017 #include "connectionsettings.h"
0018 
0019 FakeNetwork::FakeNetwork(QObject *parent)
0020     : QObject(parent)
0021     , m_activatingConnection(QDBusObjectPath("/"))
0022     , m_connectivity(NetworkManager::Connectivity::NoConnectivity)
0023     , m_networkingEnabled(true)
0024     , m_primaryConnection(QDBusObjectPath("/"))
0025     , m_state(20)
0026     , m_version(QLatin1String("0.9.10.0"))
0027     , m_wimaxEnabled(true)
0028     , m_wimaxHardwareEnabled(true)
0029     , m_wirelessEnabled(true)
0030     , m_wirelessHardwareEnabled(true)
0031     , m_wwanEnabled(true)
0032     , m_wwanHardwareEnabled(true)
0033     , m_activeConnectionsCounter(0)
0034     , m_deviceCounter(0)
0035     , m_settings(new Settings(this))
0036 {
0037     qDBusRegisterMetaType<QDBusObjectPath>();
0038     registerService();
0039     connect(m_settings, &Settings::connectionAdded, this, &FakeNetwork::onConnectionAdded);
0040     connect(m_settings, &Settings::connectionRemoved, this, &FakeNetwork::onConnectionRemoved);
0041 }
0042 
0043 FakeNetwork::~FakeNetwork()
0044 {
0045     unregisterService();
0046     qDeleteAll(m_devices);
0047     delete m_settings;
0048 }
0049 
0050 QDBusObjectPath FakeNetwork::activatingConnection() const
0051 {
0052     return m_activatingConnection;
0053 }
0054 
0055 QList<QDBusObjectPath> FakeNetwork::activeConnections() const
0056 {
0057     return m_activeConnections.keys();
0058 }
0059 
0060 uint FakeNetwork::connectivity() const
0061 {
0062     return m_connectivity;
0063 }
0064 
0065 QList<QDBusObjectPath> FakeNetwork::devices() const
0066 {
0067     return m_devices.keys();
0068 }
0069 
0070 bool FakeNetwork::networkingEnabled() const
0071 {
0072     return m_networkingEnabled;
0073 }
0074 
0075 QDBusObjectPath FakeNetwork::primaryConnection() const
0076 {
0077     return m_primaryConnection;
0078 }
0079 
0080 uint FakeNetwork::state() const
0081 {
0082     return m_state;
0083 }
0084 
0085 QString FakeNetwork::version() const
0086 {
0087     return m_version;
0088 }
0089 
0090 bool FakeNetwork::wimaxEnabled() const
0091 {
0092     return m_wimaxEnabled;
0093 }
0094 
0095 void FakeNetwork::setWimaxEnabled(bool enabled)
0096 {
0097     m_wimaxEnabled = enabled;
0098 
0099     QVariantMap map;
0100     map.insert(QLatin1String("WimaxEnabled"), m_wimaxEnabled);
0101     Q_EMIT PropertiesChanged(map);
0102 }
0103 
0104 bool FakeNetwork::wimaxHardwareEnabled() const
0105 {
0106     return m_wimaxHardwareEnabled;
0107 }
0108 
0109 void FakeNetwork::setWimaxHardwareEnabled(bool enabled)
0110 {
0111     m_wimaxHardwareEnabled = enabled;
0112 
0113     QVariantMap map;
0114     map.insert(QLatin1String("WimaxHardwareEnabled"), m_wimaxHardwareEnabled);
0115     Q_EMIT PropertiesChanged(map);
0116 }
0117 
0118 bool FakeNetwork::wirelessEnabled() const
0119 {
0120     return m_wirelessEnabled;
0121 }
0122 
0123 void FakeNetwork::setWirelessEnabled(bool enabled)
0124 {
0125     m_wirelessEnabled = enabled;
0126 
0127     QVariantMap map;
0128     map.insert(QLatin1String("WirelessEnabled"), m_wirelessEnabled);
0129     Q_EMIT PropertiesChanged(map);
0130 }
0131 
0132 bool FakeNetwork::wirelessHardwareEnabled() const
0133 {
0134     return m_wirelessHardwareEnabled;
0135 }
0136 
0137 void FakeNetwork::setWirelessHardwareEnabled(bool enabled)
0138 {
0139     m_wirelessHardwareEnabled = enabled;
0140 
0141     QVariantMap map;
0142     map.insert(QLatin1String("WirelessHardwareEnabled"), m_wirelessHardwareEnabled);
0143     Q_EMIT PropertiesChanged(map);
0144 }
0145 
0146 bool FakeNetwork::wwanEnabled() const
0147 {
0148     return m_wwanEnabled;
0149 }
0150 
0151 void FakeNetwork::setWwanEnabled(bool enabled)
0152 {
0153     m_wwanEnabled = enabled;
0154 
0155     QVariantMap map;
0156     map.insert(QLatin1String("WwanEnabled"), m_wwanEnabled);
0157     Q_EMIT PropertiesChanged(map);
0158 }
0159 
0160 bool FakeNetwork::wwanHardwareEnabled() const
0161 {
0162     return m_wwanHardwareEnabled;
0163 }
0164 
0165 void FakeNetwork::addDevice(Device *device)
0166 {
0167     QString newDevicePath = QString("/org/kde/fakenetwork/Devices/") + QString::number(m_deviceCounter++);
0168     device->setDevicePath(newDevicePath);
0169     m_devices.insert(QDBusObjectPath(newDevicePath), device);
0170     QDBusConnection::sessionBus().registerObject(newDevicePath, device, QDBusConnection::ExportScriptableContents);
0171     Q_EMIT DeviceAdded(QDBusObjectPath(newDevicePath));
0172 }
0173 
0174 void FakeNetwork::removeDevice(Device *device)
0175 {
0176     m_devices.remove(QDBusObjectPath(device->devicePath()));
0177     QDBusConnection::sessionBus().unregisterObject(device->devicePath());
0178     Q_EMIT DeviceRemoved(QDBusObjectPath(device->devicePath()));
0179 }
0180 
0181 void FakeNetwork::registerService()
0182 {
0183     QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.fakenetwork"));
0184     QDBusConnection::sessionBus().registerObject(QLatin1String("/org/kde/fakenetwork"), this, QDBusConnection::ExportScriptableContents);
0185     QDBusConnection::sessionBus().registerObject(QLatin1String("/org/kde/fakenetwork/Settings"), m_settings, QDBusConnection::ExportScriptableContents);
0186 
0187     for (auto it = m_devices.cbegin(); it != m_devices.cend(); ++it) {
0188         const QDBusObjectPath &devicePath = it.key();
0189         QDBusConnection::sessionBus().registerObject(devicePath.path(), it.value(), QDBusConnection::ExportScriptableContents);
0190         Q_EMIT DeviceAdded(devicePath);
0191     }
0192 }
0193 
0194 void FakeNetwork::unregisterService()
0195 {
0196     for (auto it = m_devices.cbegin(); it != m_devices.cend(); ++it) {
0197         const QDBusObjectPath &devicePath = it.key();
0198         QDBusConnection::sessionBus().unregisterObject(devicePath.path());
0199         Q_EMIT DeviceRemoved(devicePath);
0200     }
0201 
0202     QDBusConnection::sessionBus().unregisterObject(QLatin1String("/org/kde/fakenetwork/Settings"));
0203     QDBusConnection::sessionBus().unregisterObject(QLatin1String("/org/kde/fakenetwork"));
0204     QDBusConnection::sessionBus().unregisterService(QLatin1String("org.kde.fakenetwork"));
0205 }
0206 
0207 QDBusObjectPath FakeNetwork::ActivateConnection(const QDBusObjectPath &connection, const QDBusObjectPath &device, const QDBusObjectPath &specific_object)
0208 {
0209     QString newActiveConnectionPath = QString("/org/kde/fakenetwork/ActiveConnection/") + QString::number(m_activeConnectionsCounter++);
0210     ActiveConnection *newActiveConnection = new ActiveConnection(this);
0211     newActiveConnection->addDevice(device);
0212     newActiveConnection->setActiveConnectionPath(newActiveConnectionPath);
0213     newActiveConnection->setConnection(connection);
0214     newActiveConnection->setSpecificObject(specific_object);
0215     newActiveConnection->setState(NetworkManager::ActiveConnection::Activating);
0216 
0217     m_activeConnections.insert(QDBusObjectPath(newActiveConnectionPath), newActiveConnection);
0218     QDBusConnection::sessionBus().registerObject(newActiveConnectionPath, newActiveConnection, QDBusConnection::ExportScriptableContents);
0219 
0220     m_activatingConnection = QDBusObjectPath(newActiveConnectionPath);
0221 
0222     QVariantMap map;
0223     map.insert(QLatin1String("ActiveConnections"), QVariant::fromValue<QList<QDBusObjectPath>>(m_activeConnections.keys()));
0224     map.insert(QLatin1String("ActivatingConnection"), QVariant::fromValue(QDBusObjectPath(newActiveConnectionPath)));
0225     Q_EMIT PropertiesChanged(map);
0226 
0227     Device *usedDevice = static_cast<Device *>(QDBusConnection::sessionBus().objectRegisteredAt(device.path()));
0228     if (usedDevice) {
0229         m_activatedDevice = usedDevice->devicePath();
0230         // Start simulation of activation
0231         usedDevice->setActiveConnection(newActiveConnectionPath);
0232         usedDevice->setState(NetworkManager::Device::Preparing);
0233         QTimer::singleShot(100, this, SLOT(updateConnectingState()));
0234     }
0235 
0236     return QDBusObjectPath(newActiveConnectionPath);
0237 }
0238 
0239 void FakeNetwork::updateConnectingState()
0240 {
0241     QVariantMap deviceMap;
0242     Device *device = m_devices.value(QDBusObjectPath(m_activatedDevice));
0243     if (device->state() == NetworkManager::Device::Preparing) {
0244         device->setState(NetworkManager::Device::ConfiguringHardware);
0245     } else if (device->state() == NetworkManager::Device::ConfiguringHardware) {
0246         device->setState(NetworkManager::Device::NeedAuth);
0247     } else if (device->state() == NetworkManager::Device::NeedAuth) {
0248         device->setState(NetworkManager::Device::ConfiguringIp);
0249     } else if (device->state() == NetworkManager::Device::ConfiguringIp) {
0250         device->setState(NetworkManager::Device::CheckingIp);
0251     } else if (device->state() == NetworkManager::Device::CheckingIp) {
0252         device->setState(NetworkManager::Device::Activated);
0253 
0254         ActiveConnection *activeConnection =
0255             static_cast<ActiveConnection *>(QDBusConnection::sessionBus().objectRegisteredAt(device->activeConnection().path()));
0256         if (activeConnection) {
0257             QVariantMap activeConnectionMap;
0258             activeConnectionMap.insert(QLatin1String("State"), NetworkManager::ActiveConnection::Activated);
0259 
0260             activeConnection->setState(NetworkManager::ActiveConnection::Activated);
0261             QDBusMessage message = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0262                                                               QLatin1String("org.kde.fakenetwork.Connection.Active"),
0263                                                               QLatin1String("PropertiesChanged"));
0264             message << activeConnectionMap;
0265             QDBusConnection::sessionBus().send(message);
0266 
0267             QDBusMessage message2 = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0268                                                                QLatin1String("org.kde.fakenetwork.Connection.Active"),
0269                                                                QLatin1String("StateChanged"));
0270             message2 << (uint)2 << (uint)1; // NM_ACTIVE_CONNECTION_STATE_ACTIVATED << NM_ACTIVE_CONNECTION_STATE_REASON_NONE
0271             QDBusConnection::sessionBus().send(message2);
0272         }
0273         // TODO: set dhcp4Config, dhcp6Config, ip4Config, ip6Config
0274         // IP Interface is usually same as interface
0275         device->setIpInterface(device->interface());
0276         // Set some IP address
0277         device->setIpv4Address(1763189258);
0278 
0279         deviceMap.insert(QLatin1String("IpInterface"), device->ipInterface());
0280         deviceMap.insert(QLatin1String("Ip4Address"), device->ip4Address());
0281         deviceMap.insert(QLatin1String("ActiveConnection"), m_activatingConnection.path());
0282 
0283         // Update FakeNetwork state, connectivity, primary connection
0284         m_connectivity = NetworkManager::Connectivity::Full;
0285         m_primaryConnection = m_activatingConnection;
0286         m_activatingConnection = QDBusObjectPath("/");
0287         m_state = 70;
0288         QVariantMap networkMap;
0289         networkMap.insert(QLatin1String("ActivatingConnection"), QVariant::fromValue(m_activatingConnection));
0290         networkMap.insert(QLatin1String("Connectivity"), NetworkManager::Connectivity::Full);
0291         networkMap.insert(QLatin1String("PrimaryConnection"), QVariant::fromValue(m_primaryConnection));
0292         networkMap.insert(QLatin1String("State"), m_state);
0293 
0294         QDBusMessage message =
0295             QDBusMessage::createSignal(QLatin1String("/org/kde/fakenetwork"), QLatin1String("org.kde.fakenetwork"), QLatin1String("PropertiesChanged"));
0296         message << networkMap;
0297         QDBusConnection::sessionBus().send(message);
0298 
0299         Q_EMIT StateChanged(m_state);
0300     }
0301 
0302     deviceMap.insert(QLatin1String("State"), device->state());
0303     QDBusMessage message = QDBusMessage::createSignal(device->devicePath(), device->deviceInterface(), QLatin1String("PropertiesChanged"));
0304     message << deviceMap;
0305     QDBusConnection::sessionBus().send(message);
0306 
0307     if (device->state() != NetworkManager::Device::Activated) {
0308         QTimer::singleShot(100, this, SLOT(updateConnectingState()));
0309     }
0310 }
0311 
0312 uint FakeNetwork::CheckConnectivity() const
0313 {
0314     return m_connectivity;
0315 }
0316 
0317 void FakeNetwork::DeactivateConnection(const QDBusObjectPath &active_connection)
0318 {
0319     ActiveConnection *activeConnection = m_activeConnections.value(active_connection);
0320     if (activeConnection) {
0321         activeConnection->setState(NetworkManager::ActiveConnection::Deactivating);
0322 
0323         QVariantMap activeConnectionMap;
0324         activeConnectionMap.insert(QLatin1String("State"), NetworkManager::ActiveConnection::Deactivating);
0325 
0326         activeConnection->setState(NetworkManager::ActiveConnection::Activated);
0327         QDBusMessage message = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0328                                                           QLatin1String("org.kde.fakenetwork.Connection.Active"),
0329                                                           QLatin1String("PropertiesChanged"));
0330         message << activeConnectionMap;
0331         QDBusConnection::sessionBus().send(message);
0332 
0333         QDBusMessage message2 = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0334                                                            QLatin1String("org.kde.fakenetwork.Connection.Active"),
0335                                                            QLatin1String("StateChanged"));
0336         message2 << (uint)4 << (uint)2; // NM_ACTIVE_CONNECTION_STATE_DEACTIVATED << NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED
0337         QDBusConnection::sessionBus().send(message2);
0338 
0339         Device *device = m_devices.value(activeConnection->devices().first());
0340         if (device) {
0341             m_deactivatedDevice = device->devicePath();
0342             device->setState(NetworkManager::Device::Deactivating);
0343             QTimer::singleShot(100, this, SLOT(updateDeactivatingState()));
0344         }
0345 
0346         // Update FakeNetwork state, connectivity, primary connection
0347         m_connectivity = NetworkManager::Connectivity::NoConnectivity;
0348         m_primaryConnection = QDBusObjectPath("/");
0349         m_state = 20;
0350         QVariantMap networkMap;
0351         networkMap.insert(QLatin1String("Connectivity"), m_connectivity);
0352         networkMap.insert(QLatin1String("PrimaryConnection"), QVariant::fromValue(m_primaryConnection));
0353         networkMap.insert(QLatin1String("State"), m_state);
0354 
0355         message = QDBusMessage::createSignal(QLatin1String("/org/kde/fakenetwork"), QLatin1String("org.kde.fakenetwork"), QLatin1String("PropertiesChanged"));
0356         message << networkMap;
0357         QDBusConnection::sessionBus().send(message);
0358 
0359         Q_EMIT StateChanged(m_state);
0360     }
0361 }
0362 
0363 void FakeNetwork::updateDeactivatingState()
0364 {
0365     QVariantMap deviceMap;
0366     Device *device = m_devices.value(QDBusObjectPath(m_deactivatedDevice));
0367     ActiveConnection *activeConnection = static_cast<ActiveConnection *>(QDBusConnection::sessionBus().objectRegisteredAt(device->activeConnection().path()));
0368     if (activeConnection) {
0369         QVariantMap activeConnectionMap;
0370         activeConnectionMap.insert(QLatin1String("State"), NetworkManager::ActiveConnection::Deactivated);
0371 
0372         activeConnection->setState(NetworkManager::ActiveConnection::Activated);
0373         QDBusMessage message = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0374                                                           QLatin1String("org.kde.fakenetwork.Connection.Active"),
0375                                                           QLatin1String("PropertiesChanged"));
0376         message << activeConnectionMap;
0377         QDBusConnection::sessionBus().send(message);
0378 
0379         QDBusMessage message2 = QDBusMessage::createSignal(activeConnection->activeConnectionPath(),
0380                                                            QLatin1String("org.kde.fakenetwork.Connection.Active"),
0381                                                            QLatin1String("StateChanged"));
0382         message2 << (uint)3 << (uint)2; // NM_ACTIVE_CONNECTION_STATE_DEACTIVATING << NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED
0383         QDBusConnection::sessionBus().send(message2);
0384 
0385         removeActiveConnection(QDBusObjectPath(activeConnection->activeConnectionPath()));
0386     }
0387 
0388     device->setActiveConnection(QLatin1String("/"));
0389     device->setState(NetworkManager::Device::Disconnected);
0390     // TODO: set dhcp4Config, dhcp6Config, ip4Config, ip6Config
0391     // IP Interface is usually same as interface
0392     device->setIpInterface("");
0393     // Set some IP address
0394     device->setIpv4Address(0);
0395 
0396     deviceMap.insert(QLatin1String("ActiveConnection"), device->activeConnection().path());
0397     deviceMap.insert(QLatin1String("IpInterface"), device->ipInterface());
0398     deviceMap.insert(QLatin1String("Ip4Address"), device->ip4Address());
0399     deviceMap.insert(QLatin1String("State"), device->state());
0400 
0401     QDBusMessage message = QDBusMessage::createSignal(device->devicePath(), device->deviceInterface(), QLatin1String("PropertiesChanged"));
0402     message << deviceMap;
0403     QDBusConnection::sessionBus().send(message);
0404 }
0405 
0406 QDBusObjectPath FakeNetwork::GetDeviceByIpIface(const QString &iface)
0407 {
0408     Q_UNUSED(iface)
0409     // TODO
0410     return QDBusObjectPath();
0411 }
0412 
0413 QList<QDBusObjectPath> FakeNetwork::GetDevices() const
0414 {
0415     return m_devices.keys();
0416 }
0417 
0418 void FakeNetwork::onConnectionAdded(const QDBusObjectPath &connection)
0419 {
0420     Connection *newConnection = static_cast<Connection *>(QDBusConnection::sessionBus().objectRegisteredAt(connection.path()));
0421     if (newConnection) {
0422         NMVariantMapMap settings = newConnection->GetSettings();
0423         NetworkManager::ConnectionSettings::ConnectionType type =
0424             NetworkManager::ConnectionSettings::typeFromString(settings.value(QLatin1String("connection")).value(QLatin1String("type")).toString());
0425         if (!m_devices.isEmpty()) {
0426             Device *selectedDevice = nullptr;
0427             for (Device *device : std::as_const(m_devices)) {
0428                 if (type == NetworkManager::ConnectionSettings::Wired && device->deviceType() == NetworkManager::Device::Ethernet) {
0429                     selectedDevice = device;
0430                     device->addAvailableConnection(connection);
0431                     break;
0432                 } else if (type == NetworkManager::ConnectionSettings::Wireless && device->deviceType() == NetworkManager::Device::Wifi) {
0433                     selectedDevice = device;
0434                     // TODO
0435                     break;
0436                 }
0437             }
0438 
0439             if (selectedDevice) {
0440                 QVariantMap map;
0441                 map.insert(QLatin1String("AvailableConnections"), QVariant::fromValue<QList<QDBusObjectPath>>(selectedDevice->availableConnections()));
0442 
0443                 QDBusMessage message =
0444                     QDBusMessage::createSignal(selectedDevice->devicePath(), selectedDevice->deviceInterface(), QLatin1String("PropertiesChanged"));
0445                 message << map;
0446                 QDBusConnection::sessionBus().send(message);
0447             }
0448         }
0449     }
0450 }
0451 
0452 void FakeNetwork::onConnectionRemoved(const QDBusObjectPath &connection)
0453 {
0454     for (Device *device : std::as_const(m_devices)) {
0455         if (device && device->availableConnections().contains(connection)) {
0456             device->removeAvailableConnection(connection);
0457 
0458             QVariantMap map;
0459             map.insert(QLatin1String("AvailableConnections"), QVariant::fromValue<QList<QDBusObjectPath>>(device->availableConnections()));
0460 
0461             QDBusMessage message = QDBusMessage::createSignal(device->devicePath(), device->deviceInterface(), QLatin1String("PropertiesChanged"));
0462             message << map;
0463             QDBusConnection::sessionBus().send(message);
0464         }
0465     }
0466 }
0467 
0468 void FakeNetwork::removeActiveConnection(const QDBusObjectPath &activeConnection)
0469 {
0470     delete m_activeConnections.value(activeConnection);
0471     m_activeConnections.remove(activeConnection);
0472     QDBusConnection::sessionBus().unregisterObject(activeConnection.path());
0473 
0474     QVariantMap map;
0475     map.insert(QLatin1String("ActiveConnections"), QVariant::fromValue<QList<QDBusObjectPath>>(m_activeConnections.keys()));
0476     Q_EMIT PropertiesChanged(map);
0477 }
0478 
0479 #include "moc_fakenetwork.cpp"