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.
add-support-for-hidden-wifis
Michael Zanetti 2022-09-01 13:04:05 +02:00
parent beeb5a4a02
commit 6ec85236b2
5 changed files with 76 additions and 28 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;
if (!hidden) {
// Get the access point object path
WirelessAccessPoint *accessPoint = wirelessNetworkDevice->getAccessPoint(ssid);
if (!accessPoint)
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;
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;

View File

@ -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