~jonas-drange/ubuntu-system-settings/hotspots-change-test-backend

« back to all changes in this revision

Viewing changes to plugins/cellular/hotspotmanager.cpp

  • Committer: jonas-drange
  • Date: 2015-07-22 14:16:13 UTC
  • mfrom: (1312.3.74 tmp)
  • Revision ID: jonas.drange@canonical.com-20150722141613-4hz7rolyt8eei8ht
  Pete Woods 2015-07-16 Manage hotspots via connectity API

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2014 Canonical, Ltd.
3
 
 *
4
 
 * Authors:
5
 
 *    Jussi Pakkanen <jussi.pakkanen@canonical.com>
6
 
 *
7
 
 * This program is free software: you can redistribute it and/or modify it
8
 
 * under the terms of the GNU General Public License version 3, as published
9
 
 * by the Free Software Foundation.
10
 
 *
11
 
 * This library is distributed in the hope that it will be useful, but WITHOUT
12
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
 
 * details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include "hotspotmanager.h"
21
 
 
22
 
#include "nm_manager_proxy.h"
23
 
#include "nm_settings_proxy.h"
24
 
#include "nm_settings_connection_proxy.h"
25
 
#include <QStringList>
26
 
#include <QDBusReply>
27
 
#include <QtDebug>
28
 
#include <QDBusInterface>
29
 
#include <QDBusMetaType>
30
 
 
31
 
typedef QMap<QString, QVariantMap> nmConnectionArg;
32
 
Q_DECLARE_METATYPE(nmConnectionArg)
33
 
 
34
 
namespace {
35
 
 
36
 
const QString nm_service("org.freedesktop.NetworkManager");
37
 
const QString nm_settings_object("/org/freedesktop/NetworkManager/Settings");
38
 
const QString nm_settings_interface("org.freedesktop.NetworkManager.Settings");
39
 
const QString nm_connection_interface("org.freedesktop.NetworkManager.Settings.Connection");
40
 
const QString nm_dbus_path("/org/freedesktop/NetworkManager");
41
 
const QString nm_device_interface("org.freedesktop.NetworkManager.Device");
42
 
 
43
 
#define NM_METHOD_NAME "AddAndActivateConnection"
44
 
 
45
 
void startAdhoc(const QByteArray &ssid, const QString &password, const QDBusObjectPath &devicePath) {
46
 
    nmConnectionArg connection;
47
 
 
48
 
    QDBusObjectPath specific("/");
49
 
 
50
 
    QVariantMap wireless;
51
 
    wireless[QStringLiteral("security")] = QVariant(QStringLiteral("802-11-wireless-security"));
52
 
    wireless[QStringLiteral("ssid")] = QVariant(ssid);
53
 
    wireless[QStringLiteral("mode")] = QVariant(QStringLiteral("adhoc"));
54
 
    connection["802-11-wireless"] = wireless;
55
 
 
56
 
    QVariantMap connsettings;
57
 
    connsettings[QStringLiteral("autoconnect")] = QVariant(false);
58
 
    connsettings[QStringLiteral("uuid")] = QVariant(QStringLiteral("aab22b5d-7342-48dc-8920-1b7da31d6829"));
59
 
    connsettings[QStringLiteral("type")] = QVariant(QStringLiteral("802-11-wireless"));
60
 
    connection["connection"] = connsettings;
61
 
 
62
 
    QVariantMap ipv4;
63
 
    ipv4[QStringLiteral("addressess")] = QVariant(QStringList());
64
 
    ipv4[QStringLiteral("dns")] = QVariant(QStringList());
65
 
    ipv4[QStringLiteral("method")] = QVariant(QStringLiteral("shared"));
66
 
    ipv4[QStringLiteral("routes")] = QVariant(QStringList());
67
 
    connection["ipv4"] = ipv4;
68
 
 
69
 
    QVariantMap security;
70
 
    security[QStringLiteral("proto")] = QVariant(QStringList{"rsn"});
71
 
    security[QStringLiteral("pairwise")] = QVariant(QStringList{"ccmp"});
72
 
    security[QStringLiteral("group")] = QVariant(QStringList{"ccmp"});
73
 
    security[QStringLiteral("key-mgmt")] = QVariant(QStringLiteral("wpa-psk"));
74
 
    security[QStringLiteral("psk")] = QVariant(password);
75
 
    connection["802-11-wireless-security"] = security;
76
 
 
77
 
    OrgFreedesktopNetworkManagerInterface mgr(nm_service,
78
 
            nm_dbus_path,
79
 
            QDBusConnection::systemBus());
80
 
    auto reply = mgr.AddAndActivateConnection(connection, devicePath, specific);
81
 
    reply.waitForFinished();
82
 
    if(!reply.isValid()) {
83
 
        qWarning() << "Failed to start adhoc network: " << reply.error().message() << "\n";
84
 
    }
85
 
}
86
 
 
87
 
bool detectAdhoc(QString &dbusPath, QByteArray &ssid, QString &password, bool &isActive) {
88
 
    static const QString activeIface("org.freedesktop.NetworkManager.Connection.Active");
89
 
    static const QString connProp("Connection");
90
 
    OrgFreedesktopNetworkManagerInterface mgr(nm_service,
91
 
            nm_dbus_path,
92
 
            QDBusConnection::systemBus());
93
 
    auto activeConnections = mgr.activeConnections();
94
 
    OrgFreedesktopNetworkManagerSettingsInterface settings(nm_service, nm_settings_object,
95
 
            QDBusConnection::systemBus());
96
 
    QSet<QDBusObjectPath> actives;
97
 
    auto r = settings.ListConnections();
98
 
    r.waitForFinished();
99
 
    for(const auto &conn : activeConnections) {
100
 
        QDBusInterface iface(nm_service, conn.path(), "org.freedesktop.DBus.Properties",
101
 
                QDBusConnection::systemBus());
102
 
        QDBusReply<QVariant> conname = iface.call("Get", activeIface, connProp);
103
 
        if(!conname.isValid()) {
104
 
            qWarning() << "Error getting connamd: " << conname.error().message() << "\n";
105
 
            continue;
106
 
        }
107
 
        QDBusObjectPath mainConnection = qvariant_cast<QDBusObjectPath>(conname.value());
108
 
        actives.insert(mainConnection);
109
 
    }
110
 
    const char wifiKey[] = "802-11-wireless";
111
 
    for(const auto &i : r.value()) {
112
 
        OrgFreedesktopNetworkManagerSettingsConnectionInterface conn(nm_service,
113
 
                i.path(),
114
 
                QDBusConnection::systemBus());
115
 
        auto reply = conn.GetSettings();
116
 
        reply.waitForFinished();
117
 
        auto s = reply.value();
118
 
        if(s.find(wifiKey) != s.end()) {
119
 
            auto wsetup = s[wifiKey];
120
 
            if(wsetup["mode"] == "adhoc") {
121
 
                dbusPath = i.path();
122
 
                ssid = wsetup["ssid"].toByteArray();
123
 
                auto pwdReply = conn.GetSecrets("802-11-wireless-security");
124
 
                pwdReply.waitForFinished();
125
 
                password = pwdReply.value()["802-11-wireless-security"]["psk"].toString();
126
 
                isActive = false;
127
 
                for(const auto &ac : actives) {
128
 
                    if(i == ac) {
129
 
                        isActive = true;
130
 
                        break;
131
 
                    }
132
 
                }
133
 
                return true;
134
 
            }
135
 
        }
136
 
    }
137
 
    return false;
138
 
}
139
 
 
140
 
QDBusObjectPath detectWirelessDevice() {
141
 
    OrgFreedesktopNetworkManagerInterface mgr(nm_service,
142
 
            nm_dbus_path,
143
 
            QDBusConnection::systemBus());
144
 
    auto devices = mgr.GetDevices();
145
 
    devices.waitForFinished();
146
 
    for(const auto &dpath : devices.value()) {
147
 
        QDBusInterface iface(nm_service, dpath.path(), "org.freedesktop.DBus.Properties",
148
 
                QDBusConnection::systemBus());
149
 
        QDBusReply<QVariant> typeReply = iface.call("Get", "org.freedesktop.NetworkManager.Device", "DeviceType");
150
 
        auto typeInt = qvariant_cast<int>(typeReply.value());
151
 
        if(typeInt == 2) {
152
 
            return dpath; // Assumptions are that there is only one wifi device and it is not hotpluggable.
153
 
        }
154
 
    }
155
 
    qWarning() << "Wireless device not found, hotspot functionality is inoperative.\n";
156
 
    return QDBusObjectPath();
157
 
}
158
 
 
159
 
std::string generate_password() {
160
 
    static const std::string items("abcdefghijklmnopqrstuvwxyz01234567890");
161
 
    const int passwordLength = 8;
162
 
    std::string result;
163
 
    for(int i=0; i<passwordLength; i++) {
164
 
        result.push_back(items[std::rand() % items.length()]);
165
 
    }
166
 
    return result;
167
 
}
168
 
 
169
 
}
170
 
 
171
 
HotspotManager::HotspotManager(QObject *parent) : QObject(parent),
172
 
        m_devicePath(detectWirelessDevice()) {
173
 
    static bool isRegistered = false;
174
 
    if(!isRegistered) {
175
 
        qDBusRegisterMetaType<nmConnectionArg>();
176
 
        isRegistered = true;
177
 
    }
178
 
    if(!detectAdhoc(m_settingsPath, m_ssid, m_password, m_isActive)) {
179
 
        m_settingsPath = "";
180
 
        m_ssid = "Ubuntu hotspot";
181
 
        m_password = generate_password().c_str();
182
 
        m_isActive = false;
183
 
    }
184
 
}
185
 
 
186
 
QByteArray HotspotManager::getHotspotName() {
187
 
    return m_ssid;
188
 
}
189
 
 
190
 
QString HotspotManager::getHotspotPassword() {
191
 
    return m_password;
192
 
}
193
 
 
194
 
void HotspotManager::setupHotspot(QByteArray ssid_, QString password_) {
195
 
    m_ssid = ssid_;
196
 
    m_password = password_;
197
 
}
198
 
 
199
 
void HotspotManager::enableHotspot() {
200
 
    if(!m_settingsPath.isEmpty()) {
201
 
        // Prints a warning message if the connection has disappeared already.
202
 
        destroyHotspot();
203
 
        // NM returns from the dbus call immediately but only destroys the
204
 
        // connection some time later. There is no callback for when this happens.
205
 
        // So this is the best we can do with reasonable effort.
206
 
        QThread::sleep(1);
207
 
    }
208
 
    startAdhoc(m_ssid, m_password, m_devicePath);
209
 
    detectAdhoc(m_settingsPath, m_ssid, m_password, m_isActive);
210
 
}
211
 
 
212
 
bool HotspotManager::isHotspotActive() {
213
 
    return m_isActive;
214
 
}
215
 
 
216
 
void HotspotManager::disableHotspot() {
217
 
    static const QString activeIface("org.freedesktop.NetworkManager.Connection.Active");
218
 
    static const QString connProp("Connection");
219
 
    OrgFreedesktopNetworkManagerInterface mgr(nm_service,
220
 
            nm_dbus_path,
221
 
            QDBusConnection::systemBus());
222
 
    auto activeConnections = mgr.activeConnections();
223
 
    for(const auto &aConn : activeConnections) {
224
 
        QDBusInterface iface(nm_service, aConn.path(), "org.freedesktop.DBus.Properties",
225
 
                QDBusConnection::systemBus());
226
 
        QDBusReply<QVariant> conname = iface.call("Get", activeIface, connProp);
227
 
        QDBusObjectPath backingConnection = qvariant_cast<QDBusObjectPath>(conname.value());
228
 
        if(backingConnection.path() == m_settingsPath) {
229
 
            mgr.DeactivateConnection(aConn);
230
 
            return;
231
 
        }
232
 
    }
233
 
    qWarning() << "Could not find a hotspot setup to disable.\n";
234
 
}
235
 
 
236
 
void HotspotManager::destroyHotspot() {
237
 
    if(m_settingsPath.isEmpty()) {
238
 
        qWarning() << "Tried to destroy nonexisting hotspot.\n";
239
 
        return;
240
 
    }
241
 
    QDBusInterface control(nm_service, m_settingsPath, nm_connection_interface,
242
 
            QDBusConnection::systemBus());
243
 
    QDBusReply<void> reply = control.call("Delete");
244
 
    if(!reply.isValid()) {
245
 
        qWarning() << "Could not disconnect adhoc network: " << reply.error().message() << "\n";
246
 
    } else {
247
 
        m_isActive = false;
248
 
    }
249
 
}