summaryrefslogtreecommitdiffstats
path: root/src/imports/wifi
diff options
context:
space:
mode:
authorKalle Viironen <kalle.viironen@digia.com>2014-05-26 13:53:13 +0300
committerKalle Viironen <kalle.viironen@digia.com>2014-05-26 13:53:20 +0300
commit5cdc15a7b82b7adfd4c5cae85ffb4327593dd076 (patch)
tree342fa9523f5400f4ecbcf6fde169021fabaff500 /src/imports/wifi
parent9627172876cd2a387d44b5a9a6ce0a3867ebc730 (diff)
parent5c160b6fe916e5605eaa1fd8394b62527ff9f997 (diff)
Merge branch 'stable' into releaseQtEE_v3.0.0
* stable: (25 commits) Add notes about Quick Compiler failures doc: Updated versions and supported platforms doc: Updated links to Qt EE known issues and product page Doc: Warn the user that his Nexus will be wiped. doc: move adb connection change info to customization Build wifi also on eLinux Don't show Wi-Fi group box on iMX6-eAndroid Fix class names for WebEngine Doc: add note about webengine's widget apis Doc: add change log for version 3.0.0 doc: include sabre sd documentation Doc: Add setup instructions for Nexus 7 (2013) Set initial "backend ready" state. Port QtWifi to eLinux Add a note about webengine and emulator Doc: Update version Doc: Add table with all possible MACHINE values Doc: QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS replaces QT_QPA_GENERIC_PLUGINS Doc: Use precise naming for Boundary Devices i.MX6 Add PowerManager service. ... Change-Id: I2762dfe023d461b677d7ed748c33444145d35175
Diffstat (limited to 'src/imports/wifi')
-rw-r--r--src/imports/wifi/pluginmain.cpp25
-rw-r--r--src/imports/wifi/qwifi_elinux.cpp264
-rw-r--r--src/imports/wifi/qwifi_elinux.h34
-rw-r--r--src/imports/wifi/qwifimanager.cpp151
-rw-r--r--src/imports/wifi/qwifimanager.h30
-rw-r--r--src/imports/wifi/qwifinetworklistmodel.cpp13
-rw-r--r--src/imports/wifi/wifi.pro23
7 files changed, 504 insertions, 36 deletions
diff --git a/src/imports/wifi/pluginmain.cpp b/src/imports/wifi/pluginmain.cpp
index fdf07e9..51a2e7c 100644
--- a/src/imports/wifi/pluginmain.cpp
+++ b/src/imports/wifi/pluginmain.cpp
@@ -19,12 +19,14 @@
#include "qwifimanager.h"
#include <QtCore/QDir>
+#include <QtCore/QDebug>
#include <QtCore/QByteArray>
#include <QtQml/QQmlExtensionPlugin>
#include <QtQml/qqml.h>
+#ifdef Q_OS_ANDROID
#include <hardware_legacy/wifi.h>
-
+#endif
/*!
\qmltype Interface
\inqmlmodule Qt.labs.wifi
@@ -64,20 +66,19 @@ public:
Q_INVOKABLE bool wifiSupported() const
{
- bool supported = false;
- if (wifi_load_driver() == 0 && wifi_start_supplicant(0) == 0) {
- char interface[PROPERTY_VALUE_MAX];
- property_get("wifi.interface", interface, NULL);
- // standard linux kernel path
- QByteArray path;
- path.append("/sys/class/net/").append(interface);
- supported = QDir().exists(path.constData());
- if (!supported)
- qWarning() << "QWifiGlobal: could not find wifi interface in " << path;
+ bool hasInterface = QDir().exists(QStringLiteral("/sys/class/net/wlan0"));
+ if (!hasInterface)
+ qWarning() << "QWifiGlobal: could not find wifi interface in /sys/class/net/";
+#ifdef Q_OS_ANDROID
+ if (hasInterface && wifi_load_driver() == 0 && wifi_start_supplicant(0) == 0) {
+ return true;
} else {
qWarning() << "QWifiGlobal: wifi driver is not available";
+ return false;
}
- return supported;
+#else
+ return hasInterface;
+#endif
}
};
diff --git a/src/imports/wifi/qwifi_elinux.cpp b/src/imports/wifi/qwifi_elinux.cpp
new file mode 100644
index 0000000..551d887
--- /dev/null
+++ b/src/imports/wifi/qwifi_elinux.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use the contact form at
+** http://qt.digia.com/
+**
+** 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://qt.digia.com/
+**
+****************************************************************************/
+#include "qwifi_elinux.h"
+
+#include <QtCore/QDebug>
+
+#include "wpa-supplicant/wpa_ctrl.h"
+
+#include <poll.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+static const char SUPP_CONFIG_FILE[] = "/etc/wpa_supplicant.conf";
+static const char IFACE_DIR[] = "/var/run/wpa_supplicant/";
+static const char WIFI[] = "wlan0";
+
+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];
+
+static const char IFNAME[] = "IFNAME=";
+#define IFNAMELEN (sizeof(IFNAME) - 1)
+static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE ";
+
+int wifi_connect_on_socket_path(const char *path);
+int wifi_ctrl_recv(char *reply, size_t *reply_len);
+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();
+
+int q_wifi_start_supplicant()
+{
+ // NOTE: supplicant started when bringing up the wifi interface in
+ // QWifiManager::connectToBackend() by:
+ // QProcess::execute(QStringLiteral("ifup")
+
+ /* Clear out any stale socket files that might be left over. */
+ //wpa_ctrl_cleanup();
+ /* Reset sockets used for exiting from hung state */
+ exit_sockets[0] = exit_sockets[1] = -1;
+ return 0;
+}
+
+int q_wifi_stop_supplicant()
+{
+ // NOTE: supplicant stopped when bringing down the wifi
+ // interface in QWifiManager::disconnectFromBackend() by:
+ // QProcess::execute(QStringLiteral("ifdown")
+ return 0;
+}
+
+int q_wifi_connect_to_supplicant(const char *ifname)
+{
+ Q_UNUSED(ifname);
+ static char path[4096];
+ snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, WIFI);
+ return wifi_connect_on_socket_path(path);
+}
+
+int wifi_connect_on_socket_path(const char *path)
+{
+ // establishes the control and monitor socket connections on the interface
+ ctrl_conn = wpa_ctrl_open(path);
+ if (ctrl_conn == NULL) {
+ qWarning("Unable to open connection to supplicant on \"%s\": %s",
+ path, strerror(errno));
+ return -1;
+ }
+ monitor_conn = wpa_ctrl_open(path);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ return -1;
+ }
+ if (wpa_ctrl_attach(monitor_conn) != 0) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
+ return -1;
+ }
+
+ 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;
+ return -1;
+ }
+
+ return 0;
+}
+
+int q_wifi_wait_for_event(const char *ifname, char *buf, size_t buflen)
+{
+ Q_UNUSED(ifname);
+ return wifi_wait_on_socket(buf, buflen);
+}
+
+int wifi_wait_on_socket(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 = wifi_ctrl_recv(buf, &nread);
+
+ /* Terminate reception on exit socket */
+ if (result == -2) {
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed");
+ }
+
+ if (result < 0) {
+ qWarning("wifi_ctrl_recv failed: %s\n", 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 */
+ qWarning("Received EOF on supplicant socket\n");
+ 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, IFNAMELEN) == 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", WPA_EVENT_IGNORE);
+ }
+ } else if (buf[0] == '<') {
+ match = strchr(buf, '>');
+ if (match != NULL) {
+ nread -= (match + 1 - buf);
+ memmove(buf, match + 1, nread + 1);
+ //qWarning("supplicant generated event without interface - %s\n", buf);
+ }
+ } else {
+ /* let the event go as is! */
+ qWarning("supplicant generated event without interface and without message level - %s\n", buf);
+ }
+
+ return nread;
+}
+
+int wifi_ctrl_recv(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) {
+ qWarning("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;
+}
+
+int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
+{
+ int ret;
+ if (ctrl_conn == NULL) {
+ qWarning("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
+ return -1;
+ }
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
+ if (ret == -2) {
+ qWarning("'%s' command timed out.\n", cmd);
+ /* unblocks the monitor receive socket for termination */
+ TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
+ return -2;
+ } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
+ return -1;
+ }
+ if (strncmp(cmd, "PING", 4) == 0) {
+ reply[*reply_len] = '\0';
+ }
+ return 0;
+}
+
+int q_wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len)
+{
+ Q_UNUSED(ifname);
+ return wifi_send_command(command, reply, reply_len);
+}
+
+void q_wifi_close_supplicant_connection(const char *ifname)
+{
+ Q_UNUSED(ifname)
+ wifi_close_sockets();
+}
+
+void wifi_close_sockets()
+{
+ 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;
+ }
+}
diff --git a/src/imports/wifi/qwifi_elinux.h b/src/imports/wifi/qwifi_elinux.h
new file mode 100644
index 0000000..92a04f8
--- /dev/null
+++ b/src/imports/wifi/qwifi_elinux.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use the contact form at
+** http://qt.digia.com/
+**
+** 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://qt.digia.com/
+**
+****************************************************************************/
+#ifndef LOCAL_WIFI_H
+#define LOCAL_WIFI_H
+
+#include <string.h>
+
+// This API mirrors Android's Wi-Fi libraries interface [1] and implementation, excluding Android OS specific parts.
+// [1] http://androidxref.com/4.4.2_r2/xref/hardware/libhardware_legacy/include/hardware_legacy/wifi.h
+
+int q_wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len);
+int q_wifi_wait_for_event(const char *ifname, char *buf, size_t buflen);
+int q_wifi_connect_to_supplicant(const char *ifname);
+void q_wifi_close_supplicant_connection(const char *ifname);
+int q_wifi_start_supplicant();
+int q_wifi_stop_supplicant();
+
+#endif // LOCAL_WIFI_H
diff --git a/src/imports/wifi/qwifimanager.cpp b/src/imports/wifi/qwifimanager.cpp
index af6f5d3..65073f1 100644
--- a/src/imports/wifi/qwifimanager.cpp
+++ b/src/imports/wifi/qwifimanager.cpp
@@ -19,10 +19,13 @@
#include "qwifimanager.h"
#include <QtCore>
-
+#ifdef Q_OS_ANDROID
#include <hardware_legacy/wifi.h>
#include <cutils/sockets.h>
#include <unistd.h>
+#else
+#include <qwifi_elinux.h>
+#endif
static const char SUPPLICANT_SVC[] = "init.svc.wpa_supplicant";
static const char WIFI_INTERFACE[] = "wifi.interface";
@@ -34,6 +37,69 @@ 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);
+#ifdef Q_OS_ANDROID
+/*
+ * Work around API differences between Android versions
+ */
+
+static int q_wifi_start_supplicant()
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 1
+ return wifi_start_supplicant();
+#else
+ return wifi_start_supplicant(0);
+#endif
+}
+
+static int q_wifi_stop_supplicant()
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 1
+ return wifi_stop_supplicant();
+#else
+ return wifi_stop_supplicant(0);
+#endif
+}
+
+static int q_wifi_connect_to_supplicant(const char *ifname)
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && (Q_ANDROID_VERSION_MINOR < 4 && Q_ANDROID_VERSION_MINOR >= 1)
+ return wifi_connect_to_supplicant(ifname);
+#else
+ Q_UNUSED(ifname);
+ return wifi_connect_to_supplicant();
+#endif
+}
+
+static void q_wifi_close_supplicant_connection(const char *ifname)
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && (Q_ANDROID_VERSION_MINOR < 4 && Q_ANDROID_VERSION_MINOR >= 1)
+ wifi_close_supplicant_connection(ifname);
+#else
+ Q_UNUSED(ifname);
+ wifi_close_supplicant_connection();
+#endif
+}
+
+static int q_wifi_wait_for_event(const char *ifname, char *buf, size_t len)
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && (Q_ANDROID_VERSION_MINOR < 4 && Q_ANDROID_VERSION_MINOR >= 1)
+ return wifi_wait_for_event(ifname, buf, len);
+#else
+ Q_UNUSED(ifname);
+ return wifi_wait_for_event(buf, len);
+#endif
+}
+
+static int q_wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len)
+{
+#if Q_ANDROID_VERSION_MAJOR == 4 && (Q_ANDROID_VERSION_MINOR < 4 && Q_ANDROID_VERSION_MINOR >= 1)
+ return wifi_command(ifname, command, reply, reply_len);
+#else
+ Q_UNUSED(ifname);
+ return wifi_command(command, reply, reply_len);
+#endif
+}
+
/*
* This function is borrowed from /system/core/libnetutils/dhcp_utils.c
*
@@ -63,6 +129,7 @@ static int wait_for_property(const char *name, const char *desired_value, int ma
}
return -1; /* failure */
}
+#endif
class QWifiManagerEvent : public QEvent
{
@@ -94,7 +161,7 @@ public:
QWifiManagerEvent *event = 0;
char buffer[2048];
while (1) {
- int size = wifi_wait_for_event(m_if.constData(), buffer, sizeof(buffer) - 1);
+ int size = q_wifi_wait_for_event(m_if.constData(), buffer, sizeof(buffer) - 1);
if (size > 0) {
buffer[size] = 0;
event = 0;
@@ -348,17 +415,25 @@ QWifiManager::QWifiManager()
, m_eventThread(0)
, m_scanTimer(0)
, m_scanning(false)
+#ifdef Q_OS_ANDROID
, m_daemonClientSocket(0)
+#endif
, m_exitingEventThread(false)
, m_startingUp(true)
, m_network(0)
{
+#ifdef Q_OS_ANDROID
char interface[PROPERTY_VALUE_MAX];
property_get(WIFI_INTERFACE, interface, NULL);
m_interface = interface;
- if (QT_WIFI_DEBUG) qDebug("QWifiManager: using wifi interface: %s", m_interface.constData());
+#else
+ m_interface = "wlan0"; // use envvar for the interface name?
+ m_dhcpRunner = new ProcessRunner(m_interface);
+ QObject::connect(m_dhcpRunner, &ProcessRunner::processFinished, this, &QWifiManager::handleDhcpFinished);
+#endif
+ qDebug("QWifiManager: using wifi interface: %s", m_interface.constData());
m_eventThread = new QWifiManagerEventThread(this, m_interface);
-
+#ifdef Q_OS_ANDROID
m_daemonClientSocket = new QLocalSocket;
int qconnFd = socket_local_client("qconnectivity", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
if (qconnFd != -1) {
@@ -381,16 +456,25 @@ QWifiManager::QWifiManager()
// same here, cleans up the state
disconnectFromBackend();
}
+ } else {
+#endif
+ m_backendReady = false;
+ emit backendReadyChanged();
+#ifdef Q_OS_ANDROID
}
+#endif
}
QWifiManager::~QWifiManager()
{
exitEventThread();
delete m_eventThread;
+#ifdef Q_OS_ANDROID
delete m_daemonClientSocket;
+#endif
}
+#ifdef Q_OS_ANDROID
void QWifiManager::handleDhcpReply()
{
if (m_daemonClientSocket->canReadLine()) {
@@ -425,6 +509,14 @@ void QWifiManager::connectedToDaemon()
m_daemonClientSocket->write(m_request.constData(), m_request.length());
m_daemonClientSocket->flush();
}
+#endif
+
+void QWifiManager::handleDhcpFinished()
+{
+ // ### TODO - could be that dhcp request fails, how to determine?
+ updateNetworkState(Connected);
+ call("SAVE_CONFIG");
+}
void QWifiManager::start()
{
@@ -444,22 +536,31 @@ void QWifiManager::stop()
void QWifiManager::connectToBackend()
{
+ // ### TODO: maybe it makes sense to move this functions in non-gui thread
+#ifdef Q_OS_ANDROID
if (!(is_wifi_driver_loaded() || wifi_load_driver() == 0)) {
qWarning("QWifiManager: failed to load a driver");
return;
}
- if (wifi_start_supplicant(0) != 0) {
+#else
+ QProcess::execute(QStringLiteral("ifup"), QStringList() << m_interface.constData());
+#endif
+ if (q_wifi_start_supplicant() != 0) {
qWarning("QWifiManager: failed to start a supplicant");
return;
}
+#ifdef Q_OS_ANDROID
if (wait_for_property(SUPPLICANT_SVC, "running", 5) < 0) {
qWarning("QWifiManager: Timed out waiting for supplicant to start");
return;
}
- if (wifi_connect_to_supplicant(m_interface.constData()) == 0) {
+#endif
+ if (q_wifi_connect_to_supplicant(m_interface.constData()) == 0) {
m_backendReady = true;
emit backendReadyChanged();
+#ifdef Q_OS_ANDROID
property_set(QT_WIFI_BACKEND, "running");
+#endif
} else {
qWarning("QWifiManager: failed to connect to a supplicant");
return;
@@ -473,10 +574,15 @@ void QWifiManager::connectToBackend()
void QWifiManager::disconnectFromBackend()
{
exitEventThread();
- if (wifi_stop_supplicant(0) < 0)
+ if (q_wifi_stop_supplicant() < 0)
qWarning("QWifiManager: failed to stop supplicant");
- wifi_close_supplicant_connection(m_interface.constData());
+ q_wifi_close_supplicant_connection(m_interface.constData());
+ setScanning(false);
+#ifdef Q_OS_ANDROID
property_set(QT_WIFI_BACKEND, "stopped");
+#else
+ QProcess::execute(QStringLiteral("ifdown"), QStringList() << m_interface.constData());
+#endif
m_backendReady = false;
emit backendReadyChanged();
}
@@ -512,7 +618,7 @@ QByteArray QWifiManager::call(const char *command) const
{
char data[2048];
size_t len = sizeof(data) - 1; // -1: room to add a 0-terminator
- if (wifi_command(m_interface.constData(), command, data, &len) < 0) {
+ if (q_wifi_command(m_interface.constData(), command, data, &len) < 0) {
qWarning("QWifiManager: call failed: %s", command);
return QByteArray();
}
@@ -571,7 +677,6 @@ void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase)
return;
}
updateNetworkState(Authenticating);
-
call("DISABLE_NETWORK all");
if (!m_connectedSSID.isEmpty()) {
m_connectedSSID.clear();
@@ -633,13 +738,35 @@ void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase)
void QWifiManager::disconnect()
{
call("DISCONNECT");
+#ifdef Q_OS_ANDROID
QByteArray req = m_interface;
sendDhcpRequest(req.append(" disconnect"));
+#endif
m_connectedSSID.clear();
updateNetworkState(Disconnected);
emit connectedSSIDChanged(m_connectedSSID);
}
+void ProcessRunner::run()
+{
+ // kill existing udhcpc instance
+ QString filePath = QString("/var/run/udhcpc.").append(m_ifc).append(".pid");
+ QFile pidFile(filePath);
+ if (pidFile.open(QIODevice::ReadOnly)) {
+ QByteArray pid = pidFile.readAll();
+ pidFile.close();
+ QProcess::execute(QStringLiteral("kill"), QStringList() << pid.trimmed().constData());
+ } else {
+ qWarning() << "QWifiManager - Failed to read" << filePath;
+ }
+ QStringList args;
+ args << QStringLiteral("-R") << QStringLiteral("-n") << QStringLiteral("-p")
+ << filePath << QStringLiteral("-i") << m_ifc;
+ // start DHCP client
+ QProcess::execute(QStringLiteral("udhcpc"), args);
+ emit processFinished();
+}
+
void QWifiManager::handleConnected()
{
QList<QByteArray> lists = call("LIST_NETWORKS").split('\n');
@@ -670,6 +797,10 @@ void QWifiManager::handleConnected()
}
updateNetworkState(ObtainingIPAddress);
+#ifdef Q_OS_ANDROID
QByteArray req = m_interface;
sendDhcpRequest(req.append(" connect"));
+#else
+ m_dhcpRunner->start();
+#endif
}
diff --git a/src/imports/wifi/qwifimanager.h b/src/imports/wifi/qwifimanager.h
index 162190e..3af123f 100644
--- a/src/imports/wifi/qwifimanager.h
+++ b/src/imports/wifi/qwifimanager.h
@@ -20,15 +20,32 @@
#define QWIFIMANAGER_H
#include <QtCore/QObject>
+#include <QtCore/QThread>
#include <QtCore/QByteArray>
-#include <QtNetwork/QLocalSocket>
+#ifdef Q_OS_ANDROID
+#include <QtNetwork/QLocalSocket>
#include <cutils/properties.h>
+#endif
#include "qwifinetworklistmodel.h"
class QWifiManagerEventThread;
+class ProcessRunner : public QThread
+{
+ Q_OBJECT
+public:
+ ProcessRunner(const QByteArray &ifc) : m_ifc(ifc) {}
+ void run();
+
+signals:
+ void processFinished();
+
+private:
+ QByteArray m_ifc;
+};
+
class QWifiManager : public QObject
{
Q_OBJECT
@@ -74,21 +91,26 @@ signals:
protected:
bool event(QEvent *);
- void sendDhcpRequest(const QByteArray &request);
void handleConnected();
void connectToBackend();
void disconnectFromBackend();
void exitEventThread();
+
QByteArray call(const char *command) const;
bool checkedCall(const char *command) const;
void updateNetworkState(NetworkState state);
protected slots:
+#if defined(FORCE_MOC)
+ void sendDhcpRequest(const QByteArray &request);
void connectedToDaemon();
void handleDhcpReply();
+#endif
+ void handleDhcpFinished();
private:
friend class QWifiManagerEventThread;
+ friend class ProcessRunner;
QString m_connectedSSID;
QWifiNetworkListModel m_networkListModel;
@@ -100,7 +122,11 @@ private:
QByteArray m_interface;
NetworkState m_state;
+#ifdef Q_OS_ANDROID
QLocalSocket *m_daemonClientSocket;
+#else
+ ProcessRunner *m_dhcpRunner;
+#endif
QByteArray m_request;
bool m_exitingEventThread;
bool m_startingUp;
diff --git a/src/imports/wifi/qwifinetworklistmodel.cpp b/src/imports/wifi/qwifinetworklistmodel.cpp
index 4fbf25f..f95af36 100644
--- a/src/imports/wifi/qwifinetworklistmodel.cpp
+++ b/src/imports/wifi/qwifinetworklistmodel.cpp
@@ -88,14 +88,15 @@ void QWifiNetworkListModel::parseScanResults(const QByteArray &results)
QWifiNetwork *knownNetwork = networkForSSID(info.at(4), &pos);
if (!knownNetwork)
knownNetwork = outOfRangeListContains(info.at(4));
-
+ // 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;
if (!knownNetwork) {
QWifiNetwork *network = new QWifiNetwork();
network->setOutOfRange(false);
network->setBssid(info.at(0));
network->setFlags(info.at(3));
- // signal strength is in dBm
- network->setSignalStrength(info.at(2).toInt());
+ network->setSignalStrength(signalStrength);
network->setSsid(info.at(4));
beginInsertRows(QModelIndex(), m_networks.size(), m_networks.size());
m_networks << network;
@@ -112,15 +113,15 @@ void QWifiNetworkListModel::parseScanResults(const QByteArray &results)
// ssids are the same, compare bssids..
if (knownNetwork->bssid() == info.at(0)) {
// same access point, simply update the signal strength
- knownNetwork->setSignalStrength(info.at(2).toInt());
+ knownNetwork->setSignalStrength(signalStrength);
knownNetwork->setOutOfRange(false);
dataChanged(createIndex(pos, 0), createIndex(pos, 0));
- } else if (knownNetwork->signalStrength() < info.at(2).toInt()) {
+ } else if (knownNetwork->signalStrength() < signalStrength) {
// replace with a stronger access point within the same network
m_networks.at(pos)->setOutOfRange(false);
m_networks.at(pos)->setBssid(info.at(0));
m_networks.at(pos)->setFlags(info.at(3));
- m_networks.at(pos)->setSignalStrength(info.at(2).toInt());
+ m_networks.at(pos)->setSignalStrength(signalStrength);
m_networks.at(pos)->setSsid(info.at(4));
dataChanged(createIndex(pos, 0), createIndex(pos, 0));
}
diff --git a/src/imports/wifi/wifi.pro b/src/imports/wifi/wifi.pro
index b920978..fcb6cdd 100644
--- a/src/imports/wifi/wifi.pro
+++ b/src/imports/wifi/wifi.pro
@@ -4,18 +4,29 @@ TARGET = qwifimodule
TARGETPATH = Qt/labs/wifi
IMPORT_VERSION = 0.1
+HEADERS += \
+ qwifimanager.h \
+ qwifinetwork.h \
+ qwifinetworklistmodel.h
+
SOURCES += \
pluginmain.cpp \
qwifimanager.cpp \
qwifinetwork.cpp \
qwifinetworklistmodel.cpp
-HEADERS += \
- qwifimanager.h \
- qwifinetwork.h \
- qwifinetworklistmodel.h
+android: {
+ LIBS += -lhardware_legacy -lcutils
+ DEFINES += FORCE_MOC
+} else {
+ DEFINES += CONFIG_CTRL_IFACE \
+ CONFIG_CTRL_IFACE_UNIX
-LIBS += -lhardware_legacy -lcutils
+ HEADERS += qwifi_elinux.h
+ SOURCES += \
+ qwifi_elinux.cpp \
+ $$[QT_SYSROOT]/usr/include/wpa-supplicant/wpa_ctrl.c \
+ $$[QT_SYSROOT]/usr/include/wpa-supplicant/os_unix.c
+}
load(qml_plugin)
-