From 6ec85236b2643a285d9f5b82088c79b0e3bf4e12 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 1 Sep 2022 13:04:05 +0200 Subject: [PATCH] Add support for connecting to hidden wifis Just like with the regular setup, so far only unprotected and WEP/WPA Personal protected networks are supported. --- .../bluetooth/bluetoothuuids.h | 1 + .../bluetooth/wirelessservice.cpp | 48 +++++++++++++------ .../bluetooth/wirelessservice.h | 2 - libnymea-networkmanager/networkmanager.cpp | 41 +++++++++++----- libnymea-networkmanager/networkmanager.h | 12 ++++- 5 files changed, 76 insertions(+), 28 deletions(-) diff --git a/libnymea-networkmanager/bluetooth/bluetoothuuids.h b/libnymea-networkmanager/bluetooth/bluetoothuuids.h index fc9065b..0d7f1df 100644 --- a/libnymea-networkmanager/bluetooth/bluetoothuuids.h +++ b/libnymea-networkmanager/bluetooth/bluetoothuuids.h @@ -45,5 +45,6 @@ static QBluetoothUuid wirelessCommanderCharacteristicUuid = QBluetoothUuid(QUuid static QBluetoothUuid wirelessResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fec2-f757-4449-b9c9-bfa83133f7fc")); static QBluetoothUuid wirelessStateCharacteristicUuid = QBluetoothUuid(QUuid("e081fec3-f757-4449-b9c9-bfa83133f7fc")); static QBluetoothUuid wirelessModeCharacteristicUuid = QBluetoothUuid(QUuid("e081fec4-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid wirelessServiceVersionCharacteristicUuid = QBluetoothUuid(QUuid("e081fec5-f757-4449-b9c9-bfa83133f7fc")); #endif // BLUETOOTHUUIDS_H diff --git a/libnymea-networkmanager/bluetooth/wirelessservice.cpp b/libnymea-networkmanager/bluetooth/wirelessservice.cpp index b435fe6..f9e701f 100644 --- a/libnymea-networkmanager/bluetooth/wirelessservice.cpp +++ b/libnymea-networkmanager/bluetooth/wirelessservice.cpp @@ -84,6 +84,13 @@ QLowEnergyServiceData WirelessService::serviceData(NetworkManager *networkManage QLowEnergyDescriptorData clientConfigDescriptorData(QBluetoothUuid::ClientCharacteristicConfiguration, QByteArray(2, 0)); + QLowEnergyCharacteristicData versionCharacteristicData; + versionCharacteristicData.setUuid(wirelessServiceVersionCharacteristicUuid); + versionCharacteristicData.setProperties(QLowEnergyCharacteristic::Read); + versionCharacteristicData.setValueLength(1, 1); + versionCharacteristicData.setValue("2"); + serviceData.addCharacteristic(versionCharacteristicData); + // Wifi commander characterisitc e081fec1-f757-4449-b9c9-bfa83133f7fc QLowEnergyCharacteristicData wirelessCommanderCharacteristicData; wirelessCommanderCharacteristicData.setUuid(wirelessCommanderCharacteristicUuid); @@ -219,11 +226,9 @@ void WirelessService::streamData(const QVariantMap &responseMap) QByteArray data = QJsonDocument::fromVariant(responseMap).toJson(QJsonDocument::Compact) + '\n'; qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Start streaming response data:" << data.count() << "bytes"; - int sentDataLength = 0; QByteArray remainingData = data; while (!remainingData.isEmpty()) { QByteArray package = remainingData.left(20); - sentDataLength += package.count(); m_service->writeCharacteristic(characteristic, package); remainingData = remainingData.remove(0, package.count()); } @@ -296,7 +301,33 @@ void WirelessService::commandConnect(const QVariantMap &request) return; } - NetworkManager::NetworkManagerError networkError = m_networkManager->connectWifi(m_device->interface(), parameters.value("e").toString(), parameters.value("p").toString()); + NetworkManager::AuthAlgorithm authAlgorithm = NetworkManager::AuthAlgorithmOpen; + if (parameters.contains("a")) { + QString alg = parameters.value("a").toString(); + if (alg == "open") { + authAlgorithm = NetworkManager::AuthAlgorithmOpen; + } else { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Connect command: Invalid authentication algorithm parameter."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidParameters)); + return; + } + } + + NetworkManager::KeyManagement keyMgmt = NetworkManager::KeyManagementWpaPsk; + if (parameters.contains("k")) { + QString k = parameters.value("k").toString(); + if (k == "wpa-psk") { + keyMgmt = NetworkManager::KeyManagementWpaPsk; + } else { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Connect command: Invalid key management parameter."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidParameters)); + return; + } + } + + bool hidden = parameters.contains("h") && parameters.value("h").toBool(); + + NetworkManager::NetworkManagerError networkError = m_networkManager->connectWifi(m_device->interface(), parameters.value("e").toString(), parameters.value("p").toString(), authAlgorithm, keyMgmt, hidden); WirelessService::WirelessServiceResponse responseCode = WirelessService::WirelessServiceResponseSuccess; switch (networkError) { case NetworkManager::NetworkManagerErrorNoError: @@ -314,14 +345,6 @@ void WirelessService::commandConnect(const QVariantMap &request) streamData(createResponse(WirelessServiceCommandConnect, responseCode)); } -void WirelessService::commandConnectHidden(const QVariantMap &request) -{ - Q_UNUSED(request) - - // TODO: - qCWarning(dcNetworkManagerBluetoothServer()) << "Connect to hidden network is not implemented yet."; -} - void WirelessService::commandDisconnect(const QVariantMap &request) { Q_UNUSED(request) @@ -587,9 +610,6 @@ void WirelessService::processCommand(const QVariantMap &request) case WirelessServiceCommandConnect: commandConnect(request); break; - case WirelessServiceCommandConnectHidden: - commandConnectHidden(request); - break; case WirelessServiceCommandDisconnect: commandDisconnect(request); break; diff --git a/libnymea-networkmanager/bluetooth/wirelessservice.h b/libnymea-networkmanager/bluetooth/wirelessservice.h index f879034..8c704a8 100644 --- a/libnymea-networkmanager/bluetooth/wirelessservice.h +++ b/libnymea-networkmanager/bluetooth/wirelessservice.h @@ -49,7 +49,6 @@ public: WirelessServiceCommandInvalid = -1, WirelessServiceCommandGetNetworks = 0x00, WirelessServiceCommandConnect = 0x01, - WirelessServiceCommandConnectHidden = 0x02, WirelessServiceCommandDisconnect = 0x03, WirelessServiceCommandScan = 0x04, WirelessServiceCommandGetCurrentConnection = 0x05, @@ -95,7 +94,6 @@ private: // Methods void commandGetNetworks(const QVariantMap &request); void commandConnect(const QVariantMap &request); - void commandConnectHidden(const QVariantMap &request); void commandDisconnect(const QVariantMap &request); void commandScan(const QVariantMap &request); void commandGetCurrentConnection(const QVariantMap &request); diff --git a/libnymea-networkmanager/networkmanager.cpp b/libnymea-networkmanager/networkmanager.cpp index 65434f5..c51912b 100644 --- a/libnymea-networkmanager/networkmanager.cpp +++ b/libnymea-networkmanager/networkmanager.cpp @@ -133,7 +133,7 @@ NetworkManager::NetworkManagerConnectivityState NetworkManager::connectivityStat } /*! Connect the given \a interface to a wifi network with the given \a ssid and \a password. Returns the \l{NetworkManagerError} to inform about the result. \sa NetworkManagerError, */ -NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &interface, const QString &ssid, const QString &password, bool hidden) +NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &interface, const QString &ssid, const QString &password, AuthAlgorithm authAlgorithm, KeyManagement keyManagement, bool hidden) { // Check interface if (!getNetworkDevice(interface)) @@ -150,14 +150,20 @@ NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &i if (!wirelessNetworkDevice) return NetworkManagerErrorInvalidNetworkDeviceType; - // Get the access point object path - WirelessAccessPoint *accessPoint = wirelessNetworkDevice->getAccessPoint(ssid); - if (!accessPoint) - return NetworkManagerErrorAccessPointNotFound; + if (!hidden) { + // Get the access point object path + WirelessAccessPoint *accessPoint = wirelessNetworkDevice->getAccessPoint(ssid); + if (!accessPoint) { + return NetworkManagerErrorAccessPointNotFound; + } + + qCDebug(dcNetworkManager()) << "Connecting to" << accessPoint; + } else { + qCDebug(dcNetworkManager()) << "Connecting to hidden WiFi:" << ssid; + } // Note: https://developer.gnome.org/NetworkManager/stable/ref-settings.html - qCDebug(dcNetworkManager()) << "Start connecting to" << accessPoint << "hidden:" << hidden; // Create network settings for this wifi QVariantMap connectionSettings; @@ -175,11 +181,23 @@ NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &i // Note: disable power save mode wirelessSettings.insert("powersave", 2); - if (hidden) wirelessSettings.insert("hidden", true); + if (hidden) { + wirelessSettings.insert("hidden", true); + } QVariantMap wirelessSecuritySettings; - wirelessSecuritySettings.insert("auth-alg", "open"); - wirelessSecuritySettings.insert("key-mgmt", "wpa-psk"); + switch (authAlgorithm) { + case AuthAlgorithmOpen: + wirelessSecuritySettings.insert("auth-alg", "open"); + break; + } + + switch (keyManagement) { + case KeyManagementWpaPsk: + wirelessSecuritySettings.insert("key-mgmt", "wpa-psk"); + break; + } + wirelessSecuritySettings.insert("psk", password); QVariantMap ipv4Settings; @@ -195,8 +213,9 @@ NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &i settings.insert("ipv4", ipv4Settings); settings.insert("ipv6", ipv6Settings); - if (accessPoint->isProtected()) + if (!password.isEmpty()) { settings.insert("802-11-wireless-security", wirelessSecuritySettings); + } // Remove old configuration (if there is any) foreach (NetworkConnection *connection, m_networkSettings->connections()) { @@ -211,7 +230,7 @@ NetworkManager::NetworkManagerError NetworkManager::connectWifi(const QString &i return NetworkManagerErrorWirelessConnectionFailed; // Activate connection - QDBusMessage query = m_networkManagerInterface->call("ActivateConnection", QVariant::fromValue(connectionObjectPath), QVariant::fromValue(wirelessNetworkDevice->objectPath()), QVariant::fromValue(accessPoint->objectPath())); + QDBusMessage query = m_networkManagerInterface->call("ActivateConnection", QVariant::fromValue(connectionObjectPath), QVariant::fromValue(wirelessNetworkDevice->objectPath()), QVariant::fromValue(QDBusObjectPath("/"))); if (query.type() != QDBusMessage::ReplyMessage) { qCWarning(dcNetworkManager()) << query.errorName() << query.errorMessage(); return NetworkManagerErrorWirelessConnectionFailed; diff --git a/libnymea-networkmanager/networkmanager.h b/libnymea-networkmanager/networkmanager.h index 2a469c7..a79f283 100644 --- a/libnymea-networkmanager/networkmanager.h +++ b/libnymea-networkmanager/networkmanager.h @@ -89,6 +89,16 @@ public: }; Q_ENUM(NetworkManagerError) + enum AuthAlgorithm { + AuthAlgorithmOpen + }; + Q_ENUM(AuthAlgorithm) + + enum KeyManagement { + KeyManagementWpaPsk + }; + Q_ENUM(KeyManagement) + explicit NetworkManager(QObject *parent = nullptr); ~NetworkManager(); @@ -108,7 +118,7 @@ public: QString stateString() const; NetworkManagerConnectivityState connectivityState() const; - NetworkManagerError connectWifi(const QString &interface, const QString &ssid, const QString &password, bool hidden = false); + NetworkManagerError connectWifi(const QString &interface, const QString &ssid, const QString &password, AuthAlgorithm authAlgorithm = AuthAlgorithmOpen, KeyManagement keyManagement = KeyManagementWpaPsk, bool hidden = false); NetworkManagerError startAccessPoint(const QString &interface, const QString &ssid, const QString &password); // Networking