summaryrefslogtreecommitdiffstats
path: root/src/imports/wifi
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/wifi')
-rw-r--r--src/imports/wifi/qmldir2
-rw-r--r--src/imports/wifi/qwifimanager.cpp306
-rw-r--r--src/imports/wifi/qwifimanager.h79
-rw-r--r--src/imports/wifi/qwifimodule.pro27
-rw-r--r--src/imports/wifi/qwifinetwork.cpp13
-rw-r--r--src/imports/wifi/qwifinetwork.h51
-rw-r--r--src/imports/wifi/qwifinetworklist.cpp106
-rw-r--r--src/imports/wifi/qwifinetworklist.h33
8 files changed, 617 insertions, 0 deletions
diff --git a/src/imports/wifi/qmldir b/src/imports/wifi/qmldir
new file mode 100644
index 0000000..4c36784
--- /dev/null
+++ b/src/imports/wifi/qmldir
@@ -0,0 +1,2 @@
+module Qt.labs.wifi
+plugin qwifimodule
diff --git a/src/imports/wifi/qwifimanager.cpp b/src/imports/wifi/qwifimanager.cpp
new file mode 100644
index 0000000..984e8da
--- /dev/null
+++ b/src/imports/wifi/qwifimanager.cpp
@@ -0,0 +1,306 @@
+#include "qwifimanager.h"
+
+#include <QtCore>
+
+#include <hardware_legacy/wifi.h>
+#include <cutils/properties.h>
+
+
+#define WLAN_INTERFACE "wlan0"
+
+static bool WIFI_DEBUG = !qgetenv("WIFI_DEBUG").isEmpty();
+
+const QEvent::Type WIFI_SCAN_RESULTS = (QEvent::Type) (QEvent::User + 1);
+const QEvent::Type WIFI_CONNECTED = (QEvent::Type) (QEvent::User + 2);
+
+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 QWifiManagerEventThread : public QThread
+{
+public:
+ QWifiManagerEventThread(QWifiManager *manager)
+ : m_manager(manager)
+ {
+
+ }
+
+ void run() {
+ if (WIFI_DEBUG) qDebug("EventReceiver thread is running");
+ char buffer[2048];
+ while (1) {
+ int size = wifi_wait_for_event(WLAN_INTERFACE, buffer, sizeof(buffer) - 1);
+ if (size > 0) {
+ buffer[size] = 0;
+
+ if (WIFI_DEBUG) qDebug("EVENT: %s", buffer);
+
+ char *event = &buffer[11];
+ if (strstr(event, "SCAN-RESULTS")) {
+ QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_SCAN_RESULTS);
+ QCoreApplication::postEvent(m_manager, e);
+ } else if (strstr(event, "CONNECTED")) {
+ QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_CONNECTED);
+ QCoreApplication::postEvent(m_manager, e);
+ }
+ }
+ }
+ }
+
+ QWifiManager *m_manager;
+};
+
+
+
+QWifiManager::QWifiManager()
+ : m_networks(this)
+ , m_eventThread(0)
+ , m_scanTimer(0)
+ , m_internalState(IS_Uninitialized)
+ , m_scanning(false)
+{
+}
+
+
+
+void QWifiManager::start()
+{
+ if (WIFI_DEBUG) qDebug("QWifiManager: start");
+ connectToBackend();
+}
+
+
+
+void QWifiManager::setScanning(bool scanning)
+{
+ if (m_scanning == scanning)
+ return;
+
+ m_scanning = scanning;
+ emit scanningChanged(scanning);
+
+ if (m_scanning) {
+ if (WIFI_DEBUG) qDebug("QWifiManager: scanning");
+ call("SCAN");
+ m_scanTimer = startTimer(5000);
+ } else {
+ if (WIFI_DEBUG) qDebug("QWifiManager: stop scanning");
+ killTimer(m_scanTimer);
+ }
+}
+
+
+
+QByteArray int_to_ip(int i) {
+ QByteArray ip;
+
+ ip.append(QByteArray::number(i & 0x000000ff));
+ ip.append('.');
+ ip.append(QByteArray::number((i & 0x0000ff00) >> 8));
+ ip.append('.');
+ ip.append(QByteArray::number((i & 0x00ff0000) >> 16));
+ ip.append('.');
+ ip.append(QByteArray::number(i >> 24));
+
+ return ip;
+}
+
+
+void QWifiManager::connectToBackend()
+{
+ if (m_internalState == IS_Uninitialized)
+ m_internalState = IS_StartBackend;
+
+ if (m_internalState == IS_StartBackend
+ && wifi_start_supplicant(0) >= 0)
+ m_internalState = IS_ConnectToBackend;
+
+ if (m_internalState == IS_ConnectToBackend
+ && wifi_connect_to_supplicant(WLAN_INTERFACE) >= 0)
+ m_internalState = IS_UpAndRunning;
+
+ if (m_internalState == IS_UpAndRunning) {
+ emit readyChanged(true);
+ m_eventThread = new QWifiManagerEventThread(this);
+ m_eventThread->start();
+
+ qDebug("QWifiManager: started successfully");
+
+ handleConnected();
+ } else {
+ if (WIFI_DEBUG) qWarning("QWifiManager: stuck at internal state level: %d", m_internalState);
+ }
+}
+
+
+QByteArray QWifiManager::call(const char *command)
+{
+ char data[2048];
+ size_t len = sizeof(data);
+ if (wifi_command(WLAN_INTERFACE, command, data, &len) < 0) {
+ qWarning("QWifiManager: call failed: %s", command);
+ return QByteArray();
+ }
+ QByteArray result = QByteArray::fromRawData(data, len);
+ qDebug("QWifiManager::call: %s ==>\n%s", command, result.constData());
+ return result;
+}
+
+
+bool QWifiManager::event(QEvent *e)
+{
+ switch ((int) e->type()) {
+ case WIFI_SCAN_RESULTS:
+ m_networks.parseScanResults(call("SCAN_RESULTS"));
+ return true;
+ case WIFI_CONNECTED:
+ handleConnected();
+ break;
+ case QEvent::Timer: {
+ int tid = static_cast<QTimerEvent *>(e)->timerId();
+ if (tid == m_scanTimer) {
+ call("SCAN");
+ return true;
+ }
+ break; }
+ }
+
+ return QObject::event(e);
+}
+
+void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase)
+{
+ if (network->ssid() == m_connectedSSID) {
+ if (WIFI_DEBUG) qDebug("QWifiManager::connect(), already connected to %s", network->ssid().constData());
+ return;
+ }
+
+ QByteArray listResult = call("LIST_NETWORKS");
+
+ if (listResult.contains(network->ssid())) {
+ QList<QByteArray> lines = listResult.split('\n');
+ for (int i=1; i<lines.size(); ++i) {
+ const QByteArray &line = lines.at(i);
+ if (line.contains(network->ssid())) {
+ int networkId = line.toInt();
+ if (line.contains("[CURRENT]")) {
+ if (WIFI_DEBUG) qDebug("QWifiManager::connect(), network is already current");
+ handleConnected();
+ } else {
+ if (WIFI_DEBUG) qDebug("QWifiManager::connect(), network known, but not enabled");
+ call(QByteArray("ENABLE_NETWORK ") + QByteArray::number(networkId));
+ }
+ return;
+ }
+ }
+ }
+
+ bool ok;
+ QByteArray id = call("ADD_NETWORK").trimmed();
+ id.toInt(&ok);
+ if (!ok) {
+ qWarning("QWifiManager::connect(), failed to add network");
+ return;
+ }
+ QByteArray setNetworkCommand = QByteArray("SET_NETWORK ") + id;
+
+ QByteArray ssidOK = call(setNetworkCommand + QByteArray(" ssid ") + '"' + network->ssid() + '"');
+ QByteArray pskOK = call(setNetworkCommand + QByteArray(" psk ") + '"' + passphrase.toLatin1() + '"');
+
+ if (ssidOK.trimmed() != QByteArray("OK") || pskOK.trimmed() != QByteArray("OK")) {
+ call("REMOVE_NETWORK " + id);
+ qWarning("QWifiManager::connect(), failed to set properties on network '%s'.\n'%s'\n'%s'",
+ id.constData(),
+ ssidOK.constData(),
+ pskOK.constData());
+ return;
+ }
+
+ call(QByteArray("ENABLE_NETWORK ") + id);
+}
+
+
+class ProcessRunner : public QThread {
+public:
+ void run() {
+ QProcess::execute(QStringLiteral("dhcpcd"), QStringList() << QStringLiteral("wlan0"));
+ deleteLater();
+ }
+};
+
+
+void QWifiManager::handleConnected()
+{
+ QList<QByteArray> lists = call("LIST_NETWORKS").split('\n');
+ QByteArray connectedNetwork;
+ for (int i=1; i<lists.size(); ++i) {
+ if (lists.at(i).contains("[CURRENT]")) {
+ connectedNetwork = lists.at(i);
+ break;
+ }
+ }
+
+ if (connectedNetwork.isEmpty()) {
+ if (WIFI_DEBUG)
+ qDebug("QWifiManager::handleConnected: not connected to a network...");
+ m_online = false;
+ onlineChanged(m_online);
+ return;
+ } else {
+ if (WIFI_DEBUG)
+ qDebug("QWifiManager::handleConnected: current is %s", connectedNetwork.constData());
+ }
+
+ QList<QByteArray> info = connectedNetwork.split('\t');
+ m_connectedSSID = info.at(1);
+ emit connectedSSIDChanged(m_connectedSSID);
+
+ if (WIFI_DEBUG)
+ qDebug("QWifiManager::handleConnected: starting dhcpcd...");
+ QThread *t = new ProcessRunner();
+ t->start();
+
+ int ipaddr, gateway, mask, dns1, dns2, server, lease;
+ if (do_dhcp_request(&ipaddr, &gateway, &mask, &dns1, &dns2, &server, &lease) == 0) {
+ if (WIFI_DEBUG) {
+ printf("ip ........: %s\n"
+ "gateway ...: %s\n"
+ "mask ......: %s\n"
+ "dns1 ......: %s\n"
+ "dns2 ......: %s\n"
+ "lease .....: %d\n",
+ int_to_ip(ipaddr).constData(),
+ int_to_ip(gateway).constData(),
+ int_to_ip(mask).constData(),
+ int_to_ip(dns1).constData(),
+ int_to_ip(dns2).constData(),
+ lease);
+ }
+
+ // Updating dns values..
+ property_set("net.dns1", int_to_ip(dns1).constData());
+ property_set("net.dns2", int_to_ip(dns2).constData());
+
+ m_online = true;
+ onlineChanged(false);
+
+ } else {
+ if (WIFI_DEBUG)
+ qDebug("QWifiManager::handleConnected: dhcp request failed...");
+
+ }
+}
diff --git a/src/imports/wifi/qwifimanager.h b/src/imports/wifi/qwifimanager.h
new file mode 100644
index 0000000..a2fdb99
--- /dev/null
+++ b/src/imports/wifi/qwifimanager.h
@@ -0,0 +1,79 @@
+#ifndef QWIFIMANAGER_H
+#define QWIFIMANAGER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+
+#include "qwifinetworklist.h"
+
+class QWifiManagerEventThread;
+
+class QWifiManager : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged)
+ Q_PROPERTY(bool online READ isOnline NOTIFY onlineChanged)
+ Q_PROPERTY(bool scanning READ scanning WRITE setScanning NOTIFY scanningChanged)
+
+ Q_PROPERTY(QString connectedSSID READ connectedSSID NOTIFY connectedSSIDChanged)
+ Q_PROPERTY(QWifiNetworkList *networks READ networks CONSTANT)
+
+public:
+ enum InternalState {
+ IS_Uninitialized,
+ IS_StartBackend,
+ IS_ConnectToBackend,
+ IS_UpAndRunning
+ };
+
+ QWifiManager();
+
+ QWifiNetworkList *networks() { return &m_networks; }
+
+ QString connectedSSID() const { return m_connectedSSID; }
+
+ bool scanning() const { return m_scanning; }
+ void setScanning(bool scanning);
+
+ bool isReady() const { return m_internalState == IS_UpAndRunning; }
+ bool isOnline() const { return m_online; }
+
+
+public slots:
+ void start();
+
+ void connect(QWifiNetwork *network, const QString &passphrase);
+
+signals:
+ void scanningChanged(bool arg);
+ void readyChanged(bool ready);
+ void onlineChanged(bool online);
+ void connectedSSIDChanged(const QString &);
+
+protected:
+ bool event(QEvent *);
+
+private:
+ friend class QWifiManagerEventThread;
+
+ void handleConnected();
+ void parseScanResults();
+ void connectToBackend();
+ QByteArray call(const char *command);
+
+ QString m_connectedSSID;
+ QWifiNetworkList m_networks;
+
+ QWifiManagerEventThread *m_eventThread;
+
+ int m_scanTimer;
+
+ InternalState m_internalState;
+
+ bool m_scanning;
+ bool m_online;
+
+};
+
+#endif // QWIFIMANAGER_H
diff --git a/src/imports/wifi/qwifimodule.pro b/src/imports/wifi/qwifimodule.pro
new file mode 100644
index 0000000..311baba
--- /dev/null
+++ b/src/imports/wifi/qwifimodule.pro
@@ -0,0 +1,27 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2013-03-11T12:29:12
+#
+#-------------------------------------------------
+
+CXX_MODULE = qml
+QT += qml quick
+TARGET = qwifimodule
+TARGETPATH = Qt/labs/wifi
+IMPORT_VERSION = 0.1
+
+SOURCES += \
+ pluginmain.cpp \
+ qwifimanager.cpp \
+ qwifinetwork.cpp \
+ qwifinetworklist.cpp
+
+HEADERS += \
+ qwifimanager.h \
+ qwifinetwork.h \
+ qwifinetworklist.h
+
+LIBS += -lhardware_legacy -lcutils
+
+load(qml_plugin)
+
diff --git a/src/imports/wifi/qwifinetwork.cpp b/src/imports/wifi/qwifinetwork.cpp
new file mode 100644
index 0000000..a3fc038
--- /dev/null
+++ b/src/imports/wifi/qwifinetwork.cpp
@@ -0,0 +1,13 @@
+#include "qwifinetwork.h"
+
+QWifiNetwork::QWifiNetwork()
+{
+}
+
+void QWifiNetwork::setSignalStrength(int strenght)
+{
+ if (m_signalStrength == strenght)
+ return;
+ m_signalStrength = strenght;
+ emit signalStrengthChanged(m_signalStrength);
+}
diff --git a/src/imports/wifi/qwifinetwork.h b/src/imports/wifi/qwifinetwork.h
new file mode 100644
index 0000000..7a28a58
--- /dev/null
+++ b/src/imports/wifi/qwifinetwork.h
@@ -0,0 +1,51 @@
+#ifndef QWIFINETWORK_H
+#define QWIFINETWORK_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+
+class QWifiManager;
+
+class QWifiNetwork : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QByteArray bssid READ bssid CONSTANT)
+ Q_PROPERTY(QByteArray ssid READ ssid CONSTANT)
+ Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged)
+ Q_PROPERTY(bool supportsWPA2 READ supportsWPA2 CONSTANT)
+ Q_PROPERTY(bool supportsWPA READ supportsWPA CONSTANT)
+ Q_PROPERTY(bool supportsWEP READ supportsWEP CONSTANT)
+ Q_PROPERTY(bool supportsWPS READ supportsWPS CONSTANT)
+
+public:
+ QWifiNetwork();
+
+ QByteArray bssid() const { return m_bssid; }
+ void setBssid(const QByteArray &id) { m_bssid = id; }
+
+ QByteArray ssid() const { return m_ssid; }
+ void setSsid(const QByteArray &id) { m_ssid = id; }
+
+ int signalStrength() const { return m_signalStrength; }
+ void setSignalStrength(int strenght);
+
+ QByteArray flags() const { return m_flags; }
+ void setFlags(const QByteArray &f) { m_flags = f; }
+ bool supportsWPA2() const { return m_flags.contains("WPA2"); }
+ bool supportsWPA() const { return m_flags.contains("WPA"); }
+ bool supportsWEP() const { return m_flags.contains("WEP"); }
+ bool supportsWPS() const { return m_flags.contains("WPS"); }
+
+signals:
+ void signalStrengthChanged(int arg);
+
+private:
+ QByteArray m_bssid;
+ QByteArray m_ssid;
+ int m_signalStrength;
+
+ QByteArray m_flags;
+};
+
+#endif // QWIFINETWORK_H
diff --git a/src/imports/wifi/qwifinetworklist.cpp b/src/imports/wifi/qwifinetworklist.cpp
new file mode 100644
index 0000000..e7fa92d
--- /dev/null
+++ b/src/imports/wifi/qwifinetworklist.cpp
@@ -0,0 +1,106 @@
+#include "qwifinetworklist.h"
+
+#include <QtCore>
+
+const int ID_BSSID = (Qt::ItemDataRole) (Qt::UserRole + 1);
+const int ID_SSID = (Qt::ItemDataRole) (Qt::UserRole + 2);
+const int ID_SIGNAL = (Qt::ItemDataRole) (Qt::UserRole + 3);
+const int ID_WPA2 = (Qt::ItemDataRole) (Qt::UserRole + 4);
+const int ID_WPA = (Qt::ItemDataRole) (Qt::UserRole + 5);
+const int ID_NETWORK = (Qt::ItemDataRole) (Qt::UserRole + 6);
+
+QWifiNetworkList::QWifiNetworkList(QWifiManager *manager)
+ : m_manager(manager)
+{
+}
+
+
+QHash<int, QByteArray> QWifiNetworkList::roleNames() const
+{
+ QHash<int, QByteArray> names;
+ names.insert(ID_BSSID, "bssid");
+ names.insert(ID_SSID, "ssid");
+ names.insert(ID_SIGNAL, "strength");
+ names.insert(ID_WPA2, "wpa2");
+ names.insert(ID_WPA, "wpa");
+ names.insert(ID_NETWORK, "network");
+ return names;
+}
+
+
+
+QVariant QWifiNetworkList::data(const QModelIndex &index, int role) const
+{
+ QWifiNetwork *n = m_networks.at(index.row());
+
+ switch (role) {
+ case ID_BSSID: return n->bssid();
+ case ID_SSID: return n->ssid();
+ case ID_SIGNAL: return n->signalStrength();
+ case ID_WPA2: return n->supportsWPA2();
+ case ID_WPA: return n->supportsWPA();
+ case ID_NETWORK: return QVariant::fromValue((QObject *) n);
+ }
+
+ qDebug("QWifiNetworkList::data(), undefined role: %d\n", role);
+
+ return QVariant();
+}
+
+QWifiNetwork *QWifiNetworkList::networkForBSSID(const QByteArray &bssid, int *pos)
+{
+ for (int i=0; i<m_networks.size(); ++i) {
+ if (m_networks.at(i)->bssid() == bssid) {
+ if (pos)
+ *pos = i;
+ return m_networks.at(i);
+ }
+ }
+ return 0;
+}
+
+
+void QWifiNetworkList::parseScanResults(const QByteArray &results)
+{
+ QList<QByteArray> lines = results.split('\n');
+
+ QSet<QByteArray> bssids;
+ for (int i=1; i<lines.size(); ++i) {
+ QList<QByteArray> info = lines.at(i).split('\t');
+ if (info.size() < 5 || info.at(4).isEmpty() || info.at(0).isEmpty())
+ continue;
+ bssids.insert(info.at(0));
+ int pos = 0;
+ QWifiNetwork *existing = networkForBSSID(info.at(0), &pos);
+ if (!existing) {
+ QWifiNetwork *network = new QWifiNetwork();
+ network->setBssid(info.at(0));
+ network->setFlags(info.at(3));
+ network->setSignalStrength(info.at(2).toInt());
+ network->setSsid(info.at(4));
+ beginInsertRows(QModelIndex(), m_networks.size(), m_networks.size());
+ m_networks << network;
+ endInsertRows();
+
+ } else {
+ existing->setSignalStrength(info.at(2).toInt());
+ dataChanged(createIndex(pos, 0), createIndex(pos, 0));
+ }
+ }
+
+ for (int i=0; i<m_networks.size(); ) {
+ if (!bssids.contains(m_networks.at(i)->bssid())) {
+ beginRemoveRows(QModelIndex(), i, i);
+ delete m_networks.takeAt(i);
+ endRemoveRows();
+ } else {
+ ++i;
+ }
+ }
+
+// for (int i=0; i<m_networks.size(); ++i) {
+// qDebug() << " - network:" << m_networks.at(i)->bssid() << m_networks.at(i)->ssid() << m_networks.at(i)->flags() << m_networks.at(i)->signalStrength();
+// }
+}
+
+
diff --git a/src/imports/wifi/qwifinetworklist.h b/src/imports/wifi/qwifinetworklist.h
new file mode 100644
index 0000000..f6e134c
--- /dev/null
+++ b/src/imports/wifi/qwifinetworklist.h
@@ -0,0 +1,33 @@
+#ifndef QWIFINETWORKLIST_H
+#define QWIFINETWORKLIST_H
+
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QList>
+
+#include "qwifinetwork.h"
+
+class QWifiManager;
+
+class QWifiNetworkList : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+
+ QWifiNetworkList(QWifiManager *manager);
+
+ void parseScanResults(const QByteArray &data);
+
+ QWifiNetwork *networkForBSSID(const QByteArray &bssid, int *pos);
+
+ int rowCount(const QModelIndex &) const { return m_networks.size(); }
+ QVariant data(const QModelIndex &index, int role) const;
+
+ QHash<int,QByteArray> roleNames() const;
+
+private:
+ QWifiManager *m_manager;
+ QList<QWifiNetwork *> m_networks;
+};
+
+#endif // QWIFINETWORKLIST_H