diff options
Diffstat (limited to 'src/wifi')
-rw-r--r-- | src/wifi/qwificonfiguration.cpp | 24 | ||||
-rw-r--r-- | src/wifi/qwificonfiguration.h | 3 | ||||
-rw-r--r-- | src/wifi/qwificontroller.cpp | 68 | ||||
-rw-r--r-- | src/wifi/qwificontroller_p.h | 16 | ||||
-rw-r--r-- | src/wifi/qwifielinux.cpp | 89 | ||||
-rw-r--r-- | src/wifi/qwifimanager.cpp | 114 | ||||
-rw-r--r-- | src/wifi/qwifimanager_p.h | 9 | ||||
-rw-r--r-- | src/wifi/qwifinetworklistmodel.cpp | 19 | ||||
-rw-r--r-- | src/wifi/qwifiutils.cpp | 135 | ||||
-rw-r--r-- | src/wifi/qwifiutils_p.h | 37 | ||||
-rw-r--r-- | src/wifi/wifi.pro | 6 |
11 files changed, 361 insertions, 159 deletions
diff --git a/src/wifi/qwificonfiguration.cpp b/src/wifi/qwificonfiguration.cpp index 42196a2..b532620 100644 --- a/src/wifi/qwificonfiguration.cpp +++ b/src/wifi/qwificonfiguration.cpp @@ -31,10 +31,12 @@ public: QString m_ssid; QString m_psk; QString m_protocol; + bool m_ssidHidden; }; QWifiConfigurationPrivate::QWifiConfigurationPrivate(QWifiConfiguration *config) : q_ptr(config) + , m_ssidHidden(false) { } @@ -119,4 +121,26 @@ void QWifiConfiguration::setProtocol(const QString &protocol) d->m_protocol = protocol; } +/*! + \property QWifiConfiguration::ssidHidden + \brief Holds whether a Wifi access point broadcasts its SSID + + If a Wifi access point does not broadcast its SSID, setting this + property to \c true ensures that the Wifi backend can detect the + specified network. + + By default this property is set to \c false. +*/ +bool QWifiConfiguration::isSsidHidden() const +{ + Q_D(const QWifiConfiguration); + return d->m_ssidHidden; +} + +void QWifiConfiguration::setSsidHidden(bool hidden) +{ + Q_D(QWifiConfiguration); + d->m_ssidHidden = hidden; +} + QT_END_NAMESPACE diff --git a/src/wifi/qwificonfiguration.h b/src/wifi/qwificonfiguration.h index 9b03c9e..cdeb453 100644 --- a/src/wifi/qwificonfiguration.h +++ b/src/wifi/qwificonfiguration.h @@ -32,6 +32,7 @@ class Q_DECL_EXPORT QWifiConfiguration : public QObject Q_PROPERTY(QString ssid READ ssid WRITE setSsid) Q_PROPERTY(QString passphrase READ passphrase WRITE setPassphrase) Q_PROPERTY(QString protocol READ protocol WRITE setProtocol) + Q_PROPERTY(bool ssidHidden READ isSsidHidden WRITE setSsidHidden) public: explicit QWifiConfiguration(QObject *parent = 0); virtual ~QWifiConfiguration(); @@ -42,6 +43,8 @@ public: QString passphrase() const; void setProtocol(const QString &protocol); QString protocol() const; + void setSsidHidden(bool hidden); + bool isSsidHidden() const; private: Q_DISABLE_COPY(QWifiConfiguration) diff --git a/src/wifi/qwificontroller.cpp b/src/wifi/qwificontroller.cpp index ea49764..7b8be80 100644 --- a/src/wifi/qwificontroller.cpp +++ b/src/wifi/qwificontroller.cpp @@ -33,7 +33,7 @@ #ifdef Q_OS_ANDROID_NO_SDK /* - * Work API differences between Android versions + * Workaround API differences between Android versions */ int q_wifi_start_supplicant() { @@ -129,21 +129,6 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(B2QT_WIFI, "qt.b2qt.wifi") -class QWifiManagerEvent : public QEvent -{ -public: - QWifiManagerEvent(QEvent::Type type, const QByteArray &data = QByteArray()) - : QEvent(type) - , m_data(data) - { - } - - QByteArray data() const { return m_data; } - -private: - QByteArray m_data; -}; - class QWifiEventThread : public QThread { public: @@ -155,7 +140,7 @@ public: void run() { qCDebug(B2QT_WIFI) << "running wifi event thread"; - QWifiManagerEvent *event = 0; + QWifiEvent *event = 0; char buffer[2048]; forever { int size = q_wifi_wait_for_event(m_interface, buffer, sizeof(buffer) - 1); @@ -163,21 +148,24 @@ public: buffer[size] = 0; event = 0; qCDebug(B2QT_WIFI) << "[event]: " << buffer; + if (m_controller->isWifiThreadExitRequested()) { qCDebug(B2QT_WIFI) << "exit wifi event thread"; return; } + if (strstr(buffer, "SCAN-RESULTS")) { - event = new QWifiManagerEvent(WIFI_SCAN_RESULTS); + event = new QWifiEvent(WIFI_SCAN_RESULTS); } else if (strstr(buffer, "CTRL-EVENT-CONNECTED")) { - event = new QWifiManagerEvent(WIFI_CONNECTED); + event = new QWifiEvent(WIFI_CONNECTED); } else if (strstr(buffer, "CTRL-EVENT-DISCONNECTED")) { - event = new QWifiManagerEvent(WIFI_DISCONNECTED); + event = new QWifiEvent(WIFI_DISCONNECTED); } else if (strstr(buffer, "Trying to associate")) { - event = new QWifiManagerEvent(WIFI_AUTHENTICATING); + event = new QWifiEvent(WIFI_AUTHENTICATING, QLatin1String(buffer)); } else if (strstr(buffer, "Handshake failed")) { - event = new QWifiManagerEvent(WIFI_HANDSHAKE_FAILED); + event = new QWifiEvent(WIFI_HANDSHAKE_FAILED); } + if (event) QCoreApplication::postEvent(m_controller->wifiManager(), event); } @@ -272,12 +260,12 @@ void QWifiController::initializeBackend() { qCDebug(B2QT_WIFI) << "initializing wifi backend"; emit backendStateChanged(QWifiManager::Initializing); - + bool initFailed = false; #ifdef Q_OS_ANDROID_NO_SDK qCDebug(B2QT_WIFI) << "initialize driver"; if (!(is_wifi_driver_loaded() || wifi_load_driver() == 0)) { qCWarning(B2QT_WIFI) << "failed to load a driver"; - return; + initFailed = true; } #else qCDebug(B2QT_WIFI) << "run ifconfig (up)"; @@ -286,39 +274,42 @@ void QWifiController::initializeBackend() ifconfig.waitForFinished(); if (ifconfig.exitStatus() != QProcess::NormalExit && ifconfig.exitCode() != 0) { qCWarning(B2QT_WIFI) << "failed to bring up wifi interface!"; - return; + initFailed = true; } #endif - resetSupplicantSocket(); - startWifiEventThread(); - qCDebug(B2QT_WIFI) << "wifi backend started successfully"; - emit backendStateChanged(QWifiManager::Running); + if (!initFailed && resetSupplicantSocket()) { + qCDebug(B2QT_WIFI) << "wifi backend started successfully"; + emit backendStateChanged(QWifiManager::Running); + } else { + emit backendStateChanged(QWifiManager::NotRunning); + } } -void QWifiController::resetSupplicantSocket() const +bool QWifiController::resetSupplicantSocket() { qCDebug(B2QT_WIFI) << "reset supplicant socket"; - // close down the previous connection to supplicant if - // one exists before re-connecting. + exitWifiEventThread(); if (q_wifi_stop_supplicant() < 0) qCWarning(B2QT_WIFI) << "failed to stop supplicant!"; q_wifi_close_supplicant_connection(m_interface); qCDebug(B2QT_WIFI) << "start supplicant"; if (q_wifi_start_supplicant() != 0) { qCWarning(B2QT_WIFI) << "failed to start a supplicant!"; - return; + return false; } #ifdef Q_OS_ANDROID_NO_SDK if (wait_for_property("init.svc.wpa_supplicant", "running", 5) < 0) { qCWarning(B2QT_WIFI) << "timed out waiting for supplicant to start!"; - return; + return false; } #endif qCDebug(B2QT_WIFI) << "connect to supplicant"; if (q_wifi_connect_to_supplicant(m_interface) != 0) { qCWarning(B2QT_WIFI) << "failed to connect to a supplicant!"; - return; + return false; } + startWifiEventThread(); + return true; } void QWifiController::terminateBackend() @@ -334,10 +325,8 @@ void QWifiController::terminateBackend() QProcess ifconfig; ifconfig.start(QStringLiteral("ifconfig"), QStringList() << QLatin1String(m_interface) << QStringLiteral("down")); ifconfig.waitForFinished(); - if (ifconfig.exitStatus() != QProcess::NormalExit && ifconfig.exitCode() != 0) { + if (ifconfig.exitStatus() != QProcess::NormalExit && ifconfig.exitCode() != 0) qCWarning(B2QT_WIFI) << "failed to bring down wifi interface!"; - return; - } #endif stopDhcp(); qCDebug(B2QT_WIFI) << "wifi backend stopped successfully"; @@ -355,7 +344,8 @@ void QWifiController::exitWifiEventThread() if (m_eventThread->isRunning()) { m_exitEventThread = true; m_managerPrivate->call(QStringLiteral("SCAN")); - m_eventThread->wait(); + if (!m_eventThread->wait(8000)) + qCWarning(B2QT_WIFI, "timed out waiting for wifi event thread to exit!"); } } diff --git a/src/wifi/qwificontroller_p.h b/src/wifi/qwificontroller_p.h index 230b7c8..185cff9 100644 --- a/src/wifi/qwificontroller_p.h +++ b/src/wifi/qwificontroller_p.h @@ -62,6 +62,20 @@ class QWifiEventThread; class QLocalSocket; #endif +class QWifiEvent : public QEvent +{ +public: + QWifiEvent(QEvent::Type type, const QString &data = QString()) + : QEvent(type) + , m_data(data) + { + } + QString data() const { return m_data; } + +private: + QString m_data; +}; + class QWifiController : public QThread { Q_OBJECT @@ -83,7 +97,7 @@ public: void startWifiEventThread(); void acquireIPAddress(); void stopDhcp() const; - void resetSupplicantSocket() const; + bool resetSupplicantSocket(); signals: void backendStateChanged(QWifiManager::BackendState backendState); diff --git a/src/wifi/qwifielinux.cpp b/src/wifi/qwifielinux.cpp index 0dc3a39..e7dabb3 100644 --- a/src/wifi/qwifielinux.cpp +++ b/src/wifi/qwifielinux.cpp @@ -38,7 +38,6 @@ static struct wpa_ctrl *ctrl_conn; static struct wpa_ctrl *monitor_conn; // socket pair used to exit from a blocking read static int exit_sockets[2]; -QByteArray ctrlInterface; int wifi_connect_on_socket_path(const char *path); int wifi_ctrl_recv(char *reply, size_t *reply_len); @@ -46,12 +45,33 @@ int wifi_wait_on_socket(char *buf, size_t buflen); int wifi_send_command(const char *cmd, char *reply, size_t *reply_len); void wifi_close_sockets(); +QByteArray controlInterfacePath() +{ + QByteArray path; + QFile configFile; + configFile.setFileName(QLatin1String(SUPP_CONFIG_FILE)); + if (configFile.open(QFile::ReadOnly)) { + while (!configFile.atEnd()) { + QByteArray line = configFile.readLine().trimmed(); + if (line.startsWith("ctrl_interface")) { + path = line.mid(16); + if (path.isEmpty()) + qCWarning(B2QT_WIFI) << "ctrl_interface is not set in " << SUPP_CONFIG_FILE; + break; + } + } + configFile.close(); + } else { + qCWarning(B2QT_WIFI) << "could not find/read wpa_supplicant configuration file in" << SUPP_CONFIG_FILE; + } + return path; +} + int q_wifi_start_supplicant() { - // #### TODO - if "/etc/wpa_supplicant/driver.$IFACE" exists, read driver name from there QByteArray ifc = QWifiDevice::wifiInterfaceName(); - QString driver(QStringLiteral("wext")); QString pidFile = QLatin1String("/var/run/wpa_supplicant." + ifc + ".pid"); + QString driver(QStringLiteral("nl80211,wext")); QStringList arg; arg << QStringLiteral("--start") << QStringLiteral("--quiet") << QStringLiteral("--name"); @@ -64,33 +84,14 @@ int q_wifi_start_supplicant() QProcess ssDaemon; ssDaemon.start(QStringLiteral("start-stop-daemon"), arg); ssDaemon.waitForFinished(); - if (ssDaemon.exitStatus() != QProcess::NormalExit && ssDaemon.exitCode() != 0) { - qCWarning(B2QT_WIFI) << "failed to start a supplicant process!"; + + QByteArray path = controlInterfacePath(); + if (path.isEmpty()) return -1; - } - QFile configFile; - configFile.setFileName(QLatin1String(SUPP_CONFIG_FILE)); - if (configFile.exists() && configFile.open(QFile::ReadOnly)) { - ctrlInterface.clear(); - while (!configFile.atEnd()) { - QByteArray line = configFile.readLine().trimmed(); - if (line.startsWith("ctrl_interface")) { - ctrlInterface = line.mid(16); - break; - } - } - configFile.close(); - if (!ctrlInterface.isEmpty()) { - // if the interface socket exists, then wpa_supplicant was invoked successfully - if (!QFile(QLatin1String(ctrlInterface + "/" + ifc)).exists()) - return -1; - } else { - qCWarning(B2QT_WIFI) << "ctrl_interface is not set in " << SUPP_CONFIG_FILE; - return -1; - } - } else { - qCWarning(B2QT_WIFI) << "could not find/read wpa_supplicant configuration file in" << SUPP_CONFIG_FILE; + // if the interface socket exists then wpa-supplicant was invoked successfully + if (!QFile(QLatin1String(path + "/" + ifc)).exists()) { + qCWarning(B2QT_WIFI) << "failed to invoke wpa_supplicant!\n" << ssDaemon.readAll(); return -1; } // reset sockets used for exiting from hung state @@ -102,19 +103,29 @@ int q_wifi_stop_supplicant() { QByteArray ifc = QWifiDevice::wifiInterfaceName(); QString pidFile = QLatin1String("/var/run/wpa_supplicant." + ifc + ".pid"); - QStringList arg; - arg << QStringLiteral("--stop") << QStringLiteral("--quiet") << QStringLiteral("--name"); - arg << QStringLiteral("wpa_supplicant") << QStringLiteral("--pidfile") << pidFile; - QProcess ssDaemon; - ssDaemon.start(QStringLiteral("start-stop-daemon"), arg); - ssDaemon.waitForFinished(); - if (ssDaemon.exitStatus() != QProcess::NormalExit && ssDaemon.exitCode() != 0) { - qCWarning(B2QT_WIFI) << "failed to stop a supplicant process!"; - return -1; + + if (QFile(pidFile).exists()) { + QStringList arg; + arg << QStringLiteral("--stop") << QStringLiteral("--quiet") << QStringLiteral("--name"); + arg << QStringLiteral("wpa_supplicant") << QStringLiteral("--pidfile") << pidFile; + + QProcess ssDaemon; + ssDaemon.start(QStringLiteral("start-stop-daemon"), arg); + ssDaemon.waitForFinished(); + if (ssDaemon.exitStatus() != QProcess::NormalExit) { + qCWarning(B2QT_WIFI) << "failed to stop a supplicant process!\n" << ssDaemon.readAll();; + return -1; + } + + QFile::remove(pidFile); } - QFile::remove(QLatin1String(ctrlInterface + "/" + ifc)); - QFile::remove(pidFile); + QByteArray path = controlInterfacePath(); + if (path.isEmpty()) + return -1; + + QFile::remove(QLatin1String(path + "/" + ifc)); + return 0; } diff --git a/src/wifi/qwifimanager.cpp b/src/wifi/qwifimanager.cpp index e971fd1..2a5cfff 100644 --- a/src/wifi/qwifimanager.cpp +++ b/src/wifi/qwifimanager.cpp @@ -20,6 +20,8 @@ #include "qwifinetworklistmodel_p.h" #include "qwifinetwork_p.h" #include "qwifimanager_p.h" +#include "qwifiutils_p.h" + #include "qwifidevice.h" #include <QtCore/QFile> @@ -40,7 +42,6 @@ QWifiManagerPrivate::QWifiManagerPrivate(QWifiManager *manager) , m_interface(QWifiDevice::wifiInterfaceName()) , m_backendState(QWifiManager::NotRunning) , m_networkState(QWifiManager::Disconnected) - , m_setCurrentSSID(true) { qCDebug(B2QT_WIFI) << "using wifi interface: " << m_interface; } @@ -51,54 +52,29 @@ QWifiManagerPrivate::~QWifiManagerPrivate() delete m_networkListModel; } -QString QWifiManagerPrivate::getConnectedNetwork() -{ - QStringList lists = call(QStringLiteral("LIST_NETWORKS")).split('\n'); - QString connectedNetwork; - for (int i = 1; i < lists.size(); ++i) { - if (lists.at(i).toUpper().contains(QStringLiteral("[CURRENT]"))) { - connectedNetwork = lists.at(i); - break; - } - } - return connectedNetwork; -} - -void QWifiManagerPrivate::emitCurrentSSIDChanged() +void QWifiManagerPrivate::setCurrentSSID(const QString &ssid) { Q_Q(QWifiManager); - if (m_previousSSID != m_currentSSID) { - qCDebug(B2QT_WIFI) << "current SSID: " << m_previousSSID << " -> " << m_currentSSID; - m_previousSSID = m_currentSSID; - emit q->currentSSIDChanged(m_currentSSID); - } + qCDebug(B2QT_WIFI) << "current SSID: " << m_currentSSID << " -> " << ssid; + if (m_currentSSID == ssid) + return; + + m_currentSSID = ssid; + emit q->currentSSIDChanged(m_currentSSID); } -void QWifiManagerPrivate::setCurrentSSID() +void QWifiManagerPrivate::handleAuthenticating(QWifiEvent *event) { - qCDebug(B2QT_WIFI, "setCurrentSSID"); - m_setCurrentSSID = false; - QString connectedNetwork = getConnectedNetwork(); - if (!connectedNetwork.isEmpty()) { - QString ssid = connectedNetwork.split('\t').at(1); - QWifiNetwork *network = m_networkListModel->networkForSSID(ssid); - if (network) { - m_currentSSID = network->ssid(); - emitCurrentSSIDChanged(); - if (call(QStringLiteral("STATUS")).contains(QStringLiteral("wpa_state=COMPLETED"))) - updateNetworkState(QWifiManager::Connected); - } - } + QString data = event->data().trimmed(); + QString ssid = data.mid(data.indexOf(QLatin1String("SSID")) + 6); + ssid = ssid.left(ssid.lastIndexOf(QLatin1Char('\''))); + + setCurrentSSID(QWifiUtils::decodeHexEncoded(ssid)); + updateNetworkState(QWifiManager::Authenticating); } void QWifiManagerPrivate::handleConnected() { - qCDebug(B2QT_WIFI, "handleConnected"); - QString connectedNetwork = getConnectedNetwork(); - if (connectedNetwork.isEmpty()) - return; - - m_currentSSID = connectedNetwork.split('\t').at(1); qCDebug(B2QT_WIFI) << "connected network: " << m_currentSSID; updateNetworkState(QWifiManager::ObtainingIPAddress); m_wifiController->call(QWifiController::AcquireIPAddress); @@ -147,11 +123,8 @@ void QWifiManagerPrivate::updateWifiState() if (ps.readAll().contains("wpa_supplicant")) supplicantRunning = true; #endif - if (supplicantRunning) { - m_wifiController->resetSupplicantSocket(); - m_wifiController->startWifiEventThread(); + if (supplicantRunning && m_wifiController->resetSupplicantSocket()) m_backendState = QWifiManager::Running; - } } QString QWifiManagerPrivate::call(const QString &command) @@ -168,20 +141,21 @@ QString QWifiManagerPrivate::call(const QString &command) actualCommand.prepend(prefix); #endif #endif - if (q_wifi_command(m_interface, actualCommand.toLatin1(), data, &len) < 0) { - qCDebug(B2QT_WIFI) << "call to supplicant failed: " << actualCommand; + qCDebug(B2QT_WIFI) << "call command: " << actualCommand.toLocal8Bit(); + if (q_wifi_command(m_interface, actualCommand.toLocal8Bit(), data, &len) < 0) { + qCDebug(B2QT_WIFI) << "call to supplicant failed!"; return QString(); } if (len < sizeof(data)) data[len] = 0; QString result = QLatin1String(data); - return result; + return result.trimmed(); } bool QWifiManagerPrivate::checkedCall(const QString &command) { - return call(command).trimmed().toUpper() == QLatin1String("OK"); + return call(command).toUpper() == QLatin1String("OK"); } void QWifiManagerPrivate::updateLastError(const QString &error) @@ -238,11 +212,11 @@ void QWifiManagerPrivate::updateLastError(const QString &error) \value SSID informal (human) name of a Wifi network (QString) \value BSSID basic service set identification of a network, used to uniquely identify BSS (QString) - \value SignalStrength strength of a Wifi signal, measured in dBm (int) - \value WPASupported holds whether network access point supports WPA security protocol (QString) - \value WPA2Supported holds whether network access point supports WPA2 security protocol (QString) - \value WEPSupported holds whether network access point supports WEP security protocol (QString) - \value WPSSupported holds whether network access point supports WPS security protocol (QString) + \value SignalStrength strength of a Wifi signal represented as percentage (0-100) (int) + \value WPASupported holds whether network access point supports WPA security protocol (bool) + \value WPA2Supported holds whether network access point supports WPA2 security protocol (bool) + \value WEPSupported holds whether network access point supports WEP security protocol (bool) + \value WPSSupported holds whether network access point supports WPS security protocol (bool) */ QWifiManager* QWifiManager::m_instance = 0; @@ -424,8 +398,6 @@ bool QWifiManager::event(QEvent *event) switch ((int) event->type()) { case WIFI_SCAN_RESULTS: d->m_networkListModel->parseScanResults(d->call(QStringLiteral("SCAN_RESULTS"))); - if (d->m_setCurrentSSID || d->m_currentSSID.isEmpty()) - d->setCurrentSSID(); return true; case WIFI_CONNECTED: d->handleConnected(); @@ -434,11 +406,10 @@ bool QWifiManager::event(QEvent *event) d->handleDisconneced(); return true; case WIFI_AUTHENTICATING: - d->updateNetworkState(Authenticating); - d->emitCurrentSSIDChanged(); + d->handleAuthenticating(static_cast<QWifiEvent *>(event)); return true; case WIFI_HANDSHAKE_FAILED: - d->updateNetworkState(HandshakeFailed); + d->updateNetworkState(QWifiManager::HandshakeFailed); return true; case QEvent::Timer: { int tid = static_cast<QTimerEvent *>(event)->timerId(); @@ -469,15 +440,16 @@ bool QWifiManager::connect(QWifiConfiguration *config) } d->call(QStringLiteral("DISABLE_NETWORK all")); + d->setCurrentSSID(config->ssid()); - d->m_currentSSID = config->ssid(); bool networkKnown = false; QString id; - QString listResult = d->call(QStringLiteral("LIST_NETWORKS")); - QStringList lines = listResult.split('\n'); - foreach (const QString &line, lines) { - if (line.contains(d->m_currentSSID)) { - id = line.split('\t').at(0); + const QStringList configuredNetworks = d->call(QStringLiteral("LIST_NETWORKS")).split('\n'); + for (int i = 1; i < configuredNetworks.length(); ++i) { + const QStringList networkFields = configuredNetworks.at(i).split('\t'); + const QString ssid = QWifiUtils::decodeHexEncoded(networkFields.at(1)); + if (ssid == d->m_currentSSID) { + id = networkFields.at(0); networkKnown = true; break; } @@ -485,7 +457,7 @@ bool QWifiManager::connect(QWifiConfiguration *config) if (!networkKnown) { bool ok; - id = d->call(QStringLiteral("ADD_NETWORK")).trimmed(); + id = d->call(QStringLiteral("ADD_NETWORK")); id.toInt(&ok); if (!ok) { d->updateLastError(QStringLiteral("failed to add network!")); @@ -503,7 +475,11 @@ bool QWifiManager::connect(QWifiConfiguration *config) QString key_mgmt; QString protocol = config->protocol().toUpper(); QString psk = config->passphrase(); + + // --------------------- configure network ------------------------------ // ref: http://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf + // ref: https://www.freebsd.org/cgi/man.cgi?wpa_supplicant.conf + // ---------------------------------------------------------------------- if (protocol.isEmpty() || protocol.contains(QStringLiteral("WPA"))) { // ### todo - password length has limits (see IEEE 802.11), we need to check // for those limits here. Supplicant gives only a meaningless "fail" message. @@ -517,6 +493,10 @@ bool QWifiManager::connect(QWifiConfiguration *config) // open network key_mgmt = QLatin1String("NONE"); } + + if (config->isSsidHidden()) + ok = ok && d->checkedCall(setNetworkCommand + QLatin1String(" scan_ssid 1")); + ok = ok && d->checkedCall(setNetworkCommand + QLatin1String(" key_mgmt ") + key_mgmt); if (!ok) { if (!networkKnown) @@ -547,9 +527,6 @@ void QWifiManager::handleBackendStateChanged(BackendState backendState) { Q_D(QWifiManager); switch (backendState) { - case Running: - d->m_setCurrentSSID = true; - break; case NotRunning: d->updateNetworkState(Disconnected); break; @@ -564,7 +541,6 @@ void QWifiManager::handleDhcpRequestFinished(const QString &status) Q_D(QWifiManager); qCDebug(B2QT_WIFI) << "handleDhcpRequestFinished: " << status << " for " << d->m_currentSSID; if (status == QLatin1String("success")) { - d->emitCurrentSSIDChanged(); d->updateNetworkState(Connected); d->call(QStringLiteral("SAVE_CONFIG")); } else { diff --git a/src/wifi/qwifimanager_p.h b/src/wifi/qwifimanager_p.h index ef8a0da..6142c83 100644 --- a/src/wifi/qwifimanager_p.h +++ b/src/wifi/qwifimanager_p.h @@ -25,6 +25,8 @@ QT_BEGIN_NAMESPACE +class QWifiEvent; + class QWifiManagerPrivate { Q_DECLARE_PUBLIC(QWifiManager) @@ -33,11 +35,10 @@ public: virtual ~QWifiManagerPrivate(); // methods - QString getConnectedNetwork(); - void setCurrentSSID(); - void emitCurrentSSIDChanged(); + void setCurrentSSID(const QString &ssid); void handleConnected(); void handleDisconneced(); + void handleAuthenticating(QWifiEvent *event); void updateNetworkState(QWifiManager::NetworkState networkState); void updateBackendState(QWifiManager::BackendState backendState); @@ -57,9 +58,7 @@ public: QByteArray m_interface; QWifiManager::BackendState m_backendState; QWifiManager::NetworkState m_networkState; - bool m_setCurrentSSID; QString m_currentSSID; - QString m_previousSSID; QString m_lastError; }; diff --git a/src/wifi/qwifinetworklistmodel.cpp b/src/wifi/qwifinetworklistmodel.cpp index 6f53295..9d6202f 100644 --- a/src/wifi/qwifinetworklistmodel.cpp +++ b/src/wifi/qwifinetworklistmodel.cpp @@ -18,6 +18,7 @@ ****************************************************************************/ #include "qwifinetworklistmodel_p.h" #include "qwifinetwork_p.h" +#include "qwifiutils_p.h" #include "qwifimanager.h" @@ -123,14 +124,24 @@ void QWifiNetworkListModel::parseScanResults(const QString &results) continue; int pos = 0; - QString ssid = info.at(4); + QString ssid = QWifiUtils::decodeHexEncoded(info.at(4)); + if (ssid.isEmpty()) + continue; + sensibleNetworks.insert(ssid); QWifiNetwork *knownNetwork = networkForSSID(ssid, &pos); if (!knownNetwork) knownNetwork = outOfRangeListContains(ssid); - // signal strength is in dBm. Deprecated, but still widely used "wext" - // wifi driver reports positive values for signal strength, we workaround that. - int signalStrength = qAbs(info.at(2).trimmed().toInt()) * -1; + + int signalStrength = info.at(2).trimmed().toInt(); + if (signalStrength < 0) { + // signal is reported in dBm, rough conversion: best = -40, worst = -100 + int val = qAbs(qMax(-100, qMin(signalStrength, -40)) + 40); // clamp and normalize to 0 + signalStrength = 100 - (int) ((100.0 * (double) val) / 60.0); + } else if (signalStrength > 100) { + qCWarning(B2QT_WIFI) << "unexpected value for a signal level: " << signalStrength; + } + if (!knownNetwork) { QWifiNetwork *network = new QWifiNetwork(); network->setOutOfRange(false); diff --git a/src/wifi/qwifiutils.cpp b/src/wifi/qwifiutils.cpp new file mode 100644 index 0000000..21c440b --- /dev/null +++ b/src/wifi/qwifiutils.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc +** All rights reserved. +** For any questions to Digia, please use the contact form at +** http://www.qt.io +** +** This file is part of Qt Enterprise Embedded. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** the contact form at http://www.qt.io +** +****************************************************************************/ +#include "qwifiutils_p.h" + +QT_BEGIN_NAMESPACE + +int QWifiUtils::hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +int QWifiUtils::hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + +// the logic of this function is taken from wpa_supplicant source code (BSD +// licensed code) see http://w1.fi/cgit file hostapd/src/utils/common.c +// For Ascii encoded string, any octet < 32 or > 127 is encoded as a "\x" +// followed by the hex representation of the octet. Exception chars are ", +// \, \e, \n, \r, \t which are escaped by a backslash +QString QWifiUtils::decodeHexEncoded(const QString &encoded) +{ + int maxlen = encoded.size() + 1; + QByteArray buf; + buf.resize(maxlen); + const char *pos = encoded.toLocal8Bit().constData(); + int len = 0; + int val; + + while (*pos) { + if (len + 1 >= maxlen) + break; + switch (*pos) { + case '\\': + pos++; + switch (*pos) { + case '\\': + buf[len++] = '\\'; + pos++; + break; + case '"': + buf[len++] = '"'; + pos++; + break; + case 'n': + buf[len++] = '\n'; + pos++; + break; + case 'r': + buf[len++] = '\r'; + pos++; + break; + case 't': + buf[len++] = '\t'; + pos++; + break; + case 'e': + buf[len++] = '\033'; + pos++; + break; + case 'x': + pos++; + val = hex2byte(pos); + if (val < 0) { + val = hex2num(*pos); + if (val < 0) + break; + buf[len++] = val; + pos++; + } else { + buf[len++] = val; + pos += 2; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + val = *pos++ - '0'; + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + buf[len++] = val; + break; + default: + break; + } + break; + default: + buf[len++] = *pos++; + break; + } + } + if (maxlen > len) + buf[len] = '\0'; + + return QString::fromUtf8(buf); +} + +QT_END_NAMESPACE diff --git a/src/wifi/qwifiutils_p.h b/src/wifi/qwifiutils_p.h new file mode 100644 index 0000000..8b3e54a --- /dev/null +++ b/src/wifi/qwifiutils_p.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc +** All rights reserved. +** For any questions to Digia, please use the contact form at +** http://www.qt.io +** +** This file is part of Qt Enterprise Embedded. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** the contact form at http://www.qt.io +** +****************************************************************************/ +#ifndef QWIFIUTILS_H +#define QWIFIUTILS_H + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +class QWifiUtils +{ +public: + static int hex2num(char c); + static int hex2byte(const char *hex); + + static QString decodeHexEncoded(const QString &encoded); +}; + +QT_END_NAMESPACE + +#endif // QWIFIUTILS_H diff --git a/src/wifi/wifi.pro b/src/wifi/wifi.pro index e558081..f248774 100644 --- a/src/wifi/wifi.pro +++ b/src/wifi/wifi.pro @@ -16,7 +16,8 @@ HEADERS += \ $$PWD/qwifinetworklistmodel_p.h \ $$PWD/qwificontroller_p.h \ $$PWD/qwifidevice.h \ - $$PWD/qwificonfiguration.h + $$PWD/qwificonfiguration.h \ + $$PWD/qwifiutils_p.h SOURCES += \ $$PWD/qwifimanager.cpp \ @@ -24,7 +25,8 @@ SOURCES += \ $$PWD/qwifinetworklistmodel.cpp \ $$PWD/qwificontroller.cpp \ $$PWD/qwifidevice.cpp \ - $$PWD/qwificonfiguration.cpp + $$PWD/qwificonfiguration.cpp \ + $$PWD/qwifiutils.cpp android: { LIBS += -lhardware_legacy -lcutils |