summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKari Oikarinen <kari.oikarinen@qt.io>2017-03-02 12:34:52 +0200
committerKari Oikarinen <kari.oikarinen@qt.io>2017-05-02 11:47:27 +0000
commitd96efc1a528f38c1da6830eadd9d096a49495d08 (patch)
tree387c352de97ebba767edd926559ec78e713d1355
parente1e7ff8f1fd0558559321066cedd62e729621175 (diff)
Configure DHCP server on device before handshake
Change the procedure for a newly detected device: First configure the network and then do the handshake for the device information. The configuring the network part is new and incorporates a new service NetworkConfigurationService. On the device it relies on a script b2qt-gadget-network.sh (or as specified in a command line parameter) which does the actual configuring of the USB network interface. The network configuration to apply is selected from a list of hardcoded candidates from the private use IPv4 ranges available. They are checked against the existing networks on the host and an unused one is picked. On the device the USB interface is configured to use this network and to act as a DHCP server for it. Host will then pick up an IP from this DHCP server automatically. Previous configuration of the host network is thus not necessary and is removed. Task-number: QTBUG-58614 Change-Id: I6a4ed34ef7d5cba9e55e6fa4f07725bb3c00d795 Reviewed-by: Samuli Piippo <samuli.piippo@qt.io>
-rw-r--r--libqdb/protocol/services.h1
-rw-r--r--qdb/qdb.pro8
-rw-r--r--qdb/server/devicemanager.cpp25
-rw-r--r--qdb/server/devicemanager.h2
-rw-r--r--qdb/server/networkconfigurationservice.cpp91
-rw-r--r--qdb/server/networkconfigurationservice.h55
-rw-r--r--qdb/server/networkconfigurator.cpp78
-rw-r--r--qdb/server/networkconfigurator.h52
-rw-r--r--qdb/server/networkmanagercontrol.cpp465
-rw-r--r--qdb/server/networkmanagercontrol.h51
-rw-r--r--qdb/server/subnet.cpp77
-rw-r--r--qdb/server/subnet.h37
-rw-r--r--qdbd/configuration.cpp11
-rw-r--r--qdbd/configuration.h3
-rw-r--r--qdbd/createexecutor.cpp3
-rw-r--r--qdbd/main.cpp32
-rw-r--r--qdbd/networkconfigurationexecutor.cpp70
-rw-r--r--qdbd/networkconfigurationexecutor.h42
-rw-r--r--qdbd/qdbd.pro2
-rw-r--r--tests/tests.pro1
-rw-r--r--tests/tst_subnet.cpp100
-rw-r--r--tests/tst_subnet.pro20
22 files changed, 694 insertions, 532 deletions
diff --git a/libqdb/protocol/services.h b/libqdb/protocol/services.h
index b25b928..f9ac631 100644
--- a/libqdb/protocol/services.h
+++ b/libqdb/protocol/services.h
@@ -30,6 +30,7 @@ enum ServiceTag : uint32_t
{
EchoTag = 1,
HandshakeTag,
+ NetworkConfigurationTag,
};
inline
diff --git a/qdb/qdb.pro b/qdb/qdb.pro
index 50eef74..14b674b 100644
--- a/qdb/qdb.pro
+++ b/qdb/qdb.pro
@@ -24,8 +24,10 @@ HEADERS += \
server/hostserver.h \
server/hostservlet.h \
server/logging.h \
- server/networkmanagercontrol.h \
+ server/networkconfigurationservice.h \
+ server/networkconfigurator.h \
server/service.h \
+ server/subnet.h \
server/usb-host/usbcommon.h \
server/usb-host/usbconnection.h \
server/usb-host/usbconnectionreader.h \
@@ -45,8 +47,10 @@ SOURCES += \
server/hostserver.cpp \
server/hostservlet.cpp \
server/logging.cpp \
- server/networkmanagercontrol.cpp \
+ server/networkconfigurationservice.cpp \
+ server/networkconfigurator.cpp \
server/service.cpp \
+ server/subnet.cpp \
server/usb-host/libusbcontext.cpp \
server/usb-host/usbconnection.cpp \
server/usb-host/usbconnectionreader.cpp \
diff --git a/qdb/server/devicemanager.cpp b/qdb/server/devicemanager.cpp
index 57133ea..b468383 100644
--- a/qdb/server/devicemanager.cpp
+++ b/qdb/server/devicemanager.cpp
@@ -20,7 +20,7 @@
******************************************************************************/
#include "devicemanager.h"
-#include "networkmanagercontrol.h"
+#include "networkconfigurator.h"
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
@@ -49,6 +49,13 @@ void DeviceManager::start()
m_deviceEnumerator.startMonitoring();
}
+void DeviceManager::handleDeviceConfigured(UsbDevice device, bool success)
+{
+ qCDebug(devicesC) << "Configured device" << device.serial
+ << (success ? "successfully" : "unsuccessfully");
+ fetchDeviceInformation(device);
+}
+
void DeviceManager::handleDeviceInformation(UsbDevice device, DeviceInformationFetcher::Info info)
{
if (info.hostMac.isEmpty()) {
@@ -56,9 +63,6 @@ void DeviceManager::handleDeviceInformation(UsbDevice device, DeviceInformationF
return; // Discard the device
}
- qCDebug(devicesC) << "Configuring network for" << info.serial;
- configureUsbNetwork(info.serial, info.hostMac);
-
if (info.ipAddress.isEmpty()) {
qCDebug(devicesC) << "Incomplete information received for" << info.serial;
m_incompleteDevices.enqueue(device);
@@ -88,7 +92,7 @@ void DeviceManager::handleDeviceInformation(UsbDevice device, DeviceInformationF
void DeviceManager::handlePluggedInDevice(UsbDevice device)
{
qCDebug(devicesC) << "Device" << device.serial << "plugged in at" << device.address.busNumber << ":" << device.address.deviceAddress;
- fetchDeviceInformation(device);
+ configureDevice(device);
}
void DeviceManager::handleUnpluggedDevice(UsbAddress address)
@@ -116,6 +120,17 @@ void DeviceManager::handleUnpluggedDevice(UsbAddress address)
}
}
+void DeviceManager::configureDevice(UsbDevice device)
+{
+ qCDebug(devicesC) << "Configuring device" << device.serial;
+ auto *configurator = new NetworkConfigurator{&m_pool, device};
+ connect(configurator, &NetworkConfigurator::configured, configurator, &QObject::deleteLater);
+ connect(configurator, &NetworkConfigurator::configured,
+ this, &DeviceManager::handleDeviceConfigured);
+
+ configurator->configure();
+}
+
void DeviceManager::fetchDeviceInformation(UsbDevice device)
{
qCDebug(devicesC) << "Fetching device information for" << device.serial;
diff --git a/qdb/server/devicemanager.h b/qdb/server/devicemanager.h
index 4bd4ecd..e5f52b2 100644
--- a/qdb/server/devicemanager.h
+++ b/qdb/server/devicemanager.h
@@ -50,11 +50,13 @@ signals:
void disconnectedDevice(QString serial);
private slots:
+ void handleDeviceConfigured(UsbDevice device, bool success);
void handleDeviceInformation(UsbDevice device, DeviceInformationFetcher::Info info);
void handlePluggedInDevice(UsbDevice device);
void handleUnpluggedDevice(UsbAddress address);
private:
+ void configureDevice(UsbDevice device);
void fetchDeviceInformation(UsbDevice device);
void fetchIncomplete();
diff --git a/qdb/server/networkconfigurationservice.cpp b/qdb/server/networkconfigurationservice.cpp
new file mode 100644
index 0000000..a052156
--- /dev/null
+++ b/qdb/server/networkconfigurationservice.cpp
@@ -0,0 +1,91 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "networkconfigurationservice.h"
+
+#include "connection.h"
+#include "libqdb/protocol/services.h"
+#include "libqdb/stream.h"
+
+#include <QtCore/qloggingcategory.h>
+
+Q_LOGGING_CATEGORY(configurationC, "qdb.services.networkconfiguration")
+
+NetworkConfigurationService::NetworkConfigurationService(Connection *connection)
+ : m_connection{connection},
+ m_responded{false}
+{
+
+}
+
+NetworkConfigurationService::~NetworkConfigurationService()
+{
+ if (m_stream)
+ m_stream->requestClose();
+}
+
+void NetworkConfigurationService::initialize()
+{
+ connect(m_connection, &Connection::disconnected,
+ this, &NetworkConfigurationService::handleDisconnected);
+ m_connection->createStream(tagBuffer(NetworkConfigurationTag), [=](Stream *stream) {
+ this->streamCreated(stream);
+ });
+}
+
+void NetworkConfigurationService::configure(QString subnet)
+{
+ if (!m_stream) {
+ qCCritical(configurationC)
+ << "No valid stream in NetworkConfigurationService when trying to send";
+ return;
+ }
+ StreamPacket packet;
+ packet << subnet;
+ m_stream->write(packet);
+}
+
+void NetworkConfigurationService::receive(StreamPacket packet)
+{
+ uint32_t value;
+ packet >> value;
+
+ m_responded = true;
+ emit response(value == 1);
+}
+
+void NetworkConfigurationService::onStreamClosed()
+{
+ Service::onStreamClosed();
+ failedResponse();
+}
+
+void NetworkConfigurationService::handleDisconnected()
+{
+ failedResponse();
+}
+
+void NetworkConfigurationService::failedResponse()
+{
+ if (!m_responded) {
+ emit response(false);
+ m_responded = true;
+ }
+}
diff --git a/qdb/server/networkconfigurationservice.h b/qdb/server/networkconfigurationservice.h
new file mode 100644
index 0000000..acdb513
--- /dev/null
+++ b/qdb/server/networkconfigurationservice.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef NETWORKCONFIGURATIONSERVICE_H
+#define NETWORKCONFIGURATIONSERVICE_H
+
+#include "service.h"
+class Connection;
+
+class NetworkConfigurationService : public Service
+{
+ Q_OBJECT
+public:
+ explicit NetworkConfigurationService(Connection *connection);
+ ~NetworkConfigurationService();
+
+ void initialize() override;
+
+ void configure(QString subnet);
+
+signals:
+ void response(bool success);
+
+public slots:
+ void receive(StreamPacket packet) override;
+
+protected slots:
+ void onStreamClosed() override;
+
+private:
+ void handleDisconnected();
+ void failedResponse();
+
+ Connection *m_connection;
+ bool m_responded;
+};
+
+#endif // NETWORKCONFIGURATIONSERVICE_H
diff --git a/qdb/server/networkconfigurator.cpp b/qdb/server/networkconfigurator.cpp
new file mode 100644
index 0000000..f8dffb4
--- /dev/null
+++ b/qdb/server/networkconfigurator.cpp
@@ -0,0 +1,78 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "networkconfigurator.h"
+
+#include "connection.h"
+#include "connectionpool.h"
+#include "networkconfigurationservice.h"
+#include "subnet.h"
+
+#include <QtCore/qloggingcategory.h>
+
+Q_LOGGING_CATEGORY(configuratorC, "qdb.networkconfiguration")
+
+NetworkConfigurator::NetworkConfigurator(ConnectionPool *pool, UsbDevice device)
+ : m_connection{pool->connect(device)},
+ m_device(device) // uniform initialization with {} fails in MSVC 2013 with error C2797
+{
+
+}
+
+void NetworkConfigurator::configure()
+{
+ if (!m_connection || m_connection->state() == ConnectionState::Disconnected) {
+ qCWarning(configuratorC) << "Could not configure device" << m_device.serial
+ << "due to no connection";
+ emit configured(m_device, false);
+ return;
+ }
+
+ const std::pair<Subnet, bool> configuration = findUnusedSubnet();
+ if (!configuration.second) {
+ qCCritical(configuratorC) << "Could not find a free subnet to use for the network of device"
+ << m_device.serial;
+ emit configured(m_device, false);
+ return;
+ }
+
+ const auto &subnet = configuration.first;
+ const auto subnetString
+ = QString{"%1/%2"}.arg(subnet.address.toString()).arg(subnet.prefixLength);
+
+ qCDebug(configuratorC) << "Using subnet" << subnetString << "for" << m_device.serial;
+
+ auto *service = new NetworkConfigurationService{m_connection.get()};
+
+ connect(this, &NetworkConfigurator::configured,
+ service, &QObject::deleteLater);
+ connect(service, &NetworkConfigurationService::response,
+ this, &NetworkConfigurator::handleResponse);
+ connect(service, &Service::initialized, [=]() {
+ service->configure(subnetString);
+ });
+
+ service->initialize();
+}
+
+void NetworkConfigurator::handleResponse(bool success)
+{
+ emit configured(m_device, success);
+}
diff --git a/qdb/server/networkconfigurator.h b/qdb/server/networkconfigurator.h
new file mode 100644
index 0000000..01eaf74
--- /dev/null
+++ b/qdb/server/networkconfigurator.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef NETWORKCONFIGURATOR_H
+#define NETWORKCONFIGURATOR_H
+
+#include "usb-host/usbdevice.h"
+class Connection;
+class ConnectionPool;
+
+#include <QtCore/qobject.h>
+
+#include <memory>
+#include <vector>
+
+class NetworkConfigurator : public QObject
+{
+ Q_OBJECT
+public:
+ NetworkConfigurator(ConnectionPool *pool, UsbDevice device);
+
+ void configure();
+
+signals:
+ void configured(UsbDevice device, bool success);
+
+private slots:
+ void handleResponse(bool success);
+
+private:
+ std::shared_ptr<Connection> m_connection;
+ UsbDevice m_device;
+};
+
+#endif // NETWORKCONFIGURATOR_H
diff --git a/qdb/server/networkmanagercontrol.cpp b/qdb/server/networkmanagercontrol.cpp
deleted file mode 100644
index 162e620..0000000
--- a/qdb/server/networkmanagercontrol.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/******************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the Qt Debug Bridge.
-**
-** $QT_BEGIN_LICENSE:COMM$
-**
-** 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.
-**
-** $QT_END_LICENSE$
-**
-******************************************************************************/
-#include "networkmanagercontrol.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtDBus>
-
-#include <algorithm>
-
-Q_LOGGING_CATEGORY(networkC, "qdb.network");
-
-using SettingsMap = QMap<QString, QMap<QString, QDBusVariant>>;
-
-const QString networkManagerServiceName = "org.freedesktop.NetworkManager";
-const QString networkManagerObjectPath = "/org/freedesktop/NetworkManager";
-const QString networkManagerInterfaceName = "org.freedesktop.NetworkManager";
-
-QVariant connectionSettings(QDBusConnection &bus, const QDBusObjectPath &connectionPath);
-SettingsMap demarshallSettings(const QDBusArgument &settingsArgument);
-
-void configureUsbNetwork(const QString &serial, const QString &macAddress)
-{
- qCDebug(networkC) << "Configuring network for" << serial << "at" << macAddress;
- NetworkManagerControl networkManager;
- auto deviceResult = networkManager.findNetworkDeviceByMac(macAddress);
- if (!deviceResult.isValid()) {
- qCWarning(networkC) << "Could not find network device" << macAddress;
- return;
- } else {
- const auto networkCard = deviceResult.toString();
- if (networkManager.isActivated(networkCard)) {
- qCDebug(networkC) << networkCard << "is activated";
- if (networkManager.isDeviceUsingLinkLocal(networkCard)) {
- qCInfo(networkC) << networkCard << "is already using a link-local IP";
- return;
- }
- }
- if (!networkManager.activateOrCreateConnection(QDBusObjectPath{networkCard}, serial, macAddress))
- qCWarning(networkC) << "Could not setup network settings for the USB Ethernet interface";
- }
-}
-
-QVariant connectionMac(QDBusConnection &bus, const QDBusObjectPath &connectionPath)
-{
- const auto result = connectionSettings(bus, connectionPath);
-
- if (!result.isValid()) {
- qCWarning(networkC) << "Could not get MAC address for" << connectionPath.path();
- return QVariant{};
- }
- const auto settings = result.value<SettingsMap>();
-
- return settings["802-3-ethernet"]["mac-address"].variant();
-}
-
-QVariant connectionSettings(QDBusConnection &bus, const QDBusObjectPath &connectionPath)
-{
- if (!bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << bus.lastError();
- return QVariant{};
- }
- QDBusInterface connectionInterface{networkManagerServiceName,
- connectionPath.path(),
- networkManagerInterfaceName + ".Settings.Connection",
- bus};
- if (!connectionInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager Connection:" << connectionPath.path() << connectionInterface.lastError();
- return QVariant{};
- }
-
- QDBusMessage result = connectionInterface.call("GetSettings");
- if (result.type() != QDBusMessage::ReplyMessage) {
- qCWarning(networkC) << "Could not get connection settings for" << connectionPath.path() << ":" << result.errorMessage();
- return QVariant{};
- }
- Q_ASSERT(result.arguments().size() == 1);
- auto settingsArgument = result.arguments()[0].value<QDBusArgument>();
- return QVariant::fromValue(demarshallSettings(settingsArgument));
-}
-
-QVariant connectionSettingsFromDevice(QDBusConnection &bus, const QString &devicePath)
-{
- if (!bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << bus.lastError();
- return QVariant{};
- }
- QDBusInterface deviceInterface{networkManagerServiceName,
- devicePath,
- networkManagerInterfaceName + ".Device",
- bus};
- if (!deviceInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager Device:" << devicePath << deviceInterface.lastError();
- return QVariant{};
- }
-
- QDBusMessage result = deviceInterface.call("GetAppliedConnection", 0u);
- if (result.type() != QDBusMessage::ReplyMessage) {
- qCWarning(networkC) << "Could not get connection settings for" << devicePath << ":" << result.errorMessage();
- return QVariant{};
- }
- Q_ASSERT(result.arguments().size() == 2);
- const auto settingsArgument = result.arguments()[0].value<QDBusArgument>();
- return QVariant::fromValue(demarshallSettings(settingsArgument));
-}
-
-SettingsMap demarshallSettings(const QDBusArgument &settingsArgument)
-{
- SettingsMap settings;
- settingsArgument >> settings;
- return settings;
-}
-
-QByteArray macAddressToByteArray(const QString &macAddress)
-{
- QByteArray addressBytes;
- const auto hexs = macAddress.split(":");
- for (auto hex : hexs) {
- bool ok = false;
- addressBytes.append(static_cast<char>(hex.toInt(&ok, 16)));
- Q_ASSERT_X(ok, "macAddressToByteArray", "Invalid MAC address given");
- }
- return addressBytes;
-}
-
-bool settingsUseLinkLocal(const SettingsMap &settings)
-{
- const auto method = settings["ipv4"]["method"].variant().toString();
- return method == "link-local";
-}
-
-NetworkManagerControl::NetworkManagerControl()
- : m_bus{QDBusConnection::systemBus()}
-{
- qDBusRegisterMetaType<QMap<QString, QDBusVariant>>();
- qDBusRegisterMetaType<SettingsMap>();
-}
-
-bool NetworkManagerControl::activateOrCreateConnection(const QDBusObjectPath &devicePath, const QString &serial, const QString &macAddress)
-{
- qCDebug(networkC) << "Activating or creating a connection";
- const auto connectionsResult = findConnectionsByMac(macAddress);
- if (!connectionsResult.isValid()) {
- qCWarning(networkC) << "Could not list NetworkManager connections";
- return false;
- }
- const auto connections = connectionsResult.value<QList<QDBusObjectPath>>();
-
- const auto it = std::find_if(connections.begin(), connections.end(), [this](const QDBusObjectPath path) {
- return this->isConnectionUsingLinkLocal(path.path());
- });
-
- QDBusObjectPath connectionPath;
- if (it != connections.end()) {
- qCDebug(networkC) << "Found existing connection:" << it->path();
- connectionPath = *it;
- } else {
- qCDebug(networkC) << "Creating new connection";
- const auto result = createConnection(serial, macAddress);
- if (!result.isValid()) {
- qCWarning(networkC) << "Could not create a NetworkManager connection for" << macAddress;
- return false;
- }
- connectionPath = result.value<QDBusObjectPath>();
- qCDebug(networkC) << "New connection:" << connectionPath.path();
- }
-
- QDBusInterface networkManagerInterface{networkManagerServiceName,
- networkManagerObjectPath,
- networkManagerInterfaceName,
- m_bus};
-
- if (!networkManagerInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager D-Bus interface:"
- << networkManagerInterface.lastError();
- return false;
- }
-
- const auto response = networkManagerInterface.call("ActivateConnection",
- QVariant::fromValue(connectionPath),
- QVariant::fromValue(devicePath),
- QVariant::fromValue(QDBusObjectPath{"/"}));
-
- if (response.type() != QDBusMessage::ReplyMessage)
- return false;
- qCDebug(networkC) << "Successfully activated" << connectionPath.path();
- return true;
-}
-
-QVariant NetworkManagerControl::createConnection(const QString &serial, const QString &macAddress)
-{
- /*
- * Connection settings have the D-Bus signature a{sa{sv}}.
- * Example of the desired map structure for a new connection:
- * {
- * "connection": {
- * "id": "B2Qt test connection",
- * "type": "802-3-ethernet"
- * },
- * "802-3-ethernet": {
- * "mac-address": [106, 157, 79, 239, 108, 104]
- * },
- * "ipv4": {
- * "method": "link-local"
- * }
- * }
- */
-
- QMap<QString, QDBusVariant> connectionMap;
- connectionMap["id"] = QDBusVariant{QString{"%1 via USB"}.arg(serial)};
- connectionMap["type"] = QDBusVariant{QStringLiteral("802-3-ethernet")};
-
- QMap<QString, QDBusVariant> ethernetMap;
- ethernetMap["mac-address"] = QDBusVariant{macAddressToByteArray(macAddress)};
-
- QMap<QString, QDBusVariant> ipv4Map;
- ipv4Map["method"] = QDBusVariant{"link-local"};
-
- SettingsMap settings;
- settings["connection"] = connectionMap;
- settings["802-3-ethernet"] = ethernetMap;
- settings["ipv4"] = ipv4Map;
-
- if (!m_bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << m_bus.lastError();
- return QVariant{};
- }
-
- QDBusInterface connectionSettingsInterface{networkManagerServiceName,
- networkManagerObjectPath + "/Settings",
- networkManagerInterfaceName + ".Settings",
- m_bus};
-
- if (!connectionSettingsInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager Settings D-Bus interface:"
- << connectionSettingsInterface.lastError();
- return QVariant{};
- }
-
- const QDBusMessage result = connectionSettingsInterface.call("AddConnection",
- QVariant::fromValue(settings));
-
- if (result.type() != QDBusMessage::ReplyMessage)
- return QVariant{};
- Q_ASSERT(result.arguments().size() == 1);
- return result.arguments()[0];
-}
-
-QVariant NetworkManagerControl::findConnectionsByMac(const QString &macAddress)
-{
- if (!m_bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << m_bus.lastError();
- return QVariant{};
- }
-
- QDBusInterface settingsInterface{networkManagerServiceName,
- networkManagerObjectPath + "/Settings",
- networkManagerInterfaceName + ".Settings",
- m_bus};
-
- if (!settingsInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager D-Bus interface:"
- << settingsInterface.lastError();
- return QVariant{};
- }
-
- QVariant result = settingsInterface.property("Connections");
- if (!result.isValid()) {
- qCWarning(networkC) << "Could not fetch the NetworkManager connections via D-Bus" << settingsInterface.lastError();
- return QVariant{};
- }
-
- const auto connections = result.value<QList<QDBusObjectPath>>();
- QList<QDBusObjectPath> matchingConnections;
- std::copy_if(connections.begin(), connections.end(), std::back_inserter(matchingConnections),
- [&](const QDBusObjectPath &path) {
- const auto result = connectionMac(m_bus, path);
- if (!result.isValid())
- return false;
- const auto mac = result.toByteArray();
- return macAddressToByteArray(macAddress) == mac;
- });
- qCDebug(networkC) << "Existing connections for" << macAddress << ":";
- for (const auto &connection : matchingConnections)
- qCDebug(networkC) << " " << connection.path();
- return QVariant::fromValue(matchingConnections);
-}
-
-QVariant NetworkManagerControl::findNetworkDeviceByMac(const QString &macAddress)
-{
- QVariant result = listNetworkDevices();
-
- const auto devices = result.value<QList<QDBusObjectPath>>();
- const auto normalizedMac = macAddress.toUpper();
- for (const auto &device : devices) {
- QDBusInterface wiredDeviceInterface{networkManagerServiceName,
- device.path(),
- networkManagerInterfaceName + ".Device.Wired",
- m_bus};
- if (!wiredDeviceInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager Device:" << device.path() << wiredDeviceInterface.lastError();
- continue;
- }
- QVariant macResult = wiredDeviceInterface.property("HwAddress");
- if (!macResult.isValid()) {
- const auto error = wiredDeviceInterface.lastError();
- // Non-wired devices result into errors due to no MAC address and need not be warned about.
- // For some reason the error type in this case can be either UnknownInterface or InvalidArgs.
- if (error.type() != QDBusError::UnknownInterface && error.type() != QDBusError::InvalidArgs)
- qCWarning(networkC) << "Could not fetch hw address for" << device.path() << error;
- continue;
- }
-
- if (macResult.toString().toUpper() == normalizedMac) {
- qCDebug(networkC) << macAddress << "is" << device.path();
- return device.path();
- }
- }
- return QVariant{};
-}
-
-bool NetworkManagerControl::isActivated(const QString &devicePath)
-{
- if (!m_bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << m_bus.lastError();
- // TODO: separate error value?
- return false;
- }
-
- QDBusInterface deviceInterface{networkManagerServiceName,
- devicePath,
- networkManagerInterfaceName + ".Device",
- m_bus};
- if (!deviceInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager Device:" << devicePath << deviceInterface.lastError();
- // TODO: separate error value?
- return false;
- }
-
- const QVariant result = deviceInterface.property("State");
- if (!result.isValid()) {
- qCWarning(networkC) << "Could not check activation status of " << devicePath
- << "via D-Bus:" << deviceInterface.lastError();
- }
- const auto state = result.toUInt();
-
- // Should match https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMDeviceState
- enum NetworkManagerState {
- NM_DEVICE_STATE_UNKNOWN = 0,
- NM_DEVICE_STATE_UNMANAGED = 10,
- NM_DEVICE_STATE_UNAVAILABLE = 20,
- NM_DEVICE_STATE_DISCONNECTED = 30,
- NM_DEVICE_STATE_PREPARE = 40,
- NM_DEVICE_STATE_CONFIG = 50,
- NM_DEVICE_STATE_NEED_AUTH = 60,
- NM_DEVICE_STATE_IP_CONFIG = 70,
- NM_DEVICE_STATE_IP_CHECK = 80,
- NM_DEVICE_STATE_SECONDARIES = 90,
- NM_DEVICE_STATE_ACTIVATED = 100,
- NM_DEVICE_STATE_DEACTIVATING = 110,
- NM_DEVICE_STATE_FAILED = 120,
- };
-
- switch (state) {
- case NM_DEVICE_STATE_UNKNOWN:
- return false;
- case NM_DEVICE_STATE_UNMANAGED:
- return false;
- case NM_DEVICE_STATE_UNAVAILABLE:
- return false;
- case NM_DEVICE_STATE_DISCONNECTED:
- return false;
- case NM_DEVICE_STATE_PREPARE:
- return true;
- case NM_DEVICE_STATE_CONFIG:
- return true;
- case NM_DEVICE_STATE_NEED_AUTH:
- // Authentication is not needed for our configuration
- return false;
- case NM_DEVICE_STATE_IP_CONFIG:
- return true;
- case NM_DEVICE_STATE_IP_CHECK:
- return true;
- case NM_DEVICE_STATE_SECONDARIES:
- // Secondary devices are not needed for our configuration
- return false;
- case NM_DEVICE_STATE_ACTIVATED:
- return true;
- case NM_DEVICE_STATE_DEACTIVATING:
- return false;
- case NM_DEVICE_STATE_FAILED:
- return false;
- default:
- qCCritical(networkC) << "Unrecognized NetworkManager device state" << state;
- return false;
- }
-}
-
-bool NetworkManagerControl::isConnectionUsingLinkLocal(const QString &connectionPath)
-{
- const QVariant result = connectionSettings(m_bus, QDBusObjectPath{connectionPath});
-
- if (!result.isValid()) {
- // TODO: correct way to handle failure?
- return false;
- }
- const auto settings = result.value<SettingsMap>();
- return settingsUseLinkLocal(settings);
-}
-
-bool NetworkManagerControl::isDeviceUsingLinkLocal(const QString &devicePath)
-{
- const QVariant settingsResult = connectionSettingsFromDevice(m_bus, devicePath);
-
- if (!settingsResult.isValid()) {
- // TODO: correct way to handle failure?
- return false;
- }
-
- const auto settings = settingsResult.value<SettingsMap>();
- return settingsUseLinkLocal(settings);
-}
-
-QVariant NetworkManagerControl::listNetworkDevices()
-{
- if (!m_bus.isConnected()) {
- qCWarning(networkC) << "Could not connect to D-Bus system bus: " << m_bus.lastError();
- return QVariant{};
- }
-
- QDBusInterface networkManagerInterface{networkManagerServiceName,
- networkManagerObjectPath,
- networkManagerInterfaceName,
- m_bus};
-
- if (!networkManagerInterface.isValid()) {
- qCWarning(networkC) << "Could not find NetworkManager D-Bus interface:"
- << networkManagerInterface.lastError();
- return QVariant{};
- }
-
- QVariant result = networkManagerInterface.property("Devices");
- if (!result.isValid()) {
- qCWarning(networkC) << "Could not fetch the NetworkManager devices via D-Bus"
- << networkManagerInterface.lastError();
- }
- return result;
-}
diff --git a/qdb/server/networkmanagercontrol.h b/qdb/server/networkmanagercontrol.h
deleted file mode 100644
index f8add06..0000000
--- a/qdb/server/networkmanagercontrol.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/******************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the Qt Debug Bridge.
-**
-** $QT_BEGIN_LICENSE:COMM$
-**
-** 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.
-**
-** $QT_END_LICENSE$
-**
-******************************************************************************/
-#ifndef NETWORKMANAGERCONTROL_H
-#define NETWORKMANAGERCONTROL_H
-
-#include <QtCore/qvariant.h>
-#include <QtDBus/qdbusconnection.h>
-QT_BEGIN_NAMESPACE
-class QDBusObjectPath;
-QT_END_NAMESPACE
-
-void configureUsbNetwork(const QString &serial, const QString &macAddress);
-
-class NetworkManagerControl
-{
-public:
- NetworkManagerControl();
-
- bool activateOrCreateConnection(const QDBusObjectPath &devicePath, const QString &serial, const QString &macAddress);
- QVariant createConnection(const QString &serial, const QString &macAddress);
- QVariant findConnectionsByMac(const QString &macAddress);
- QVariant findNetworkDeviceByMac(const QString &macAddress);
- bool isActivated(const QString &devicePath);
- bool isConnectionUsingLinkLocal(const QString &connectionPath);
- bool isDeviceUsingLinkLocal(const QString &devicePath);
- QVariant listNetworkDevices();
-
-private:
- QDBusConnection m_bus;
-};
-
-
-#endif // NETWORKMANAGERCONTROL_H
diff --git a/qdb/server/subnet.cpp b/qdb/server/subnet.cpp
new file mode 100644
index 0000000..61c80b8
--- /dev/null
+++ b/qdb/server/subnet.cpp
@@ -0,0 +1,77 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "subnet.h"
+
+#include <QtNetwork/qnetworkinterface.h>
+
+namespace {
+
+std::vector<Subnet> fetchUsedSubnets()
+{
+ std::vector<Subnet> subnets;
+ for (const QNetworkInterface &interface : QNetworkInterface::allInterfaces())
+ for (const QNetworkAddressEntry &entry : interface.addressEntries())
+ subnets.push_back(Subnet{entry.ip(), entry.prefixLength()});
+
+ return subnets;
+}
+
+} // anonymous namespace
+
+std::pair<Subnet, bool> findUnusedSubnet()
+{
+ const std::vector<Subnet> usedSubnets = fetchUsedSubnets();
+ const std::vector<Subnet> candidateSubnets = {{QHostAddress{"172.16.58.1"}, 30},
+ {QHostAddress{"172.17.58.1"}, 30},
+ {QHostAddress{"172.18.58.1"}, 30},
+ {QHostAddress{"172.19.58.1"}, 30},
+ {QHostAddress{"172.20.58.1"}, 30},
+ {QHostAddress{"172.21.58.1"}, 30},
+ {QHostAddress{"172.22.58.1"}, 30},
+ {QHostAddress{"172.23.58.1"}, 30},
+ {QHostAddress{"172.24.58.1"}, 30},
+ {QHostAddress{"172.25.58.1"}, 30},
+ {QHostAddress{"172.26.58.1"}, 30},
+ {QHostAddress{"172.27.58.1"}, 30},
+ {QHostAddress{"172.28.58.1"}, 30},
+ {QHostAddress{"172.29.58.1"}, 30},
+ {QHostAddress{"172.30.58.1"}, 30},
+ {QHostAddress{"172.31.58.1"}, 30},
+ {QHostAddress{"192.168.58.1"}, 30},
+ {QHostAddress{"10.17.20.1"}, 30}};
+ return findUnusedSubnet(candidateSubnets, usedSubnets);
+}
+
+std::pair<Subnet, bool> findUnusedSubnet(const std::vector<Subnet> &candidateSubnets,
+ const std::vector<Subnet> &usedSubnets)
+{
+ for (const Subnet &candidate : candidateSubnets) {
+ auto overlaps = [&candidate](const Subnet &subnet) {
+ // Subnets are defined by prefix masks, so they can't overlap partially.
+ // If there is overlap, one is a subset of the other.
+ return candidate.address.isInSubnet(subnet.address, subnet.prefixLength)
+ || subnet.address.isInSubnet(candidate.address, candidate.prefixLength);
+ };
+ if (std::none_of(usedSubnets.begin(), usedSubnets.end(), overlaps))
+ return std::make_pair(candidate, true);
+ }
+ return std::make_pair(Subnet{}, false);
+}
diff --git a/qdb/server/subnet.h b/qdb/server/subnet.h
new file mode 100644
index 0000000..bc8833d
--- /dev/null
+++ b/qdb/server/subnet.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef SUBNET_H
+#define SUBNET_H
+
+#include <QtNetwork/qhostaddress.h>
+
+struct Subnet
+{
+ QHostAddress address;
+ int prefixLength;
+};
+Q_DECLARE_METATYPE(Subnet)
+
+std::pair<Subnet, bool> findUnusedSubnet();
+std::pair<Subnet, bool> findUnusedSubnet(const std::vector<Subnet> &candidateSubnets,
+ const std::vector<Subnet> &usedSubnets);
+
+#endif // SUBNET_H
diff --git a/qdbd/configuration.cpp b/qdbd/configuration.cpp
index 3a3e825..5703988 100644
--- a/qdbd/configuration.cpp
+++ b/qdbd/configuration.cpp
@@ -32,6 +32,11 @@ QString Configuration::gadgetConfigFsDir()
return s_gadgetConfigFsDir;
}
+QString Configuration::networkScript()
+{
+ return s_networkScript;
+}
+
QString Configuration::rndisFunctionName()
{
return s_rndisFunctionName;
@@ -47,6 +52,11 @@ void Configuration::setGadgetConfigFsDir(const QString &path)
s_gadgetConfigFsDir = QDir::cleanPath(path);
}
+void Configuration::setNetworkScript(const QString &script)
+{
+ s_networkScript = script;
+}
+
void Configuration::setRndisFunctionName(const QString &name)
{
s_rndisFunctionName = name;
@@ -55,3 +65,4 @@ void Configuration::setRndisFunctionName(const QString &name)
QString Configuration::s_functionFsDir = "/dev/usb-ffs/qdb";
QString Configuration::s_gadgetConfigFsDir = "/sys/kernel/config/usb_gadget/g1";
QString Configuration::s_rndisFunctionName = "rndis.usb0";
+QString Configuration::s_networkScript = "b2qt-gadget-network.sh";
diff --git a/qdbd/configuration.h b/qdbd/configuration.h
index 8a4c32f..8433782 100644
--- a/qdbd/configuration.h
+++ b/qdbd/configuration.h
@@ -28,14 +28,17 @@ class Configuration
public:
static QString functionFsDir();
static QString gadgetConfigFsDir();
+ static QString networkScript();
static QString rndisFunctionName();
static void setFunctionFsDir(const QString &path);
static void setGadgetConfigFsDir(const QString &path);
+ static void setNetworkScript(const QString &script);
static void setRndisFunctionName(const QString &name);
private:
static QString s_functionFsDir;
static QString s_gadgetConfigFsDir;
+ static QString s_networkScript;
static QString s_rndisFunctionName;
};
diff --git a/qdbd/createexecutor.cpp b/qdbd/createexecutor.cpp
index d11eb4c..16200af 100644
--- a/qdbd/createexecutor.cpp
+++ b/qdbd/createexecutor.cpp
@@ -22,6 +22,7 @@
#include "echoexecutor.h"
#include "handshakeexecutor.h"
+#include "networkconfigurationexecutor.h"
#include "libqdb/make_unique.h"
#include "libqdb/protocol/services.h"
@@ -39,6 +40,8 @@ std::unique_ptr<Executor> createExecutor(Stream *stream, const QByteArray &tagBu
return make_unique<EchoExecutor>(stream);
case HandshakeTag:
return make_unique<HandshakeExecutor>(stream);
+ case NetworkConfigurationTag:
+ return make_unique<NetworkConfigurationExecutor>(stream);
default:
qCritical("Unknown ServiceTag %d in createExecutor", tag);
return std::unique_ptr<Executor>{};
diff --git a/qdbd/main.cpp b/qdbd/main.cpp
index 5171dad..3c0d9f7 100644
--- a/qdbd/main.cpp
+++ b/qdbd/main.cpp
@@ -33,24 +33,38 @@ int main(int argc, char *argv[])
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationVersion(QString{"%1, based on Qt %2"}.arg(QDB_VERSION).arg(QT_VERSION_STR));
+ const QString ffsKey{"ffs-dir"};
+ const QString gadgetKey{"gadget-configfs-dir"};
+ const QString networkKey{"network-script"};
+ const QString rndisKey{"rndis-function-name"};
+
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
parser.addOption({"debug-transport", "Show each transmitted message"});
parser.addOption({"debug-connection", "Show enqueued messages"});
- parser.addOption({"ffs-dir", "Directory to the USB Function File System endpoints to use", "directory"});
- parser.addOption({"gadget-configfs-dir",
+ parser.addOption({ffsKey,
+ "Directory to the USB Function File System endpoints to use",
+ "directory"});
+ parser.addOption({gadgetKey,
"Location of the configfs gadget configuration (including the gadget name)",
"directory"});
- parser.addOption({"rndis-function-name", "Name of the Function File System function that provides RNDIS", "name"});
+ parser.addOption({networkKey,
+ "Script to run for controlling the network between host and device",
+ "script"});
+ parser.addOption({rndisKey,
+ "Name of the Function File System function that provides RNDIS",
+ "name"});
parser.process(app);
- if (parser.isSet("ffs-dir"))
- Configuration::setFunctionFsDir(parser.value("ffs-dir"));
- if (parser.isSet("gadget-configfs-dir"))
- Configuration::setGadgetConfigFsDir(parser.value("gadget-configfs-dir"));
- if (parser.isSet("rndis-function-name"))
- Configuration::setRndisFunctionName(parser.value("rndis-function-name"));
+ if (parser.isSet(ffsKey))
+ Configuration::setFunctionFsDir(parser.value(ffsKey));
+ if (parser.isSet(gadgetKey))
+ Configuration::setGadgetConfigFsDir(parser.value(gadgetKey));
+ if (parser.isSet(networkKey))
+ Configuration::setNetworkScript(parser.value(networkKey));
+ if (parser.isSet(rndisKey))
+ Configuration::setRndisFunctionName(parser.value(rndisKey));
QString filterRules;
if (!parser.isSet("debug-transport")) {
diff --git a/qdbd/networkconfigurationexecutor.cpp b/qdbd/networkconfigurationexecutor.cpp
new file mode 100644
index 0000000..b3b53c7
--- /dev/null
+++ b/qdbd/networkconfigurationexecutor.cpp
@@ -0,0 +1,70 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "networkconfigurationexecutor.h"
+
+#include "configuration.h"
+#include "libqdb/stream.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qprocess.h>
+
+Q_LOGGING_CATEGORY(configurationC, "qdb.executors.networkconfiguration")
+
+NetworkConfigurationExecutor::NetworkConfigurationExecutor(Stream *stream)
+ : m_stream{stream}
+{
+ if (m_stream)
+ connect(m_stream, &Stream::packetAvailable, this, &Executor::receive);
+}
+
+void NetworkConfigurationExecutor::receive(StreamPacket packet)
+{
+ QString subnetString;
+ packet >> subnetString;
+
+ if (subnetString.isEmpty()) {
+ failedResponse();
+ return;
+ }
+
+ QProcess process;
+ process.start(Configuration::networkScript(), QStringList{"--set", subnetString});
+ process.waitForFinished();
+ if (process.exitCode() != 0) {
+ qCWarning(configurationC) << "Using script to configure the network failed";
+ failedResponse();
+ return;
+ }
+
+ StreamPacket response;
+ uint32_t value = 1u;
+ response << value;
+ m_stream->write(response);
+ qCDebug(configurationC) << "Configured device network to" << subnetString;
+}
+
+void NetworkConfigurationExecutor::failedResponse()
+{
+ StreamPacket response;
+ uint32_t value = 0u;
+ response << value;
+ m_stream->write(response);
+}
diff --git a/qdbd/networkconfigurationexecutor.h b/qdbd/networkconfigurationexecutor.h
new file mode 100644
index 0000000..f3c1c1a
--- /dev/null
+++ b/qdbd/networkconfigurationexecutor.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef NETWORKCONFIGURATIONEXECUTOR_H
+#define NETWORKCONFIGURATIONEXECUTOR_H
+
+#include "executor.h"
+class Stream;
+
+class NetworkConfigurationExecutor : public Executor
+{
+ Q_OBJECT
+public:
+ explicit NetworkConfigurationExecutor(Stream *stream);
+
+public slots:
+ void receive(StreamPacket packet) override;
+
+private:
+ void failedResponse();
+
+ Stream *m_stream;
+};
+
+#endif // NETWORKCONFIGURATIONEXECUTOR_H
diff --git a/qdbd/qdbd.pro b/qdbd/qdbd.pro
index 9295c0d..c4b573a 100644
--- a/qdbd/qdbd.pro
+++ b/qdbd/qdbd.pro
@@ -18,6 +18,7 @@ SOURCES += \
executor.cpp \
handshakeexecutor.cpp \
main.cpp \
+ networkconfigurationexecutor.cpp \
server.cpp \
usb-gadget/usbgadget.cpp \
usb-gadget/usbgadgetreader.cpp \
@@ -29,6 +30,7 @@ HEADERS += \
echoexecutor.h \
executor.h \
handshakeexecutor.h \
+ networkconfigurationexecutor.h \
server.h \
usb-gadget/usbgadget.h \
usb-gadget/usbgadgetreader.h \
diff --git a/tests/tests.pro b/tests/tests.pro
index cbd10df..7de79f3 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -4,6 +4,7 @@ CONFIG += ordered
SUBDIRS = \
tst_qdbmessage.pro \
tst_stream.pro \
+ tst_subnet.pro \
config_libusb10 {
SUBDIRS += \
diff --git a/tests/tst_subnet.cpp b/tests/tst_subnet.cpp
new file mode 100644
index 0000000..5aa36cf
--- /dev/null
+++ b/tests/tst_subnet.cpp
@@ -0,0 +1,100 @@
+/******************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "../qdb/server/subnet.h"
+
+#include <QtCore/qstring.h>
+#include <QtTest>
+
+using Subnets = std::vector<Subnet>;
+
+bool operator==(const Subnet &lhs, const Subnet &rhs)
+{
+ return lhs.address == rhs.address
+ && lhs.prefixLength == rhs.prefixLength;
+}
+
+class tst_Subnet : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void freeSubnets();
+ void freeSubnets_data();
+ void usedSubnets();
+ void usedSubnets_data();
+};
+
+void tst_Subnet::freeSubnets()
+{
+ QFETCH(Subnets, candidates);
+ QFETCH(Subnets, useds);
+
+ const std::pair<Subnet, bool> result = findUnusedSubnet(candidates, useds);
+ QCOMPARE(result.second, true);
+ QCOMPARE(result.first, candidates[0]);
+}
+
+void tst_Subnet::freeSubnets_data()
+{
+ QTest::addColumn<Subnets>("candidates");
+ QTest::addColumn<Subnets>("useds");
+
+ Subnets candidates = {{QHostAddress{"172.31.0.1"}, 30}};
+ Subnets subnets = {{QHostAddress{"10.9.7.70"}, 22}};
+ QTest::newRow("1") << candidates << subnets;
+ subnets = {{QHostAddress{"10.9.7.70"}, 22},
+ {QHostAddress{"10.30.7.0"}, 22}};
+ QTest::newRow("2") << candidates << subnets;
+ candidates = {{QHostAddress{"10.9.7.254"}, 22}};
+ subnets = {{QHostAddress{"10.9.8.1"}, 22}};
+ QTest::newRow("3") << candidates << subnets;
+}
+
+void tst_Subnet::usedSubnets()
+{
+ QFETCH(Subnets, candidates);
+ QFETCH(Subnets, useds);
+
+ const std::pair<Subnet, bool> result = findUnusedSubnet(candidates, useds);
+ QCOMPARE(result.second, false);
+}
+
+void tst_Subnet::usedSubnets_data()
+{
+ QTest::addColumn<Subnets>("candidates");
+ QTest::addColumn<Subnets>("useds");
+
+ Subnets candidates = {{QHostAddress{"10.9.7.0"}, 30}};
+ Subnets subnets = {{QHostAddress{"10.9.4.70"}, 22}};
+ QTest::newRow("1") << candidates << subnets;
+ candidates = {{QHostAddress{"10.0.0.0"}, 8}};
+ subnets = {{QHostAddress{"10.200.100.1"}, 24}};
+ QTest::newRow("2") << candidates << subnets;
+ candidates = {{QHostAddress{"10.9.4.70"}, 22}};
+ subnets = {{QHostAddress{"192.168.12.1"}, 24},
+ {QHostAddress{"172.16.45.1"}, 24},
+ {QHostAddress{"10.9.0.1"}, 16}};
+ QTest::newRow("3") << candidates << subnets;
+}
+
+QTEST_APPLESS_MAIN(tst_Subnet)
+
+#include "tst_subnet.moc"
diff --git a/tests/tst_subnet.pro b/tests/tst_subnet.pro
new file mode 100644
index 0000000..9a5a1bc
--- /dev/null
+++ b/tests/tst_subnet.pro
@@ -0,0 +1,20 @@
+QT -= gui
+QT += network testlib
+
+CONFIG += c++11
+CONFIG += testcase
+
+TARGET = tst_subnet
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+INCLUDEPATH += $$PWD/../
+
+HEADERS += \
+ ../qdb/server/subnet.h \
+
+SOURCES += \
+ ../qdb/server/subnet.cpp \
+ tst_subnet.cpp \