1/*
2 SPDX-FileCopyrightText: 2008, 2010 Will Stephenson <wstephenson@kde.org>
3 SPDX-FileCopyrightText: 2013 Daniel Nicoletti <dantti12@gmail.com>
4 SPDX-FileCopyrightText: 2013 Jan Grulich <jgrulich@redhat.com>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include "connection.h"
10#include "device_p.h"
11#include "manager.h"
12#include "manager_p.h"
13#include "nmdebug.h"
14#include "settings.h"
15
16#include <arpa/inet.h>
17
18#include <QDBusMetaType>
19#include <QDBusObjectPath>
20
21// logging category for this framework, default: log stuff >= warning
22Q_LOGGING_CATEGORY(NMQT, "kf.networkmanagerqt", QtWarningMsg)
23
24namespace NetworkManager
25{
26class DeviceStateReasonPrivate
27{
28public:
29 DeviceStateReasonPrivate(Device::State st, Device::StateChangeReason rsn)
30 : state(st)
31 , reason(rsn)
32 {
33 }
34 DeviceStateReasonPrivate()
35 : state(Device::UnknownState)
36 , reason(Device::UnknownReason)
37 {
38 }
39 Device::State state;
40 Device::StateChangeReason reason;
41};
42}
43
44NetworkManager::DeviceStateReason::DeviceStateReason(Device::State state, Device::StateChangeReason reason)
45 : d_ptr(new DeviceStateReasonPrivate(state, reason))
46{
47}
48
49NetworkManager::DeviceStateReason::DeviceStateReason(const NetworkManager::DeviceStateReason &other)
50 : d_ptr(new DeviceStateReasonPrivate(*other.d_ptr))
51{
52}
53
54NetworkManager::DeviceStateReason::~DeviceStateReason()
55{
56 delete d_ptr;
57}
58
59NetworkManager::Device::State NetworkManager::DeviceStateReason::state() const
60{
61 Q_D(const DeviceStateReason);
62 return d->state;
63}
64
65NetworkManager::Device::StateChangeReason NetworkManager::DeviceStateReason::reason() const
66{
67 Q_D(const DeviceStateReason);
68 return d->reason;
69}
70
71NetworkManager::DeviceStateReason &NetworkManager::DeviceStateReason::operator=(const NetworkManager::DeviceStateReason &other)
72{
73 if (&other != this) {
74 *d_ptr = *other.d_ptr;
75 }
76 return *this;
77}
78
79NetworkManager::DevicePrivate::DevicePrivate(const QString &path, NetworkManager::Device *q)
80#ifdef NMQT_STATIC
81 : deviceIface(NetworkManagerPrivate::DBUS_SERVICE, path, QDBusConnection::sessionBus())
82#else
83 : deviceIface(NetworkManagerPrivate::DBUS_SERVICE, path, QDBusConnection::systemBus())
84#endif
85 , uni(path)
86 , designSpeed(0)
87 , deviceType(Device::UnknownType)
88 , dhcp4Config(nullptr)
89 , dhcp6Config(nullptr)
90 , mtu(0)
91 , q_ptr(q)
92{
93}
94
95NetworkManager::DevicePrivate::~DevicePrivate()
96{
97}
98
99void NetworkManager::DevicePrivate::init()
100{
101 qDBusRegisterMetaType<UIntList>();
102 qDBusRegisterMetaType<UIntListList>();
103 qDBusRegisterMetaType<IpV6DBusAddress>();
104 qDBusRegisterMetaType<IpV6DBusAddressList>();
105 qDBusRegisterMetaType<IpV6DBusNameservers>();
106 qDBusRegisterMetaType<IpV6DBusRoute>();
107 qDBusRegisterMetaType<IpV6DBusRouteList>();
108 qDBusRegisterMetaType<DeviceDBusStateReason>();
109
110 QDBusConnection::systemBus().connect(service: NetworkManagerPrivate::DBUS_SERVICE,
111 path: uni,
112 interface: NetworkManagerPrivate::FDO_DBUS_PROPERTIES,
113 name: QLatin1String("PropertiesChanged"),
114 receiver: this,
115 SLOT(dbusPropertiesChanged(QString, QVariantMap, QStringList)));
116 QObject::connect(sender: &deviceIface, signal: &OrgFreedesktopNetworkManagerDeviceInterface::StateChanged, context: this, slot: &DevicePrivate::deviceStateChanged);
117
118
119 // The interfaceFlags will return NM_DEVICE_INTERFACE_FLAG_NONE when runtime NM < 1.22
120 // we initialize the interfaceFlags
121 interfaceFlags = NetworkManager::Device::Interfaceflag::None;
122 deviceStatistics = DeviceStatistics::Ptr(new NetworkManager::DeviceStatistics(uni), &QObject::deleteLater);
123
124 // Get all Device's properties at once
125 QVariantMap initialProperties = NetworkManagerPrivate::retrieveInitialProperties(interfaceName: deviceIface.staticInterfaceName(), path: uni);
126 if (!initialProperties.isEmpty()) {
127 propertiesChanged(properties: initialProperties);
128 }
129
130}
131
132NetworkManager::Device::MeteredStatus NetworkManager::DevicePrivate::convertMeteredStatus(uint metered)
133{
134 NetworkManager::Device::MeteredStatus ourMeteredStatus = (NetworkManager::Device::MeteredStatus)metered;
135 return ourMeteredStatus;
136}
137
138NetworkManager::Device::Capabilities NetworkManager::DevicePrivate::convertCapabilities(uint theirCaps)
139{
140 NetworkManager::Device::Capabilities ourCaps = (NetworkManager::Device::Capabilities)theirCaps;
141 return ourCaps;
142}
143
144NetworkManager::Device::Interfaceflags NetworkManager::DevicePrivate::convertInterfaceflags(uint flags)
145{
146 NetworkManager::Device::Interfaceflags ourFlags = static_cast<NetworkManager::Device::Interfaceflags>(flags);
147 return ourFlags;
148}
149
150NetworkManager::Device::State NetworkManager::DevicePrivate::convertState(uint theirState)
151{
152 NetworkManager::Device::State ourState = static_cast<NetworkManager::Device::State>(theirState);
153 return ourState;
154}
155
156NetworkManager::Device::StateChangeReason NetworkManager::DevicePrivate::convertReason(uint theirReason)
157{
158 NetworkManager::Device::StateChangeReason ourReason = (NetworkManager::Device::StateChangeReason)theirReason;
159 return ourReason;
160}
161
162NetworkManager::Device::Type NetworkManager::DevicePrivate::convertType(uint type)
163{
164 // These are identical to NM enums
165 if (type <= NM_DEVICE_TYPE_TEAM) {
166 return (NetworkManager::Device::Type)type;
167 }
168
169 switch (type) {
170 case 16:
171 // NM_DEVICE_TYPE_TUN
172 return NetworkManager::Device::Tun;
173 case 17:
174 // NM_DEVICE_TYPE_IP_TUNNEL
175 return NetworkManager::Device::IpTunnel;
176 case 18:
177 // NM_DEVICE_TYPE_MACVLAN
178 return NetworkManager::Device::MacVlan;
179 case 19:
180 // NM_DEVICE_TYPE_VXLAN
181 return NetworkManager::Device::VxLan;
182 case 20:
183 // NM_DEVICE_TYPE_VETH
184 return NetworkManager::Device::Veth;
185 case 21:
186 // NM_DEVICE_TYPE_MACSEC
187 return NetworkManager::Device::MacSec;
188 case 22:
189 // NM_DEVICE_TYPE_DUMMY
190 return NetworkManager::Device::Dummy;
191 case 23:
192 // NM_DEVICE_TYPE_PPP
193 return NetworkManager::Device::Ppp;
194 case 24:
195 // NM_DEVICE_TYPE_OVS_INTERFACE
196 return NetworkManager::Device::OvsInterface;
197 case 25:
198 // NM_DEVICE_TYPE_OVS_PORT
199 return NetworkManager::Device::OvsPort;
200 case 26:
201 // NM_DEVICE_TYPE_OVS_BRIDGE
202 return NetworkManager::Device::OvsBridge;
203 case 27:
204 // NM_DEVICE_TYPE_WPAN
205 return NetworkManager::Device::Wpan;
206 case 28:
207 // NM_DEVICE_TYPE_6LOWPAN
208 return NetworkManager::Device::Lowpan;
209 case 29:
210 // NM_DEVICE_TYPE_NM_DEVICE_TYPE_WIREGUARD
211 return NetworkManager::Device::WireGuard;
212 case 30:
213 // NM_DEVICE_TYPE_WIFI_P2P
214 return NetworkManager::Device::WifiP2P;
215 }
216
217 return NetworkManager::Device::UnknownType;
218}
219
220NetworkManager::Device::Device(const QString &path, QObject *parent)
221 : QObject(parent)
222 , d_ptr(new DevicePrivate(path, this))
223{
224 Q_D(Device);
225
226 d->init();
227}
228
229NetworkManager::Device::Device(DevicePrivate &dd, QObject *parent)
230 : QObject(parent)
231 , d_ptr(&dd)
232{
233 Q_D(Device);
234
235 d->init();
236}
237
238void NetworkManager::DevicePrivate::propertyChanged(const QString &property, const QVariant &value)
239{
240 Q_Q(Device);
241
242 // qCDebug(NMQT) << property << " - " << value;
243 if (property == QLatin1String("ActiveConnection")) {
244 // FIXME workaround, because NM doesn't Q_EMIT correct value
245 // d->activeConnection = value.value<QDBusObjectPath>.path();
246 activeConnection = deviceIface.activeConnection().path();
247 Q_EMIT q->activeConnectionChanged();
248 } else if (property == QLatin1String("Autoconnect")) {
249 autoconnect = value.toBool();
250 Q_EMIT q->autoconnectChanged();
251 } else if (property == QLatin1String("AvailableConnections")) {
252 QStringList newAvailableConnections;
253 const QList<QDBusObjectPath> availableConnectionsTmp = qdbus_cast<QList<QDBusObjectPath>>(v: value);
254 for (const QDBusObjectPath &availableConnection : availableConnectionsTmp) {
255 newAvailableConnections << availableConnection.path();
256 if (!availableConnections.contains(str: availableConnection.path())) {
257 availableConnections << availableConnection.path();
258 Q_EMIT q->availableConnectionAppeared(connection: availableConnection.path());
259 }
260 }
261 auto it = availableConnections.begin();
262 while (it != availableConnections.end()) {
263 const QString availableConnection = *it;
264 if (!newAvailableConnections.contains(str: availableConnection)) {
265 it = availableConnections.erase(pos: it);
266 Q_EMIT q->availableConnectionDisappeared(connection: availableConnection);
267 } else {
268 ++it;
269 }
270 }
271 Q_EMIT q->availableConnectionChanged();
272 } else if (property == QLatin1String("Capabilities")) {
273 capabilities = NetworkManager::DevicePrivate::convertCapabilities(theirCaps: value.toUInt());
274 Q_EMIT q->capabilitiesChanged();
275 } else if (property == QLatin1String("DeviceType")) {
276 deviceType = convertType(type: value.toUInt());
277 } else if (property == QLatin1String("Dhcp4Config")) {
278 QDBusObjectPath dhcp4ConfigPathTmp = value.value<QDBusObjectPath>();
279 if (dhcp4ConfigPathTmp.path().isNull()) {
280 dhcp4Config.clear();
281 dhcp4ConfigPath.clear();
282 } else if (!dhcp4Config || dhcp4Config->path() != dhcp4ConfigPathTmp.path()) {
283 dhcp4Config.clear();
284 dhcp4ConfigPath = dhcp4ConfigPathTmp.path();
285 }
286 Q_EMIT q->dhcp4ConfigChanged();
287 } else if (property == QLatin1String("Dhcp6Config")) {
288 QDBusObjectPath dhcp6ConfigPathTmp = value.value<QDBusObjectPath>();
289 if (dhcp6ConfigPathTmp.path().isNull()) {
290 dhcp6Config.clear();
291 dhcp6ConfigPath.clear();
292 } else if (!dhcp6Config || dhcp6Config->path() != dhcp6ConfigPathTmp.path()) {
293 dhcp6Config.clear();
294 dhcp6ConfigPath = dhcp6ConfigPathTmp.path();
295 }
296 Q_EMIT q->dhcp6ConfigChanged();
297 } else if (property == QLatin1String("Driver")) {
298 driver = value.toString();
299 Q_EMIT q->driverChanged();
300 } else if (property == QLatin1String("DriverVersion")) {
301 driverVersion = value.toString();
302 Q_EMIT q->driverVersionChanged();
303 } else if (property == QLatin1String("FirmwareMissing")) {
304 firmwareMissing = value.toBool();
305 Q_EMIT q->firmwareMissingChanged();
306 } else if (property == QLatin1String("FirmwareVersion")) {
307 firmwareVersion = value.toString();
308 Q_EMIT q->firmwareVersionChanged();
309 } else if (property == QLatin1String("Interface")) {
310 interfaceName = value.toString();
311 Q_EMIT q->interfaceNameChanged();
312 } else if (property == QLatin1String("InterfaceFlags")) {
313 interfaceFlags = NetworkManager::DevicePrivate::convertInterfaceflags(flags: value.toUInt());
314 Q_EMIT q->interfaceFlagsChanged();
315 } else if (property == QLatin1String("Ip4Address")) {
316 ipV4Address = QHostAddress(ntohl(netlong: value.toUInt()));
317 Q_EMIT q->ipV4AddressChanged();
318 } else if (property == QLatin1String("Ip4Config")) {
319 QDBusObjectPath ip4ConfigObjectPathTmp = value.value<QDBusObjectPath>();
320 if (ip4ConfigObjectPathTmp.path().isNull() || ip4ConfigObjectPathTmp.path() == QLatin1String("/")) {
321 ipV4ConfigPath.clear();
322 } else {
323 ipV4ConfigPath = ip4ConfigObjectPathTmp.path();
324 }
325 ipV4Config = IpConfig();
326 Q_EMIT q->ipV4ConfigChanged();
327 } else if (property == QLatin1String("Ip6Config")) {
328 QDBusObjectPath ip6ConfigObjectPathTmp = value.value<QDBusObjectPath>();
329 if (ip6ConfigObjectPathTmp.path().isNull() || ip6ConfigObjectPathTmp.path() == QLatin1String("/")) {
330 ipV6ConfigPath.clear();
331 } else {
332 ipV6ConfigPath = ip6ConfigObjectPathTmp.path();
333 }
334 ipV6Config = IpConfig();
335 Q_EMIT q->ipV6ConfigChanged();
336 } else if (property == QLatin1String("IpInterface")) {
337 ipInterface = value.toString();
338 Q_EMIT q->ipInterfaceChanged();
339 } else if (property == QLatin1String("Managed")) {
340 managed = value.toBool();
341 Q_EMIT q->managedChanged();
342 } else if (property == QLatin1String("State")) {
343 connectionState = NetworkManager::DevicePrivate::convertState(theirState: value.toUInt());
344 // FIXME NetworkManager 0.9.8 (maybe greater) doesn't
345 // update ActiveConnection when disconnected
346 // This is fixed in NM 73d128bbd17120225bb4986e3f05566f10fab581
347 if (connectionState == NetworkManager::Device::Disconnected && activeConnection != QLatin1String("/")) {
348 activeConnection = QLatin1Char('/');
349 Q_EMIT q->activeConnectionChanged();
350 }
351 Q_EMIT q->connectionStateChanged();
352 } else if (property == QLatin1String("StateReason")) { // just extracting the reason
353 reason = NetworkManager::DevicePrivate::convertReason(theirReason: qdbus_cast<DeviceDBusStateReason>(v: value).reason);
354 Q_EMIT q->stateReasonChanged();
355 } else if (property == QLatin1String("Udi")) {
356 udi = value.toString();
357 Q_EMIT q->udiChanged();
358 } else if (property == QLatin1String("PhysicalPortId")) {
359 physicalPortId = value.toString();
360 Q_EMIT q->physicalPortIdChanged();
361 } else if (property == QLatin1String("Mtu")) {
362 mtu = value.toUInt();
363 Q_EMIT q->mtuChanged();
364 } else if (property == QLatin1String("NmPluginMissing")) {
365 nmPluginMissing = value.toBool();
366 Q_EMIT q->nmPluginMissingChanged(nmPluginMissing);
367 } else if (property == QLatin1String("Metered")) {
368 metered = NetworkManager::DevicePrivate::convertMeteredStatus(metered: value.toUInt());
369 Q_EMIT q->meteredChanged(metered);
370 } else {
371 qCDebug(NMQT) << Q_FUNC_INFO << "Unhandled property" << property;
372 }
373}
374
375NetworkManager::Device::~Device()
376{
377 Q_D(Device);
378 delete d;
379}
380
381QString NetworkManager::Device::uni() const
382{
383 Q_D(const Device);
384 return d->uni;
385}
386
387QString NetworkManager::Device::interfaceName() const
388{
389 Q_D(const Device);
390 return d->interfaceName;
391}
392
393QString NetworkManager::Device::ipInterfaceName() const
394{
395 Q_D(const Device);
396 return d->ipInterface;
397}
398
399QString NetworkManager::Device::driver() const
400{
401 Q_D(const Device);
402 return d->driver;
403}
404
405QString NetworkManager::Device::driverVersion() const
406{
407 Q_D(const Device);
408 return d->driverVersion;
409}
410
411QString NetworkManager::Device::firmwareVersion() const
412{
413 Q_D(const Device);
414 return d->firmwareVersion;
415}
416
417NetworkManager::ActiveConnection::Ptr NetworkManager::Device::activeConnection() const
418{
419 Q_D(const Device);
420 return NetworkManager::findActiveConnection(uni: d->activeConnection);
421}
422
423NetworkManager::Connection::List NetworkManager::Device::availableConnections()
424{
425 Q_D(const Device);
426
427 NetworkManager::Connection::List list;
428 for (const QString &availableConnection : std::as_const(t: d->availableConnections)) {
429 NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(path: availableConnection);
430 if (connection) {
431 list << connection;
432 }
433 }
434
435 return list;
436}
437
438bool NetworkManager::Device::firmwareMissing() const
439{
440 Q_D(const Device);
441 return d->firmwareMissing;
442}
443
444bool NetworkManager::Device::autoconnect() const
445{
446 Q_D(const Device);
447 return d->autoconnect;
448}
449
450void NetworkManager::Device::setAutoconnect(bool autoconnect)
451{
452 Q_D(Device);
453 d->deviceIface.setAutoconnect(autoconnect);
454}
455
456QString NetworkManager::Device::udi() const
457{
458 Q_D(const Device);
459 return d->udi;
460}
461
462QString NetworkManager::Device::physicalPortId() const
463{
464 Q_D(const Device);
465 return d->physicalPortId;
466}
467
468QHostAddress NetworkManager::Device::ipV4Address() const
469{
470 Q_D(const Device);
471 return d->ipV4Address;
472}
473
474NetworkManager::DeviceStateReason NetworkManager::Device::stateReason() const
475{
476 Q_D(const Device);
477 return DeviceStateReason(d->connectionState, d->reason);
478}
479
480NetworkManager::IpConfig NetworkManager::Device::ipV4Config() const
481{
482 Q_D(const Device);
483 if (!d->ipV4Config.isValid() && !d->ipV4ConfigPath.isNull()) {
484 d->ipV4Config.setIPv4Path(d->ipV4ConfigPath);
485 }
486 return d->ipV4Config;
487}
488
489NetworkManager::IpConfig NetworkManager::Device::ipV6Config() const
490{
491 Q_D(const Device);
492 if (!d->ipV6Config.isValid() && !d->ipV6ConfigPath.isNull()) {
493 d->ipV6Config.setIPv6Path(d->ipV6ConfigPath);
494 }
495 return d->ipV6Config;
496}
497
498NetworkManager::Dhcp4Config::Ptr NetworkManager::Device::dhcp4Config() const
499{
500 Q_D(const Device);
501 if (!d->dhcp4Config && !d->dhcp4ConfigPath.isNull()) {
502 d->dhcp4Config = NetworkManager::Dhcp4Config::Ptr(new Dhcp4Config(d->dhcp4ConfigPath), &QObject::deleteLater);
503 }
504 return d->dhcp4Config;
505}
506
507NetworkManager::Dhcp6Config::Ptr NetworkManager::Device::dhcp6Config() const
508{
509 Q_D(const Device);
510 if (!d->dhcp6Config && !d->dhcp6ConfigPath.isNull()) {
511 d->dhcp6Config = NetworkManager::Dhcp6Config::Ptr(new Dhcp6Config(d->dhcp6ConfigPath), &QObject::deleteLater);
512 }
513 return d->dhcp6Config;
514}
515
516bool NetworkManager::Device::isActive() const
517{
518 Q_D(const Device);
519 /* clang-format off */
520 return !(d->connectionState == NetworkManager::Device::Unavailable
521 || d->connectionState == NetworkManager::Device::Unmanaged
522 || d->connectionState == NetworkManager::Device::Disconnected
523 || d->connectionState == NetworkManager::Device::Failed);
524 /* clang-format on */
525}
526
527bool NetworkManager::Device::isValid() const
528{
529 Q_D(const Device);
530 return d->deviceIface.isValid();
531}
532
533bool NetworkManager::Device::managed() const
534{
535 Q_D(const Device);
536 return d->managed;
537}
538
539NetworkManager::Device::Interfaceflags NetworkManager::Device::interfaceFlags() const
540{
541 Q_D(const Device);
542 return d->interfaceFlags;
543}
544
545uint NetworkManager::Device::mtu() const
546{
547 Q_D(const Device);
548 return d->mtu;
549}
550
551bool NetworkManager::Device::nmPluginMissing() const
552{
553 Q_D(const Device);
554 return d->nmPluginMissing;
555}
556
557NetworkManager::Device::MeteredStatus NetworkManager::Device::metered() const
558{
559 Q_D(const Device);
560 return d->metered;
561}
562
563QDBusPendingReply<> NetworkManager::Device::reapplyConnection(const NMVariantMapMap &connection, qulonglong version_id, uint flags)
564{
565 Q_D(Device);
566 return d->deviceIface.Reapply(connection, version_id, flags);
567}
568
569QDBusPendingReply<> NetworkManager::Device::disconnectInterface()
570{
571 Q_D(Device);
572 return d->deviceIface.Disconnect();
573}
574
575QDBusPendingReply<> NetworkManager::Device::deleteInterface()
576{
577 if (NetworkManager::checkVersion(x: 1, y: 0, z: 0)) {
578 Q_D(Device);
579 return d->deviceIface.Delete();
580 } else {
581 return QDBusPendingReply<>();
582 }
583}
584
585NetworkManager::Device::State NetworkManager::Device::state() const
586{
587 Q_D(const Device);
588 return d->connectionState;
589}
590
591int NetworkManager::Device::designSpeed() const
592{
593 Q_D(const Device);
594 return d->designSpeed;
595}
596
597NetworkManager::Device::Capabilities NetworkManager::Device::capabilities() const
598{
599 Q_D(const Device);
600 return d->capabilities;
601}
602
603QVariant NetworkManager::Device::capabilitiesV() const
604{
605 Q_D(const Device);
606 return QVariant(d->capabilities);
607}
608
609NetworkManager::DeviceStatistics::Ptr NetworkManager::Device::deviceStatistics() const
610{
611 Q_D(const Device);
612 return d->deviceStatistics;
613}
614
615void NetworkManager::DevicePrivate::deviceStateChanged(uint newState, uint oldState, uint reason)
616{
617 Q_Q(Device);
618 connectionState = NetworkManager::DevicePrivate::convertState(theirState: newState);
619 reason = NetworkManager::DevicePrivate::convertReason(theirReason: reason);
620
621 Q_EMIT q->stateChanged(newstate: connectionState, oldstate: NetworkManager::DevicePrivate::convertState(theirState: oldState), reason: NetworkManager::DevicePrivate::convertReason(theirReason: reason));
622}
623
624void NetworkManager::DevicePrivate::dbusPropertiesChanged(const QString &interfaceName, const QVariantMap &properties, const QStringList &invalidatedProperties)
625{
626 Q_UNUSED(invalidatedProperties);
627 if (interfaceName.contains(s: QLatin1String("org.freedesktop.NetworkManager.Device"))
628 && interfaceName != QLatin1String("org.freedesktop.NetworkManager.Device.Statistics")) {
629 propertiesChanged(properties);
630 }
631}
632
633void NetworkManager::DevicePrivate::propertiesChanged(const QVariantMap &properties)
634{
635 // qCDebug(NMQT) << Q_FUNC_INFO << properties;
636
637 QVariantMap::const_iterator it = properties.constBegin();
638 while (it != properties.constEnd()) {
639 propertyChanged(property: it.key(), value: it.value());
640 ++it;
641 }
642
643 // FIXME workaround, we need to get a path to updated IPv[46]Config,
644 // because NM doesn't Q_EMIT the updated value when the device is activated
645 // BUG: https://bugzilla.gnome.org/show_bug.cgi?id=725657
646 if (properties.contains(key: QLatin1String("State")) && connectionState == NetworkManager::Device::Activated) {
647 propertyChanged(property: QLatin1String("Ip4Config"), value: QVariant::fromValue<QDBusObjectPath>(value: deviceIface.ip4Config()));
648 propertyChanged(property: QLatin1String("Ip6Config"), value: QVariant::fromValue<QDBusObjectPath>(value: deviceIface.ip6Config()));
649 }
650}
651
652NetworkManager::Device::Type NetworkManager::Device::type() const
653{
654 Q_D(const Device);
655 return d->deviceType;
656}
657
658#include "moc_device.cpp"
659#include "moc_device_p.cpp"
660

source code of networkmanager-qt/src/device.cpp