summaryrefslogtreecommitdiffstats
path: root/src/networksettings/wpasupplicant
diff options
context:
space:
mode:
authorTeemu Holappa <teemu.holappa@theqtcompany.com>2016-02-11 11:50:55 +0200
committerTeemu Holappa <teemu.holappa@theqtcompany.com>2016-02-17 11:57:20 +0000
commitf1d884b6dad5a93d7a3077b6b05d3ec7fcd9a6ea (patch)
tree9d48669bdf1e8877b19c3a98cd8bbd8c90df5290 /src/networksettings/wpasupplicant
parentb4088adc7f2666d468a478e379b94c5cb4494c1b (diff)
Refactored Qml plugins into modules.
Separated C++ and Qml interfaces. All the UI's from plugins are moved to the settingsui folder. Change-Id: Id6a6623346b18321357bc42d24121c4d9cdfd098 Reviewed-by: Kimmo Ollila <kimmo.ollila@theqtcompany.com>
Diffstat (limited to 'src/networksettings/wpasupplicant')
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsinterface_p.cpp71
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsinterface_p.h88
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsmanager_p.cpp433
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsmanager_p.h94
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsservice_p.cpp127
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsservice_p.h87
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.cpp57
-rw-r--r--src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.h56
-rw-r--r--src/networksettings/wpasupplicant/qwificontroller.cpp285
-rw-r--r--src/networksettings/wpasupplicant/qwificontroller_p.h116
-rw-r--r--src/networksettings/wpasupplicant/qwifidevice.cpp94
-rw-r--r--src/networksettings/wpasupplicant/qwifidevice.h44
-rw-r--r--src/networksettings/wpasupplicant/qwifisupplicant.cpp443
-rw-r--r--src/networksettings/wpasupplicant/qwifisupplicant_p.h65
14 files changed, 2060 insertions, 0 deletions
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.cpp b/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.cpp
new file mode 100644
index 0000000..7370421
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.cpp
@@ -0,0 +1,71 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qnetworksettingsinterface_p.h"
+#include "qnetworksettingsmanager_p.h"
+#include "qwifidevice.h"
+
+QNetworkSettingsInterfacePrivate::QNetworkSettingsInterfacePrivate(QNetworkSettingsInterface* parent)
+ :QObject(parent)
+ ,q_ptr(parent)
+{
+ m_name = QWifiDevice::wifiInterfaceName();
+ m_type.setType(QNetworkSettingsType::Wifi);
+ m_powered = true; //We don't really know
+}
+
+void QNetworkSettingsInterfacePrivate::setManager(QNetworkSettingsManagerPrivate *manager)
+{
+ m_manager = manager;
+}
+
+void QNetworkSettingsInterfacePrivate::setPowered(const bool power)
+{
+ //Not supported
+ Q_UNUSED(power);
+}
+
+void QNetworkSettingsInterfacePrivate::setState(QNetworkSettingsState::States aState)
+{
+ Q_Q(QNetworkSettingsInterface);
+ m_state.setState(aState);
+ emit q->stateChanged();
+}
+
+void QNetworkSettingsInterfacePrivate::scan()
+{
+ m_manager->call(QStringLiteral("SCAN"));
+}
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.h b/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.h
new file mode 100644
index 0000000..d8964c3
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsinterface_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QNETWORKSETTINGSINTERFACEPRIVATE_H
+#define QNETWORKSETTINGSINTERFACEPRIVATE_H
+
+#include <QObject>
+#include "qnetworksettings.h"
+#include "qnetworksettingsinterface.h"
+#include "qnetworksettingsmanager_p.h"
+
+class QNetworkSettingsInterfacePrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(QNetworkSettingsInterface)
+public:
+ explicit QNetworkSettingsInterfacePrivate(QNetworkSettingsInterface* parent);
+ void initialize(const QString& path, const QVariantMap& properties);
+ void setPowered(const bool power);
+ void setState(QNetworkSettingsState::States aState);
+ void setManager(QNetworkSettingsManagerPrivate *manager);
+ void scan();
+
+signals:
+
+protected:
+ QString m_name;
+ QNetworkSettingsType m_type;
+ QNetworkSettingsState m_state;
+ bool m_powered;
+ QNetworkSettingsManagerPrivate *m_manager; //not owned
+ QNetworkSettingsInterface *q_ptr;
+};
+
+class WpaSupplicantSettingsInterface : public QNetworkSettingsInterface
+{
+ Q_OBJECT
+public:
+ WpaSupplicantSettingsInterface(QNetworkSettingsManagerPrivate* manager)
+ :QNetworkSettingsInterface(manager)
+ {
+ Q_D(QNetworkSettingsInterface);
+ d->setManager(manager);
+ }
+
+ void setState(QNetworkSettingsState::States aState) {
+ Q_D(QNetworkSettingsInterface);
+ d->setState(aState);
+ }
+
+ virtual ~WpaSupplicantSettingsInterface() {
+ }
+};
+
+#endif // QNETWORKSETTINGSINTERFACEPRIVATE_H
+
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.cpp b/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.cpp
new file mode 100644
index 0000000..17a1f2f
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.cpp
@@ -0,0 +1,433 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QProcess>
+#include "qnetworksettingsmanager_p.h"
+#include "qwificontroller_p.h"
+#include "qnetworksettingsinterface_p.h"
+#include "qnetworksettingsservice_p.h"
+#include "qnetworksettingsuseragent.h"
+#include "qwifisupplicant_p.h"
+
+QNetworkSettingsManagerPrivate::QNetworkSettingsManagerPrivate(QNetworkSettingsManager *parent)
+ :QObject(parent)
+ ,q_ptr(parent)
+{
+ m_serviceFilter.setSourceModel(&m_serviceModel);
+ m_wifiController = new QWifiController(this);
+ m_wifiController->asyncCall(QWifiController::InitializeBackend);
+
+ QObject::connect(m_wifiController, &QWifiController::backendStateChanged,
+ this, &QNetworkSettingsManagerPrivate::handleBackendStateChanged);
+ QObject::connect(m_wifiController, &QWifiController::dhcpRequestFinished,
+ this, &QNetworkSettingsManagerPrivate::handleDhcpRequestFinished);
+
+ QObject::connect(m_wifiController, &QWifiController::raiseError, this, &QNetworkSettingsManagerPrivate::updateLastError);
+ m_wifiController->start();
+
+ updateWifiState();
+}
+
+QNetworkSettingsManagerPrivate::~QNetworkSettingsManagerPrivate()
+{
+ m_wifiController->asyncCall(QWifiController::ExitEventLoop);
+ m_wifiController->wait();
+ delete m_wifiController;
+}
+
+bool QNetworkSettingsManagerPrivate::event(QEvent *event)
+{
+ switch ((int) event->type()) {
+ case WIFI_SCAN_RESULTS:
+ parseScanResults(call(QStringLiteral("SCAN_RESULTS")));
+ return true;
+ case WIFI_CONNECTED:
+ handleConnected();
+ return true;
+ case WIFI_DISCONNECTED:
+ handleDisconneced();
+ return true;
+ case WIFI_AUTHENTICATING:
+ handleAuthenticating(static_cast<QWifiEvent *>(event));
+ return true;
+ case WIFI_HANDSHAKE_FAILED:
+ updateNetworkState(QNetworkSettingsState::Failure);
+ return true;
+ }
+ return QObject::event(event);
+}
+
+void QNetworkSettingsManagerPrivate::connectNetwork(const QString& ssid)
+{
+ if (m_backendState != QWifiController::Running) {
+ qCWarning(B2QT_WIFI) << "start wifi backend before calling connect()";
+ return;
+ }
+
+ call(QStringLiteral("DISABLE_NETWORK all"));
+ m_currentSSID = ssid;
+ emit m_agent->showUserCredentialsInput();
+}
+
+void QNetworkSettingsManagerPrivate::userInteractionReady(bool cancel)
+{
+ if (cancel) {
+ m_currentSSID = "";
+ return;
+ }
+ bool networkKnown = false;
+ QString id;
+ const QStringList configuredNetworks = 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 = QWifiSupplicant::decodeSsid(networkFields.at(1));
+ if (ssid == m_currentSSID) {
+ id = networkFields.at(0);
+ networkKnown = true;
+ break;
+ }
+ }
+
+ if (!networkKnown) {
+ bool ok;
+ id = call(QStringLiteral("ADD_NETWORK"));
+ id.toInt(&ok);
+ if (!ok) {
+ updateLastError(QStringLiteral("failed to add network"));
+ return;
+ }
+ }
+
+ bool ok = true;
+ QChar q = QLatin1Char('"');
+ QString setNetworkCommand = QLatin1String("SET_NETWORK ") + id;
+ if (!networkKnown) {
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" ssid ") + q + m_currentSSID + q);
+ }
+
+ QString key_mgmt;
+ WpaSupplicantService *service = networkForSSID(m_currentSSID);
+ if (!service) {
+ return;
+ }
+ QString psk = m_agent->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 (service->wirelessConfig()->supportsSecurity(QNetworkSettingsWireless::WPA) ||
+ service->wirelessConfig()->supportsSecurity(QNetworkSettingsWireless::WPA2)) {
+ // ### TODO - password length has limits (see IEEE 802.11), we need to check
+ // for those limits here. Supplicant gives only a meaningless "fail" message.
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" psk ") + q + psk + q);
+ key_mgmt = QLatin1String("WPA-PSK");
+ } else if (service->wirelessConfig()->supportsSecurity(QNetworkSettingsWireless::WEP)) {
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" wep_key0 ") + q + psk + q);
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" auth_alg OPEN SHARED"));
+ key_mgmt = QLatin1String("NONE");
+ } else if (service->wirelessConfig()->supportsSecurity(QNetworkSettingsWireless::None)) {
+ // open network
+ key_mgmt = QLatin1String("NONE");
+ }
+
+ if (service->wirelessConfig()->hidden())
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" scan_ssid 1"));
+
+ ok = ok && checkedCall(setNetworkCommand + QLatin1String(" key_mgmt ") + key_mgmt);
+ if (!ok) {
+ if (!networkKnown)
+ call(QLatin1String("REMOVE_NETWORK ") + id);
+ updateLastError(QLatin1String("failed to set properties on network: ") + id);
+ return;
+ }
+
+ call(QLatin1String("SELECT_NETWORK ") + id);
+ call(QStringLiteral("RECONNECT"));
+}
+
+void QNetworkSettingsManagerPrivate::disconnectNetwork()
+{
+ call(QStringLiteral("DISCONNECT"));
+ m_wifiController->asyncCall(QWifiController::StopDhcp);
+}
+
+void QNetworkSettingsManagerPrivate::handleBackendStateChanged(QWifiController::BackendState backendState)
+{
+ switch (backendState) {
+ case QWifiController::NotRunning:
+ updateNetworkState(QNetworkSettingsState::Disconnect);
+ break;
+ default:
+ break;
+ }
+ updateBackendState(backendState);
+}
+
+void QNetworkSettingsManagerPrivate::handleDhcpRequestFinished(const QString &status)
+{
+ qCDebug(B2QT_WIFI) << "handleDhcpRequestFinished: " << status << " for " << m_currentSSID;
+ if (status == QLatin1String("success")) {
+ updateNetworkState(QNetworkSettingsState::Online);
+ call(QStringLiteral("SAVE_CONFIG"));
+ } else {
+ updateNetworkState(QNetworkSettingsState::Failure);
+ }
+}
+
+void QNetworkSettingsManagerPrivate::setUserAgent(QNetworkSettingsUserAgent *agent)
+{
+ m_agent = agent;
+ connect(m_agent, &QNetworkSettingsUserAgent::ready, this, &QNetworkSettingsManagerPrivate::userInteractionReady);
+}
+
+void QNetworkSettingsManagerPrivate::setCurrentSSID(const QString &ssid)
+{
+ qCDebug(B2QT_WIFI) << "current SSID: " << m_currentSSID << " -> " << ssid;
+ if (m_currentSSID == ssid)
+ return;
+
+ m_currentSSID = ssid;
+}
+
+void QNetworkSettingsManagerPrivate::handleAuthenticating(QWifiEvent *event)
+{
+ QString data = event->data().trimmed();
+ QString ssid = data.mid(data.indexOf(QLatin1String("SSID")) + 6);
+ ssid = ssid.left(ssid.lastIndexOf(QLatin1Char('\'')));
+
+ setCurrentSSID(QWifiSupplicant::decodeSsid(ssid));
+ updateNetworkState(QNetworkSettingsState::Association);
+}
+
+void QNetworkSettingsManagerPrivate::handleConnected()
+{
+ qCDebug(B2QT_WIFI) << "connected network: " << m_currentSSID;
+ updateNetworkState(QNetworkSettingsState::Ready);
+ m_wifiController->asyncCall(QWifiController::AcquireIPAddress);
+}
+
+void QNetworkSettingsManagerPrivate::handleDisconneced()
+{
+ updateNetworkState(QNetworkSettingsState::Disconnect);
+}
+
+void QNetworkSettingsManagerPrivate::updateNetworkState(QNetworkSettingsState::States networkState)
+{
+ //Update interface
+ if (!m_interfaceModel.getModel().isEmpty()) {
+ WpaSupplicantSettingsInterface* interface = qobject_cast<WpaSupplicantSettingsInterface*>(m_interfaceModel.getModel().first());
+ if (interface && interface->state() != networkState) {
+ interface->setState(networkState);
+ }
+ }
+
+ //Update service state
+ WpaSupplicantService *service = networkForSSID(m_currentSSID);
+ if (service) {
+ service->setState(networkState);
+ }
+}
+
+void QNetworkSettingsManagerPrivate::updateBackendState(QWifiController::BackendState backendState)
+{
+ if (m_backendState == backendState)
+ return;
+
+ m_backendState = backendState;
+
+ if (m_backendState == QWifiController::Running && m_interfaceModel.getModel().isEmpty()) {
+ WpaSupplicantSettingsInterface *interface = new WpaSupplicantSettingsInterface(this);
+ m_interfaceModel.append(interface);
+ } else if (m_backendState == QWifiController::NotRunning && m_interfaceModel.getModel().size() > 0){
+ m_interfaceModel.remove(0);
+ }
+}
+
+void QNetworkSettingsManagerPrivate::updateWifiState()
+{
+ QProcess ps;
+ ps.start(QStringLiteral("ps"));
+ if (!ps.waitForStarted()) {
+ updateLastError(ps.program() + QLatin1String(": ") + ps.errorString());
+ return;
+ }
+
+ ps.waitForFinished();
+ bool supplicantRunning = ps.readAll().contains("wpa_supplicant");
+ if (supplicantRunning && m_wifiController->resetSupplicantSocket())
+ m_backendState = QWifiController::Running;
+}
+
+QString QNetworkSettingsManagerPrivate::call(const QString &command)
+{
+ if (m_backendState != QWifiController::Running)
+ return QString();
+
+ QByteArray reply;
+ bool success = m_wifiController->supplicant()->sendCommand(command, &reply);
+ if (!success) {
+ qCDebug(B2QT_WIFI) << "call to supplicant failed";
+ return QString();
+ }
+
+ return QLatin1String(reply.trimmed());
+}
+
+bool QNetworkSettingsManagerPrivate::checkedCall(const QString &command)
+{
+ return call(command).toUpper() == QLatin1String("OK");
+}
+
+void QNetworkSettingsManagerPrivate::updateLastError(const QString &error)
+{
+ qCWarning(B2QT_WIFI) << error;
+ if (!m_interfaceModel.getModel().isEmpty()) {
+ WpaSupplicantSettingsInterface* interface = qobject_cast<WpaSupplicantSettingsInterface*>(m_interfaceModel.getModel().first());
+ if (interface) {
+ interface->setState(QNetworkSettingsState::Failure);
+ }
+ }
+}
+
+WpaSupplicantService* QNetworkSettingsManagerPrivate::networkForSSID(const QString& ssid)
+{
+ int pos = 0;
+ return networkForSSID(ssid, pos);
+}
+
+WpaSupplicantService* QNetworkSettingsManagerPrivate::networkForSSID(const QString& ssid, int& pos)
+{
+ QList<QNetworkSettingsService*> services = m_serviceModel.getModel();
+ pos = 0;
+ foreach (QNetworkSettingsService *service, services) {
+ if (service->name() == ssid) {
+ return qobject_cast<WpaSupplicantService*>(service);
+ }
+ pos++;
+ }
+ pos = -1;
+ return NULL;
+}
+
+WpaSupplicantService* QNetworkSettingsManagerPrivate::outOfRangeListContains(const QString& ssid)
+{
+ QList<QNetworkSettingsService*> services = m_outOfRangeServiceModel.getModel();
+ foreach (QNetworkSettingsService *service, services) {
+ if (service->name() == ssid) {
+ return qobject_cast<WpaSupplicantService*>(service);
+ }
+ }
+ return NULL;
+}
+
+void QNetworkSettingsManagerPrivate::parseScanResults(const QString &results)
+{
+ QStringList lines = results.split('\n');
+ QSet<QString> sensibleNetworks;
+
+ for (int i = 1; i < lines.size(); ++i) {
+ QStringList info = lines.at(i).split('\t');
+ if (info.size() < 5 || info.at(4).isEmpty() || info.at(0).isEmpty())
+ continue;
+ int pos = 0;
+
+ QString ssid = QWifiSupplicant::decodeSsid(info.at(4));
+ if (ssid.isEmpty())
+ continue;
+
+ sensibleNetworks.insert(ssid);
+ WpaSupplicantService *knownNetwork = networkForSSID(ssid, pos);
+
+ if (!knownNetwork) {
+ knownNetwork = outOfRangeListContains(ssid);
+ m_outOfRangeServiceModel.getModel().removeOne(knownNetwork);
+ }
+
+ 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) {
+ WpaSupplicantService *network = new WpaSupplicantService(this);
+ network->setId(info.at(0));
+ network->setFlags(info.at(3));
+ network->wirelessConfig()->setSignalStrength(signalStrength);
+ network->setName(ssid);
+ m_serviceModel.append(network);
+ } else {
+ if (knownNetwork->wirelessConfig()->outOfRange()) {
+ // known network has come back into a range
+ knownNetwork->wirelessConfig()->setOutOfRange(false);
+ m_serviceModel.append(knownNetwork);
+ pos = m_serviceModel.getModel().size() - 1;
+ }
+ // ssids are the same, compare bssids..
+ if (knownNetwork->id() == info.at(0)) {
+ // same access point, simply update the signal strength
+ knownNetwork->wirelessConfig()->setSignalStrength(signalStrength);
+ knownNetwork->wirelessConfig()->setOutOfRange(false);
+ m_serviceModel.updated(pos);
+ } else if (knownNetwork->wirelessConfig()->signalStrength() < signalStrength) {
+ // replace with a stronger access point within the same network
+ knownNetwork->wirelessConfig()->setOutOfRange(false);
+ knownNetwork->setId(info.at(0));
+ knownNetwork->setFlags(info.at(3));
+ knownNetwork->wirelessConfig()->setSignalStrength(signalStrength);
+ knownNetwork->setName(ssid);
+ m_serviceModel.updated(pos);
+ }
+ }
+ }
+ // remove out-of-range networks from the data model
+ QList<QNetworkSettingsService*> networks;
+ for (int i = 0; i < networks.size();) {
+ if (!sensibleNetworks.contains(networks.at(i)->name())) {
+ WpaSupplicantService *n = qobject_cast<WpaSupplicantService*>(networks.at(i));
+ m_serviceModel.remove(i);
+ if (n) {
+ n->wirelessConfig()->setOutOfRange(true);
+ m_outOfRangeServiceModel.append(n);
+ }
+ } else {
+ ++i;
+ }
+ }
+}
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.h b/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.h
new file mode 100644
index 0000000..fa20fb4
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsmanager_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QNETWORKSETTINGSMANAGERPRIVATE_H
+#define QNETWORKSETTINGSMANAGERPRIVATE_H
+
+#include <QObject>
+#include "qnetworksettings.h"
+#include "qnetworksettingsmanager.h"
+#include "qnetworksettingsinterfacemodel.h"
+#include "qnetworksettingsservicemodel.h"
+#include "qwificontroller_p.h"
+
+class WpaSupplicantService;
+
+class QNetworkSettingsManagerPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(QNetworkSettingsManager)
+public:
+ explicit QNetworkSettingsManagerPrivate(QNetworkSettingsManager *parent);
+ virtual ~QNetworkSettingsManagerPrivate();
+ QNetworkSettingsManager *q_ptr;
+ void setUserAgent(QNetworkSettingsUserAgent *agent);
+ void connectNetwork(const QString& ssid);
+ void disconnectNetwork();
+ QString call(const QString &command);
+ bool checkedCall(const QString &command);
+protected:
+ bool event(QEvent *event);
+
+private slots:
+ void handleBackendStateChanged(QWifiController::BackendState backendState);
+ void handleDhcpRequestFinished(const QString &status);
+ void userInteractionReady(bool cancel);
+ void updateLastError(const QString &error);
+private:
+ void setCurrentSSID(const QString &ssid);
+ void handleConnected();
+ void handleDisconneced();
+ void handleAuthenticating(QWifiEvent *event);
+ void updateNetworkState(QNetworkSettingsState::States networkState);
+ void updateBackendState(QWifiController::BackendState backendState);
+ void updateWifiState();
+ void parseScanResults(const QString &results);
+ WpaSupplicantService* networkForSSID(const QString& ssid);
+ WpaSupplicantService* networkForSSID(const QString& ssid, int& pos);
+ WpaSupplicantService* outOfRangeListContains(const QString& ssid);
+
+ QNetworkSettingsInterfaceModel m_interfaceModel;
+ QNetworkSettingsServiceModel m_serviceModel;
+ QNetworkSettingsServiceModel m_outOfRangeServiceModel;
+ QNetworkSettingsServiceFilter m_serviceFilter;
+ QWifiController *m_wifiController;
+ QNetworkSettingsUserAgent *m_agent; //Not owned
+
+ QWifiController::BackendState m_backendState;
+ QString m_currentSSID;
+};
+
+
+#endif // QNETWORKSETTINGSMANAGERPRIVATE_H
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsservice_p.cpp b/src/networksettings/wpasupplicant/qnetworksettingsservice_p.cpp
new file mode 100644
index 0000000..b5d4545
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsservice_p.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qnetworksettingsservice_p.h"
+#include "qnetworksettingsmanager_p.h"
+
+QNetworkSettingsServicePrivate::QNetworkSettingsServicePrivate(const QString& bssid, QNetworkSettingsService *parent) :
+ QObject(parent)
+ ,q_ptr(parent)
+ ,m_id(bssid)
+{
+ m_type.setType(QNetworkSettingsType::Wifi);
+}
+
+void QNetworkSettingsServicePrivate::setManager(QNetworkSettingsManagerPrivate *manager)
+{
+ m_manager = manager;
+}
+
+void QNetworkSettingsServicePrivate::connectService()
+{
+ m_manager->connectNetwork(m_name);
+}
+
+void QNetworkSettingsServicePrivate::disconnectService()
+{
+ m_manager->disconnectNetwork();
+}
+
+void QNetworkSettingsServicePrivate::setupIpv6Config()
+{
+ //Not supported
+}
+
+void QNetworkSettingsServicePrivate::setupNameserversConfig()
+{
+ //Not supported
+}
+
+void QNetworkSettingsServicePrivate::setupDomainsConfig()
+{
+ //Not supported
+}
+
+void QNetworkSettingsServicePrivate::setupQNetworkSettingsProxy()
+{
+ //Not supported
+}
+
+void QNetworkSettingsServicePrivate::setupIpv4Config()
+{
+ //Not supported
+}
+
+WpaSupplicantService::WpaSupplicantService(QNetworkSettingsManagerPrivate* manager, QObject* parent)
+ :QNetworkSettingsService("", parent)
+{
+ Q_D(QNetworkSettingsService);
+ d->setManager(manager);
+}
+
+void WpaSupplicantService::setId(const QString& aId)
+{
+ Q_D(QNetworkSettingsService);
+ d->m_id = aId;
+}
+
+void WpaSupplicantService::setName(const QString& aName)
+{
+ Q_D(QNetworkSettingsService);
+ d->m_name = aName;
+ emit nameChanged();
+}
+
+void WpaSupplicantService::setFlags(const QString& aFlags)
+{
+ Q_D(QNetworkSettingsService);
+
+ if (aFlags.contains("WPA-")) {
+ d->m_wifiConfig.setSecurity(QNetworkSettingsWireless::WPA);
+ }
+ if (aFlags.contains("WPA2-")) {
+ d->m_wifiConfig.setSecurity(QNetworkSettingsWireless::WPA2);
+ }
+ if (aFlags.contains("WEP-")) {
+ d->m_wifiConfig.setSecurity(QNetworkSettingsWireless::WEP);
+ }
+}
+
+void WpaSupplicantService::setState(QNetworkSettingsState::States aState)
+{
+ Q_D(QNetworkSettingsService);
+ d->m_state.setState(aState);
+ emit stateChanged();
+}
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsservice_p.h b/src/networksettings/wpasupplicant/qnetworksettingsservice_p.h
new file mode 100644
index 0000000..12cc193
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsservice_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QNETWORKSETTINGSSERVICEPRIVATE_H
+#define QNETWORKSETTINGSSERVICEPRIVATE_H
+
+#include <QObject>
+#include "qnetworksettings.h"
+#include "qnetworksettingsservice.h"
+
+class QNetworkSettingsManagerPrivate;
+
+class QNetworkSettingsServicePrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(QNetworkSettingsService)
+public:
+ QNetworkSettingsServicePrivate(const QString& aServiceId, QNetworkSettingsService *parent=0);
+ void setManager(QNetworkSettingsManagerPrivate *manager);
+ QNetworkSettingsService *q_ptr;
+
+ void setAutoConnect(const bool autoconnect);
+ void setupIpv4Config();
+ void setupIpv6Config();
+ void setupNameserversConfig();
+ void setupDomainsConfig();
+ void setupQNetworkSettingsProxy();
+ void connectService();
+ void disconnectService();
+
+ QString m_id;
+ QString m_name;
+ QNetworkSettingsState m_state;
+ QNetworkSettingsIPv4 m_ipv4config;
+ QNetworkSettingsIPv6 m_ipv6config;
+ QNetworkSettingsAddressModel m_domainsConfig;
+ QNetworkSettingsAddressModel m_nameserverConfig;
+ QNetworkSettingsProxy m_proxyConfig;
+ QNetworkSettingsWireless m_wifiConfig;
+ QNetworkSettingsType m_type;
+ QNetworkSettingsManagerPrivate *m_manager; //Not owned
+};
+
+class WpaSupplicantService : public QNetworkSettingsService
+{
+ Q_OBJECT
+public:
+ explicit WpaSupplicantService(QNetworkSettingsManagerPrivate* manager, QObject* parent=0);
+ void setId(const QString& aId);
+ void setName(const QString& aName);
+ void setFlags(const QString& aFlags);
+ void setState(QNetworkSettingsState::States aState);
+};
+
+#endif // QNETWORKSETTINGSSERVICEPRIVATE_H
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.cpp b/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.cpp
new file mode 100644
index 0000000..4e636c0
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qnetworksettingsuseragent_p.h"
+
+QNetworkSettingsUserAgentPrivate::QNetworkSettingsUserAgentPrivate(QNetworkSettingsUserAgent* parent)
+ :QObject(parent)
+ ,q_ptr(parent)
+{
+
+}
+
+void QNetworkSettingsUserAgentPrivate::setUserCredentials(const QString& aUsername, const QString& aPassword)
+{
+ Q_Q(QNetworkSettingsUserAgent);
+ m_passphrase = aPassword;
+ m_username = aUsername;
+ emit q->ready(false);
+}
+
+void QNetworkSettingsUserAgentPrivate::cancel()
+{
+ Q_Q(QNetworkSettingsUserAgent);
+ emit q->ready(true);
+}
diff --git a/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.h b/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.h
new file mode 100644
index 0000000..fc717dc
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qnetworksettingsuseragent_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Device Utilities module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QNETWORKSETTINGSUSERAGENTPRIVATE_H
+#define QNETWORKSETTINGSUSERAGENTPRIVATE_H
+
+#include <QObject>
+#include "qnetworksettingsuseragent.h"
+
+class QNetworkSettingsUserAgentPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(QNetworkSettingsUserAgent)
+public:
+ explicit QNetworkSettingsUserAgentPrivate(QNetworkSettingsUserAgent* parent);
+ virtual ~QNetworkSettingsUserAgentPrivate() {}
+ void setUserCredentials(const QString& aUsername, const QString& aPassword);
+ void cancel();
+ QString m_passphrase;
+ QString m_username;
+ QNetworkSettingsUserAgent *q_ptr;
+};
+
+#endif // QNETWORKSETTINGSUSERAGENTPRIVATE_H
diff --git a/src/networksettings/wpasupplicant/qwificontroller.cpp b/src/networksettings/wpasupplicant/qwificontroller.cpp
new file mode 100644
index 0000000..8e6cfff
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwificontroller.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 "qwificontroller_p.h"
+#include "qnetworksettingsmanager_p.h"
+#include "qwifisupplicant_p.h"
+#include "qwifidevice.h"
+
+#include <sys/types.h>
+#include <signal.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QByteArray>
+#include <QtCore/QFile>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(B2QT_WIFI, "qt.b2qt.wifi")
+
+class QWifiEventThread : public QThread
+{
+public:
+ QWifiEventThread(QWifiController *controller)
+ : m_controller(controller)
+ {
+ }
+
+ void run() {
+ qCDebug(B2QT_WIFI) << "running wifi event thread";
+ QWifiEvent *event = 0;
+ char buffer[2048];
+ forever {
+ int size = m_controller->supplicant()->waitForEvent(buffer, sizeof(buffer) - 1);
+ if (size > 0) {
+ 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 QWifiEvent(WIFI_SCAN_RESULTS);
+ } else if (strstr(buffer, "CTRL-EVENT-CONNECTED")) {
+ event = new QWifiEvent(WIFI_CONNECTED);
+ } else if (strstr(buffer, "CTRL-EVENT-DISCONNECTED")) {
+ event = new QWifiEvent(WIFI_DISCONNECTED);
+ } else if (strstr(buffer, "Trying to associate")) {
+ event = new QWifiEvent(WIFI_AUTHENTICATING, QLatin1String(buffer));
+ } else if (strstr(buffer, "Handshake failed")) {
+ event = new QWifiEvent(WIFI_HANDSHAKE_FAILED);
+ }
+
+ if (event) {
+ QCoreApplication::postEvent(m_controller->manager(), event);
+ }
+ }
+ }
+ }
+
+private:
+ QWifiController *m_controller;
+};
+
+
+QWifiController::QWifiController(QNetworkSettingsManagerPrivate *manager) :
+ m_manager(manager),
+ m_exitEventThread(false),
+ m_interface(QWifiDevice::wifiInterfaceName()),
+ m_eventThread(new QWifiEventThread(this)),
+ m_supplicant(new QWifiSupplicant(this))
+{
+ qRegisterMetaType<QWifiController::BackendState>("BackendState");
+ connect(m_supplicant, &QWifiSupplicant::raiseError, this, &QWifiController::raiseError);
+}
+
+QWifiController::~QWifiController()
+{
+ exitWifiEventThread();
+ delete m_eventThread;
+}
+
+void QWifiController::run()
+{
+ qCDebug(B2QT_WIFI) << "running wifi backend controller thread";
+ Method method;
+ forever {
+ m_methodsMutex.lock();
+ if (m_methods.isEmpty())
+ methodCallRequested.wait(&m_methodsMutex);
+ method = m_methods.takeFirst();
+ m_methodsMutex.unlock();
+ switch (method) {
+ case InitializeBackend:
+ initializeBackend();
+ break;
+ case TerminateBackend:
+ terminateBackend();
+ break;
+ case AcquireIPAddress:
+ acquireIPAddress();
+ break;
+ case StopDhcp:
+ stopDhcp();
+ break;
+ case ExitEventLoop:
+ qCDebug(B2QT_WIFI) << "exit wifi backend controller thread";
+ return;
+ }
+ }
+}
+
+void QWifiController::asyncCall(Method method)
+{
+ QMutexLocker locker(&m_methodsMutex);
+ m_methods.append(method);
+ methodCallRequested.wakeOne();
+}
+
+void QWifiController::initializeBackend()
+{
+ qCDebug(B2QT_WIFI) << "initializing wifi backend";
+ emit backendStateChanged(QWifiController::Initializing);
+
+ QProcess rfkill;
+ rfkill.start(QStringLiteral("rfkill"),
+ QStringList() << QStringLiteral("unblock") << QStringLiteral("wifi"));
+ rfkill.waitForFinished();
+
+ QProcess ifconfig;
+ ifconfig.start(QStringLiteral("ifconfig"),
+ QStringList() << QLatin1String(m_interface) << QStringLiteral("up"));
+ if (!ifconfig.waitForStarted()) {
+ emit raiseError(ifconfig.program() + QLatin1String(": ") + ifconfig.errorString());
+ return;
+ }
+
+ ifconfig.waitForFinished();
+ bool initFailed = false;
+ QByteArray error = ifconfig.readAllStandardError();
+ if (!error.isEmpty()) {
+ emit raiseError(QLatin1String("failed to bring up wifi interface: " + error));
+ initFailed = true;
+ }
+ if (!initFailed && resetSupplicantSocket())
+ emit backendStateChanged(QWifiController::Running);
+ else
+ emit backendStateChanged(QWifiController::NotRunning);
+}
+
+bool QWifiController::resetSupplicantSocket()
+{
+ qCDebug(B2QT_WIFI) << "reset supplicant socket";
+ exitWifiEventThread();
+ m_supplicant->stopSupplicant();
+ m_supplicant->closeSupplicantConnection();
+ if (!m_supplicant->startSupplicant())
+ return false;
+ if (!m_supplicant->connectToSupplicant())
+ return false;
+
+ startWifiEventThread();
+ return true;
+}
+
+void QWifiController::terminateBackend()
+{
+ qCDebug(B2QT_WIFI) << "terminating wifi backend";
+ emit backendStateChanged(QWifiController::Terminating);
+
+ exitWifiEventThread();
+ m_supplicant->stopSupplicant();
+ m_supplicant->closeSupplicantConnection();
+
+ QProcess ifconfig;
+ ifconfig.start(QStringLiteral("ifconfig"),
+ QStringList() << QLatin1String(m_interface) << QStringLiteral("down"));
+ if (!ifconfig.waitForStarted()) {
+ emit raiseError(ifconfig.program() + QLatin1String(": ") + ifconfig.errorString());
+ return;
+ }
+
+ ifconfig.waitForFinished();
+ QByteArray error = ifconfig.readAllStandardError();
+ if (!error.isEmpty())
+ emit raiseError(QLatin1String("failed to bring down wifi interface: " + error));
+
+ stopDhcp();
+ emit backendStateChanged(QWifiController::NotRunning);
+}
+
+void QWifiController::startWifiEventThread()
+{
+ m_exitEventThread = false;
+ m_eventThread->start();
+}
+
+void QWifiController::exitWifiEventThread()
+{
+ if (m_eventThread->isRunning()) {
+ m_exitEventThread = true;
+ m_manager->call(QStringLiteral("SCAN"));
+ if (!m_eventThread->wait(8000))
+ qCWarning(B2QT_WIFI, "timed out waiting for wifi event thread to exit");
+ }
+}
+
+void QWifiController::killDhcpProcess(const QString &path) const
+{
+ QFile pidFile(path);
+ if (!pidFile.exists())
+ return;
+
+ if (!pidFile.open(QIODevice::ReadOnly)) {
+ qCWarning(B2QT_WIFI) << "could not open pid file: " << path;
+ return;
+ }
+
+ bool ok;
+ int pid = pidFile.readAll().trimmed().toInt(&ok);
+ if (!ok) {
+ qCWarning(B2QT_WIFI) << "pid is not a number";
+ return;
+ }
+
+ kill(pid, 9);
+}
+
+void QWifiController::acquireIPAddress()
+{
+ qCDebug(B2QT_WIFI, "acquireIPAddress");
+ QString filePath = QLatin1String("/var/run/udhcpc." + m_interface + ".pid");
+ killDhcpProcess(filePath);
+ QStringList args;
+ args << QStringLiteral("-R") << QStringLiteral("-n") << QStringLiteral("-p")
+ << filePath << QStringLiteral("-i") << QLatin1String(m_interface);
+
+ QProcess udhcpc;
+ udhcpc.start(QStringLiteral("udhcpc"), args);
+ if (!udhcpc.waitForStarted()) {
+ emit raiseError(udhcpc.program() + QLatin1String(": ") + udhcpc.errorString());
+ emit dhcpRequestFinished(QLatin1String("failed"));
+ return;
+ }
+
+ udhcpc.waitForFinished();
+ QByteArray error = udhcpc.readAllStandardError();
+ QString status = QLatin1String("success");
+ if (!error.isEmpty()) {
+ emit raiseError(QLatin1String("udhcpc failed: " + error));
+ status = QLatin1String("failed");
+ } else {
+ if (udhcpc.readAllStandardOutput().contains("No lease"))
+ status = QLatin1String("failed");
+ }
+
+ emit dhcpRequestFinished(status);
+}
+
+void QWifiController::stopDhcp() const
+{
+ qCDebug(B2QT_WIFI, "stopDhcp");
+ QString filePath = QLatin1String("/var/run/udhcpc." + m_interface + ".pid");
+ killDhcpProcess(filePath);
+}
+
+QT_END_NAMESPACE
diff --git a/src/networksettings/wpasupplicant/qwificontroller_p.h b/src/networksettings/wpasupplicant/qwificontroller_p.h
new file mode 100644
index 0000000..902bc6e
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwificontroller_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 QWIFICONTROLLER_H
+#define QWIFICONTROLLER_H
+
+#include <QtCore/QEvent>
+#include <QtCore/QVector>
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(B2QT_WIFI)
+
+const QEvent::Type WIFI_SCAN_RESULTS = (QEvent::Type) (QEvent::User + 2001);
+const QEvent::Type WIFI_CONNECTED = (QEvent::Type) (QEvent::User + 2002);
+const QEvent::Type WIFI_HANDSHAKE_FAILED = (QEvent::Type) (QEvent::User + 2003);
+const QEvent::Type WIFI_AUTHENTICATING = (QEvent::Type) (QEvent::User + 2004);
+const QEvent::Type WIFI_DISCONNECTED = (QEvent::Type) (QEvent::User + 2005);
+
+class QWifiEventThread;
+class QWifiSupplicant;
+class QNetworkSettingsManagerPrivate;
+
+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
+ Q_ENUMS(BackendState)
+public:
+ enum Method {
+ InitializeBackend,
+ TerminateBackend,
+ AcquireIPAddress,
+ StopDhcp,
+ ExitEventLoop
+ };
+
+ enum BackendState {
+ Initializing,
+ Running,
+ Terminating,
+ NotRunning
+ };
+
+ explicit QWifiController(QNetworkSettingsManagerPrivate *manager);
+ ~QWifiController();
+
+ void asyncCall(Method method);
+ QNetworkSettingsManagerPrivate *manager() const { return m_manager; }
+ bool isWifiThreadExitRequested() const { return m_exitEventThread; }
+ void startWifiEventThread();
+ void acquireIPAddress();
+ void stopDhcp() const;
+ bool resetSupplicantSocket();
+ QWifiSupplicant *supplicant() const { return m_supplicant; }
+
+signals:
+ void backendStateChanged(BackendState backendState);
+ void dhcpRequestFinished(const QString &status);
+ void raiseError(const QString &error);
+
+protected:
+ void run();
+ void initializeBackend();
+ void terminateBackend();
+ void exitWifiEventThread();
+ void killDhcpProcess(const QString &path) const;
+
+private:
+ QNetworkSettingsManagerPrivate *m_manager; //not owned
+ bool m_exitEventThread;
+ QByteArray m_interface;
+ QVector<Method> m_methods;
+ QWifiEventThread *m_eventThread;
+ QMutex m_methodsMutex;
+ QWaitCondition methodCallRequested;
+ QWifiSupplicant *m_supplicant;
+};
+
+Q_DECLARE_METATYPE(QWifiController::BackendState)
+
+QT_END_NAMESPACE
+
+#endif // QWIFICONTROLLER_H
diff --git a/src/networksettings/wpasupplicant/qwifidevice.cpp b/src/networksettings/wpasupplicant/qwifidevice.cpp
new file mode 100644
index 0000000..a6812e7
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwifidevice.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 "qwifidevice.h"
+
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+#include <QtCore/QDir>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWifiDevice
+ \inmodule B2Qt.Wifi.Cpp
+ \ingroup wifi-cppclasses
+ \brief Represents a physical device.
+
+ Use this class to query if a device is Wifi capable, before attempting
+ to use the functionality of QWifiManager.
+
+ \code
+ QWifiManager *m_wifiManager = 0;
+ if (QWifiDevice::wifiSupported())
+ m_wifiManager = QWifiManager::instance();
+
+ if (m_wifiManager) {
+ m_wifiManager->start();
+ // and other wifi related code
+ }
+ \endcode
+ */
+
+QWifiDevice::QWifiDevice()
+{
+}
+
+QWifiDevice::~QWifiDevice()
+{
+}
+
+/*!
+ Returns \c true if a device is Wifi capable - Wifi driver and firmware has been
+ successfully loaded by the system, otherwise returns \c false.
+*/
+bool QWifiDevice::wifiSupported()
+{
+ QByteArray ifc = wifiInterfaceName();
+ bool hasInterface = QDir().exists(QString::fromLatin1("/sys/class/net/" + ifc));
+ if (!hasInterface)
+ qCWarning(B2QT_WIFI) << "could not find wifi interface in \"/sys/class/net/\", "
+ "looking for interface named: " << ifc;
+ return hasInterface;
+}
+
+/*!
+ Returns Wifi interface name.
+
+ Interface name is read from the \c B2QT_WIFI_INTERFACE
+ environment variable if it is set, otherwise, the default interface
+ name ("\e{wlan0}") is used.
+
+ \sa setWifiInterfaceName()
+ */
+QByteArray QWifiDevice::wifiInterfaceName()
+{
+ return qEnvironmentVariableIsSet("B2QT_WIFI_INTERFACE") ? qgetenv("B2QT_WIFI_INTERFACE") : "wlan0";
+}
+
+/*!
+ A conveniece method to set the Wifi interface \a name.
+
+ \sa wifiInterfaceName()
+ */
+void QWifiDevice::setWifiInterfaceName(const QByteArray &name)
+{
+ qputenv("B2QT_WIFI_INTERFACE", name);
+}
+
+QT_END_NAMESPACE
diff --git a/src/networksettings/wpasupplicant/qwifidevice.h b/src/networksettings/wpasupplicant/qwifidevice.h
new file mode 100644
index 0000000..80b4891
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwifidevice.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 QWIFIDEVICE_H
+#define QWIFIDEVICE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(B2QT_WIFI)
+
+class Q_DECL_EXPORT QWifiDevice : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QWifiDevice();
+ virtual ~QWifiDevice();
+
+ Q_INVOKABLE static bool wifiSupported();
+ static QByteArray wifiInterfaceName();
+ static void setWifiInterfaceName(const QByteArray &name);
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIFIDEVICE_H
diff --git a/src/networksettings/wpasupplicant/qwifisupplicant.cpp b/src/networksettings/wpasupplicant/qwifisupplicant.cpp
new file mode 100644
index 0000000..779475e
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwifisupplicant.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 "qwifisupplicant_p.h"
+#include "qwifidevice.h"
+
+#include <poll.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QProcess>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(B2QT_WIFI_VERBOSE, "qt.b2qt.wifi.verbose")
+
+#define CONFIG_FILE "/etc/wpa_supplicant.qtwifi.conf"
+#define CONTROL_INTERFACE_PATH "/var/run/wpa_supplicant/"
+
+QWifiSupplicant::QWifiSupplicant(QObject *parent) :
+ QObject(parent),
+ ctrl_conn(0),
+ monitor_conn(0),
+ interface(QWifiDevice::wifiInterfaceName())
+{
+ createSupplicantConfig();
+}
+
+void QWifiSupplicant::createSupplicantConfig()
+{
+ QFile supplicantConfig(QLatin1String(CONFIG_FILE));
+ if (supplicantConfig.exists())
+ return;
+
+ if (supplicantConfig.open(QIODevice::WriteOnly)) {
+ supplicantConfig.write("ctrl_interface=" CONTROL_INTERFACE_PATH "\n"
+ "ctrl_interface_group=0\n"
+ "update_config=1\n");
+ } else {
+ emit raiseError(QLatin1String("failed to create wpa_supplicant configuration file."));
+ }
+}
+
+bool QWifiSupplicant::startSupplicant()
+{
+ QString pidFile = QLatin1String("/var/run/wpa_supplicant." + interface + ".pid");
+ QString driver(QStringLiteral("nl80211,wext"));
+
+ QStringList arg;
+ arg << QStringLiteral("--start") << QStringLiteral("--quiet") << QStringLiteral("--name");
+ arg << QStringLiteral("wpa_supplicant") << QStringLiteral("--startas");
+ arg << QStringLiteral("/usr/sbin/wpa_supplicant") << QStringLiteral("--pidfile") << pidFile;
+ arg << QStringLiteral("--") << QStringLiteral("-B") << QStringLiteral("-P") << pidFile;
+ arg << QStringLiteral("-i") << QLatin1String(interface) << QStringLiteral("-c");
+ arg << QLatin1String(CONFIG_FILE) << QStringLiteral("-D") << driver;
+
+ QProcess startStopDaemon;
+ startStopDaemon.setProcessChannelMode(QProcess::MergedChannels);
+ startStopDaemon.start(QStringLiteral("start-stop-daemon"), arg);
+ if (!startStopDaemon.waitForStarted()) {
+ emit raiseError(startStopDaemon.program() + QLatin1String(": ") + startStopDaemon.errorString());
+ return false;
+ }
+ startStopDaemon.waitForFinished();
+ // if the interface socket exists then wpa-supplicant was invoked successfully
+ if (!QFile(QLatin1String(CONTROL_INTERFACE_PATH + interface)).exists()) {
+ emit raiseError(QLatin1String("failed to invoke wpa_supplicant: "
+ + startStopDaemon.readAll()));
+ return false;
+ }
+ // reset sockets used for exiting from hung state
+ exit_sockets[0] = exit_sockets[1] = -1;
+ return true;
+}
+
+bool QWifiSupplicant::stopSupplicant()
+{
+ QString pidFile = QLatin1String("/var/run/wpa_supplicant." + interface + ".pid");
+
+ if (QFile(pidFile).exists()) {
+ QStringList arg;
+ arg << QStringLiteral("--stop") << QStringLiteral("--quiet") << QStringLiteral("--name");
+ arg << QStringLiteral("wpa_supplicant") << QStringLiteral("--pidfile") << pidFile;
+
+ QProcess startStopDaemon;
+ startStopDaemon.start(QStringLiteral("start-stop-daemon"), arg);
+ if (!startStopDaemon.waitForStarted()) {
+ emit raiseError(startStopDaemon.program() + QLatin1String(": ") + startStopDaemon.errorString());
+ return false;
+ }
+ startStopDaemon.waitForFinished();
+ QByteArray error = startStopDaemon.readAllStandardError();
+ if (!error.isEmpty()) {
+ emit raiseError(QLatin1String("failed to stop a wpa_supplicant process" + error));
+ return false;
+ }
+
+ QFile::remove(pidFile);
+ }
+
+ QFile::remove(QLatin1String(CONTROL_INTERFACE_PATH + interface));
+
+ // workaround for QTEE-957
+ QProcess killall;
+ killall.start(QStringLiteral("killall"), QStringList() << QStringLiteral("-9") << QStringLiteral("wpa_supplicant"));
+ killall.waitForFinished();
+
+ return true;
+}
+
+/*! \internal
+ *
+ wpa_supplicant socket communication code (Apache License 2.0) with few modifications
+ from https://android.googlesource.com/platform/hardware/libhardware_legacy/
+
+ */
+bool QWifiSupplicant::connectToSupplicant()
+{
+ static char path[4096];
+ snprintf(path, sizeof(path), "%s/%s", CONTROL_INTERFACE_PATH, interface.constData());
+ bool connected = true;
+
+ ctrl_conn = wpa_ctrl_open(path);
+ if (ctrl_conn == NULL) {
+ qCWarning(B2QT_WIFI, "Unable to open connection to wpa_supplicant on \"%s\": %s",
+ path, strerror(errno));
+ connected = false;
+ }
+ monitor_conn = wpa_ctrl_open(path);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ connected = false;
+ }
+ if (wpa_ctrl_attach(monitor_conn) != 0) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
+ connected = false;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
+ connected = false;
+ }
+
+ if (!connected)
+ emit raiseError(QLatin1String("failed to connect to wpa_supplicant"));
+ return connected;
+}
+
+void QWifiSupplicant::closeSupplicantConnection()
+{
+ if (ctrl_conn != NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (monitor_conn != NULL) {
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+
+ if (exit_sockets[0] >= 0) {
+ close(exit_sockets[0]);
+ exit_sockets[0] = -1;
+ }
+
+ if (exit_sockets[1] >= 0) {
+ close(exit_sockets[1]);
+ exit_sockets[1] = -1;
+ }
+}
+
+int QWifiSupplicant::waitForEvent(char *buf, size_t buflen)
+{
+ size_t nread = buflen - 1;
+ int result;
+ char *match, *match2;
+
+ if (monitor_conn == NULL)
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed");
+
+ result = receiveEvent(buf, &nread);
+
+ // Terminate reception on exit socket
+ if (result == -2)
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed");
+
+ if (result < 0) {
+ qCWarning(B2QT_WIFI, "receiveEvent failed: %s", strerror(errno));
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - recv error");
+ }
+
+ buf[nread] = '\0';
+ // Check for EOF on the socket
+ if (result == 0 && nread == 0) {
+ // Fabricate an event to pass up
+ qCWarning(B2QT_WIFI, "Received EOF on supplicant socket");
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - signal 0 received");
+ }
+
+ /*
+ * Events strings are in the format
+ *
+ * IFNAME=iface <N>CTRL-EVENT-XXX
+ * or
+ * <N>CTRL-EVENT-XXX
+ *
+ * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
+ * etc.) and XXX is the event name. The level information is not useful
+ * to us, so strip it off.
+ */
+
+ if (strncmp(buf, "IFNAME=", (sizeof("IFNAME=") - 1)) == 0) {
+ match = strchr(buf, ' ');
+ if (match != NULL) {
+ if (match[1] == '<') {
+ match2 = strchr(match + 2, '>');
+ if (match2 != NULL) {
+ nread -= (match2 - match);
+ memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
+ }
+ }
+ } else {
+ return snprintf(buf, buflen, "%s", "CTRL-EVENT-IGNORE ");
+ }
+ } else if (buf[0] == '<') {
+ match = strchr(buf, '>');
+ if (match != NULL) {
+ nread -= (match + 1 - buf);
+ memmove(buf, match + 1, nread + 1);
+ //qCWarning(B2QT_WIFI, "supplicant generated event without interface - %s", buf);
+ }
+ } else {
+ // let the event go as is!
+ qCWarning(B2QT_WIFI, "supplicant generated event without interface and without message level - %s", buf);
+ }
+
+ return nread;
+}
+
+bool QWifiSupplicant::sendCommand(const QString &command, QByteArray *reply)
+{
+ QByteArray cmd = command.toLocal8Bit();
+ qCDebug(B2QT_WIFI) << "[command]: " << cmd;
+
+ if (ctrl_conn == NULL) {
+ qCWarning(B2QT_WIFI, "Not connected to wpa_supplicant");
+ return false;
+ }
+
+ char data[8192];
+ size_t len = sizeof(data) - 1; // -1: room to add a 0-terminator
+ int ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), data, &len, NULL);
+ if (ret == -2) {
+ qCWarning(B2QT_WIFI) << "command timed out";
+ // unblocks the monitor receive socket for termination
+ TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
+ return false;
+ } else if (ret < 0 || strncmp(data, "FAIL", 4) == 0) {
+ return false;
+ }
+
+ if (len == sizeof(data) - 1) {
+ qCWarning(B2QT_WIFI) << "possible buffer overflow detected";
+ return false;
+ }
+
+ data[len] = 0;
+ qCDebug(B2QT_WIFI_VERBOSE) << "[response]: " << data;
+ *reply = QByteArray(data, len);
+
+ return true;
+}
+
+int QWifiSupplicant::receiveEvent(char *reply, size_t *reply_len)
+{
+ int res = 0;
+ int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
+ struct pollfd rfds[2];
+
+ memset(rfds, 0, 2 * sizeof(struct pollfd));
+ rfds[0].fd = ctrlfd;
+ rfds[0].events |= POLLIN;
+ rfds[1].fd = exit_sockets[1];
+ rfds[1].events |= POLLIN;
+ res = TEMP_FAILURE_RETRY(poll(rfds, 2, -1));
+ if (res < 0) {
+ qCWarning(B2QT_WIFI, "Error poll = %d", res);
+ return res;
+ }
+ if (rfds[0].revents & POLLIN) {
+ return wpa_ctrl_recv(monitor_conn, reply, reply_len);
+ }
+
+ /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
+ * or we timed out. In either case, this call has failed ..
+ */
+ return -2;
+}
+
+static inline int 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;
+}
+
+static inline int 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;
+}
+
+static inline int printf_decode(char *buf, int maxlen, const char *str)
+{
+ const char *pos = str;
+ 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 len;
+}
+
+/*! \internal
+ *
+ Decode wpa_supplicant encoded string, see file hostapd/src/utils/common.c
+ in git://w1.fi/hostap.git repository.
+
+ 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 QWifiSupplicant::decodeSsid(const QString &encoded)
+{
+ static char ssid[2048];
+ printf_decode(ssid, sizeof(ssid), encoded.toLatin1().constData());
+ return QString::fromUtf8(ssid);
+}
+
+QT_END_NAMESPACE
diff --git a/src/networksettings/wpasupplicant/qwifisupplicant_p.h b/src/networksettings/wpasupplicant/qwifisupplicant_p.h
new file mode 100644
index 0000000..13855c0
--- /dev/null
+++ b/src/networksettings/wpasupplicant/qwifisupplicant_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 QWIFISUPPLICANT_H
+#define QWIFISUPPLICANT_H
+
+#include <QObject>
+#include <QByteArray>
+#include <QLoggingCategory>
+
+#include "wpa-supplicant/wpa_ctrl.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(B2QT_WIFI)
+Q_DECLARE_LOGGING_CATEGORY(B2QT_WIFI_VERBOSE)
+
+class QWifiManagerPrivate;
+
+class QWifiSupplicant : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QWifiSupplicant(QObject *parent);
+
+ void createSupplicantConfig();
+ bool startSupplicant();
+ bool stopSupplicant();
+ bool connectToSupplicant();
+ void closeSupplicantConnection();
+ int waitForEvent(char *buf, size_t buflen);
+ bool sendCommand(const QString &command, QByteArray *reply);
+ static QString decodeSsid(const QString &encoded);
+
+signals:
+ void raiseError(const QString& error);
+
+protected:
+ int receiveEvent(char *reply, size_t *reply_len);
+
+private:
+ wpa_ctrl *ctrl_conn;
+ wpa_ctrl *monitor_conn;
+ int exit_sockets[2];
+ QByteArray interface;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIFISUPPLICANT_H