diff options
Diffstat (limited to 'src/networksettings/wpasupplicant/qwifisupplicant.cpp')
-rw-r--r-- | src/networksettings/wpasupplicant/qwifisupplicant.cpp | 453 |
1 files changed, 0 insertions, 453 deletions
diff --git a/src/networksettings/wpasupplicant/qwifisupplicant.cpp b/src/networksettings/wpasupplicant/qwifisupplicant.cpp deleted file mode 100644 index e8a88a8..0000000 --- a/src/networksettings/wpasupplicant/qwifisupplicant.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Device Utilities module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#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 |