1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qnetworkinfo_linux_p.h"
35
36#if !defined(QT_NO_OFONO)
37#include "qofonowrapper_p.h"
38#endif
39
40#include <QtCore/qdir.h>
41#include <QtCore/qfile.h>
42#include <QtCore/qmetaobject.h>
43#include <QtCore/qtextstream.h>
44#include <QtCore/qtimer.h>
45#if !defined(QT_NO_BLUEZ)
46#include <bluetooth/bluetooth.h>
47#include <bluetooth/hci.h>
48#include <bluetooth/hci_lib.h>
49#endif // QT_NO_BLUEZ
50
51#if !defined(QT_NO_UDEV)
52#include <QtCore/qsocketnotifier.h>
53#include <libudev.h>
54#endif // QT_NO_UDEV
55
56#include <math.h>
57#include <sys/ioctl.h>
58#include <sys/types.h>
59#include <sys/socket.h>
60#include <linux/wireless.h>
61#include <unistd.h>
62
63QT_BEGIN_NAMESPACE
64
65Q_GLOBAL_STATIC_WITH_ARGS(const QString, NETWORK_SYSFS_PATH, (QLatin1String("/sys/class/net/")))
66
67Q_GLOBAL_STATIC_WITH_ARGS(const QStringList, WLAN_MASK, (QStringList() << QLatin1String("wlan*") << QLatin1String("wlp*")))
68Q_GLOBAL_STATIC_WITH_ARGS(const QStringList, ETHERNET_MASK, (QStringList() << QLatin1String("eth*") << QLatin1String("usb*") << QLatin1String("enp*")))
69
70QNetworkInfoPrivate::QNetworkInfoPrivate(QNetworkInfo *parent)
71 : QObject(parent)
72 , q_ptr(parent)
73 , watchCurrentNetworkMode(false)
74 , watchNetworkInterfaceCount(false)
75 , watchNetworkSignalStrength(false)
76 , watchNetworkStatus(false)
77 , watchNetworkName(false)
78 , timer(0)
79#if !defined(QT_NO_OFONO)
80 , ofonoWrapper(0)
81#endif
82#if !defined(QT_NO_UDEV)
83 , udevNotifier(0)
84 , udevHandle(0)
85 , udevMonitor(0)
86#endif // QT_NO_UDEV
87{
88}
89
90QNetworkInfoPrivate::~QNetworkInfoPrivate()
91{
92#if !defined(QT_NO_UDEV)
93 if (udevMonitor)
94 udev_monitor_unref(udevMonitor);
95
96 if (udevHandle)
97 udev_unref(udevHandle);
98#endif // QT_NO_UDEV
99}
100
101int QNetworkInfoPrivate::networkInterfaceCount(QNetworkInfo::NetworkMode mode)
102{
103 if (watchNetworkInterfaceCount && (mode == QNetworkInfo::WlanMode
104 || mode == QNetworkInfo::EthernetMode
105 || mode == QNetworkInfo::BluetoothMode)) {
106 return networkInterfaceCounts.value(akey: mode);
107 } else
108 return getNetworkInterfaceCount(mode);
109}
110
111int QNetworkInfoPrivate::networkSignalStrength(QNetworkInfo::NetworkMode mode, int interface)
112{
113 if (watchNetworkSignalStrength && (mode == QNetworkInfo::WlanMode
114 || mode == QNetworkInfo::EthernetMode
115 || mode == QNetworkInfo::BluetoothMode)) {
116 return networkSignalStrengths.value(akey: QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
117 } else
118 return getNetworkSignalStrength(mode, interface);
119}
120
121QNetworkInfo::CellDataTechnology QNetworkInfoPrivate::currentCellDataTechnology(int interface)
122{
123#if !defined(QT_NO_OFONO)
124 if (QOfonoWrapper::isOfonoAvailable()) {
125 if (!ofonoWrapper)
126 ofonoWrapper = new QOfonoWrapper(this);
127 QStringList modems = ofonoWrapper->allModems();
128 if (interface < modems.size()) {
129 QString modem = ofonoWrapper->allModems().at(interface);
130 if (!modem.isEmpty())
131 return ofonoWrapper->currentCellDataTechnology(modem);
132 }
133 }
134#else
135 Q_UNUSED(interface)
136#endif
137 return QNetworkInfo::UnknownDataTechnology;
138}
139
140QNetworkInfo::NetworkMode QNetworkInfoPrivate::currentNetworkMode()
141{
142 if (watchCurrentNetworkMode)
143 return currentMode;
144 else
145 return getCurrentNetworkMode();
146}
147
148QNetworkInfo::NetworkStatus QNetworkInfoPrivate::networkStatus(QNetworkInfo::NetworkMode mode, int interface)
149{
150 if (watchNetworkStatus && (mode == QNetworkInfo::WlanMode
151 || mode == QNetworkInfo::EthernetMode
152 || mode == QNetworkInfo::BluetoothMode)) {
153 return networkStatuses.value(akey: QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
154 } else
155 return getNetworkStatus(mode, interface);
156}
157
158#ifndef QT_NO_NETWORKINTERFACE
159QNetworkInterface QNetworkInfoPrivate::interfaceForMode(QNetworkInfo::NetworkMode mode, int interface)
160{
161 switch (mode) {
162 case QNetworkInfo::WlanMode: {
163 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *WLAN_MASK());
164 if (interface < dirs.size()) {
165 QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(name: dirs.at(i: interface));
166 if (networkInterface.isValid())
167 return networkInterface;
168 }
169 break;
170 }
171
172 case QNetworkInfo::EthernetMode: {
173 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *ETHERNET_MASK());
174 if (interface < dirs.size()) {
175 QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(name: dirs.at(i: interface));
176 if (networkInterface.isValid())
177 return networkInterface;
178 }
179 break;
180 }
181
182// case QNetworkInfo::BluetoothMode:
183// case QNetworkInfo::GsmMode:
184// case QNetworkInfo::CdmaMode:
185// case QNetworkInfo::WcdmaMode:
186// case QNetworkInfo::WimaxMode:
187// case QNetworkInfo::LteMode:
188// case QNetworkInfo::TdscdmaMode:
189 default:
190 break;
191 };
192
193 return QNetworkInterface();
194}
195#endif // QT_NO_NETWORKINTERFACE
196
197QString QNetworkInfoPrivate::cellId(int interface)
198{
199#if !defined(QT_NO_OFONO)
200 if (QOfonoWrapper::isOfonoAvailable()) {
201 if (!ofonoWrapper)
202 ofonoWrapper = new QOfonoWrapper(this);
203 QStringList modems = ofonoWrapper->allModems();
204 if (interface < modems.size()) {
205 QString modem = ofonoWrapper->allModems().at(interface);
206 if (!modem.isEmpty())
207 return ofonoWrapper->cellId(modem);
208 }
209 }
210#else
211 Q_UNUSED(interface)
212#endif
213 return QString();
214}
215
216QString QNetworkInfoPrivate::currentMobileCountryCode(int interface)
217{
218#if !defined(QT_NO_OFONO)
219 if (QOfonoWrapper::isOfonoAvailable()) {
220 if (!ofonoWrapper)
221 ofonoWrapper = new QOfonoWrapper(this);
222 QStringList modems = ofonoWrapper->allModems();
223 if (interface < modems.size()) {
224 QString modem = ofonoWrapper->allModems().at(interface);
225 if (!modem.isEmpty())
226 return ofonoWrapper->currentMcc(modem);
227 }
228 }
229#else
230 Q_UNUSED(interface)
231#endif
232 return QString();
233}
234
235QString QNetworkInfoPrivate::currentMobileNetworkCode(int interface)
236{
237#if !defined(QT_NO_OFONO)
238 if (QOfonoWrapper::isOfonoAvailable()) {
239 if (!ofonoWrapper)
240 ofonoWrapper = new QOfonoWrapper(this);
241 QStringList modems = ofonoWrapper->allModems();
242 if (interface < modems.size()) {
243 QString modem = ofonoWrapper->allModems().at(interface);
244 if (!modem.isEmpty())
245 return ofonoWrapper->currentMnc(modem);
246 }
247 }
248#else
249 Q_UNUSED(interface)
250#endif
251 return QString();
252}
253
254QString QNetworkInfoPrivate::homeMobileCountryCode(int interface)
255{
256#if !defined(QT_NO_OFONO)
257 if (QOfonoWrapper::isOfonoAvailable()) {
258 if (!ofonoWrapper)
259 ofonoWrapper = new QOfonoWrapper(this);
260 QStringList modems = ofonoWrapper->allModems();
261 if (interface < modems.size()) {
262 QString modem = ofonoWrapper->allModems().at(interface);
263 if (!modem.isEmpty())
264 return ofonoWrapper->homeMcc(modem);
265 }
266 }
267#else
268 Q_UNUSED(interface)
269#endif
270 return QString();
271}
272
273QString QNetworkInfoPrivate::homeMobileNetworkCode(int interface)
274{
275#if !defined(QT_NO_OFONO)
276 if (QOfonoWrapper::isOfonoAvailable()) {
277 if (!ofonoWrapper)
278 ofonoWrapper = new QOfonoWrapper(this);
279 QStringList modems = ofonoWrapper->allModems();
280 if (interface < modems.size()) {
281 QString modem = ofonoWrapper->allModems().at(interface);
282 if (!modem.isEmpty())
283 return ofonoWrapper->homeMnc(modem);
284 }
285 }
286#else
287 Q_UNUSED(interface)
288#endif
289 return QString();
290}
291
292QString QNetworkInfoPrivate::imsi(int interface)
293{
294#if !defined(QT_NO_OFONO)
295 if (QOfonoWrapper::isOfonoAvailable()) {
296 if (!ofonoWrapper)
297 ofonoWrapper = new QOfonoWrapper(this);
298 QStringList modems = ofonoWrapper->allModems();
299 if (interface < modems.size()) {
300 QString modem = ofonoWrapper->allModems().at(interface);
301 if (!modem.isEmpty())
302 return ofonoWrapper->imsi(modem);
303 }
304 }
305#else
306 Q_UNUSED(interface)
307#endif
308 return QString();
309}
310
311QString QNetworkInfoPrivate::locationAreaCode(int interface)
312{
313#if !defined(QT_NO_OFONO)
314 if (QOfonoWrapper::isOfonoAvailable()) {
315 if (!ofonoWrapper)
316 ofonoWrapper = new QOfonoWrapper(this);
317 QStringList modems = ofonoWrapper->allModems();
318 if (interface < modems.size()) {
319 QString modem = ofonoWrapper->allModems().at(interface);
320 if (!modem.isEmpty())
321 return ofonoWrapper->lac(modem);
322 }
323 }
324#else
325 Q_UNUSED(interface)
326#endif
327 return QString();
328}
329
330QString QNetworkInfoPrivate::macAddress(QNetworkInfo::NetworkMode mode, int interface)
331{
332 switch (mode) {
333 case QNetworkInfo::WlanMode: {
334 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *WLAN_MASK());
335 if (interface < dirs.size()) {
336 QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(i: interface) + QString(QStringLiteral("/address")));
337 if (carrier.open(flags: QIODevice::ReadOnly))
338 return QString::fromLatin1(str: carrier.readAll().simplified().data());
339 }
340 break;
341 }
342
343 case QNetworkInfo::EthernetMode: {
344 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *ETHERNET_MASK());
345 if (interface < dirs.size()) {
346 QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(i: interface) + QString(QStringLiteral("/address")));
347 if (carrier.open(flags: QIODevice::ReadOnly))
348 return QString::fromLatin1(str: carrier.readAll().simplified().data());
349 }
350 break;
351 }
352
353 case QNetworkInfo::BluetoothMode: {
354#if !defined(QT_NO_BLUEZ)
355 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
356 if (ctl < 0)
357 break;
358 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
359 deviceList->dev_num = HCI_MAX_DEV;
360 QString macAddress;
361 if (ioctl(fd: ctl, HCIGETDEVLIST, deviceList) == 0) {
362 int count = deviceList->dev_num;
363 if (interface < count) {
364 struct hci_dev_info deviceInfo;
365 deviceInfo.dev_id = (deviceList->dev_req + interface)->dev_id;
366 if (ioctl(fd: ctl, HCIGETDEVINFO, &deviceInfo) == 0) {
367 // do not use BDADDR_ANY, fails with gcc 4.6
368 bdaddr_t bdaddr_any = (bdaddr_t) {.b: {0, 0, 0, 0, 0, 0}};
369 if (hci_test_bit(nr: HCI_RAW, addr: &deviceInfo.flags) && !bacmp(ba1: &deviceInfo.bdaddr, ba2: &bdaddr_any)) {
370 int hciDevice = hci_open_dev(dev_id: deviceInfo.dev_id);
371 hci_read_bd_addr(dd: hciDevice, bdaddr: &deviceInfo.bdaddr, to: 1000);
372 hci_close_dev(dd: hciDevice);
373 }
374 char address[18];
375 ba2str(ba: &deviceInfo.bdaddr, str: address);
376 macAddress = QString::fromLatin1(str: address);
377 }
378 }
379 }
380 free(ptr: deviceList);
381 close(fd: ctl);
382 return macAddress;
383#else
384 break;
385#endif // QT_NO_BLUEZ
386 }
387
388// case QNetworkInfo::GsmMode:
389// case QNetworkInfo::CdmaMode:
390// case QNetworkInfo::WcdmaMode:
391// case QNetworkInfo::WimaxMode:
392// case QNetworkInfo::LteMode:
393// case QNetworkInfo::TdscdmaMode:
394 default:
395 break;
396 };
397
398 return QString();
399}
400
401QString QNetworkInfoPrivate::networkName(QNetworkInfo::NetworkMode mode, int interface)
402{
403 if (watchNetworkName && (mode == QNetworkInfo::WlanMode
404 || mode == QNetworkInfo::EthernetMode
405 || mode == QNetworkInfo::BluetoothMode)) {
406 return networkNames.value(akey: QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
407 } else
408 return getNetworkName(mode, interface);
409}
410
411extern QMetaMethod proxyToSourceSignal(const QMetaMethod &, QObject *);
412
413void QNetworkInfoPrivate::connectNotify(const QMetaMethod &signal)
414{
415#if !defined(QT_NO_OFONO)
416 if (QOfonoWrapper::isOfonoAvailable()) {
417 if (!ofonoWrapper)
418 ofonoWrapper = new QOfonoWrapper(this);
419 QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
420 connect(ofonoWrapper, sourceSignal, this, signal, Qt::UniqueConnection);
421 }
422#endif
423
424 static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::currentNetworkModeChanged);
425 static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkNameChanged);
426 static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkSignalStrengthChanged);
427 static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkStatusChanged);
428
429 // we always monitor "networkInterfaceCount" , as long as users connect any signals,
430 // with update to date network interface counts, we can compute network mode, strength,
431 // status, name properties in an efficient way
432 if (!watchNetworkInterfaceCount) {
433 QList<QNetworkInfo::NetworkMode> modes;
434 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
435 networkInterfaceCounts.clear();
436 foreach (QNetworkInfo::NetworkMode mode, modes)
437 networkInterfaceCounts[mode] = getNetworkInterfaceCount(mode);
438#if !defined(QT_NO_UDEV)
439 if (!udevHandle) {
440 udevHandle = udev_new();
441 udevMonitor = udev_monitor_new_from_netlink(udevHandle, "udev");
442 udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "net", NULL);
443 udev_monitor_enable_receiving(udevMonitor);
444 udevNotifier = new QSocketNotifier(udev_monitor_get_fd(udevMonitor), QSocketNotifier::Read, this);
445 connect(udevNotifier, SIGNAL(activated(int)), this, SLOT(onUdevChanged()));
446 }
447 udevNotifier->setEnabled(true);
448
449#endif // QT_NO_UDEV
450 watchNetworkInterfaceCount = true;
451 }
452
453 if (signal == currentNetworkModeChangedSignal) {
454// we monitor "networkStatus" by default, as long as currentNetworkModeChanged signal
455// is connected, with always up to date network status, current network mode can
456// be fast computed.
457 if (!watchNetworkStatus) {
458 QList<QNetworkInfo::NetworkMode> modes;
459 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
460 networkStatuses.clear();
461 foreach (QNetworkInfo::NetworkMode mode, modes) {
462 int count = networkInterfaceCount(mode);
463 for (int i = 0; i < count; ++i)
464 networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, interface: i);
465 }
466 watchNetworkStatus = true;
467 }
468 currentMode = getCurrentNetworkMode();
469 watchCurrentNetworkMode = true;
470 } else if (signal == networkSignalStrengthChangedSignal) {
471 QList<QNetworkInfo::NetworkMode> modes;
472 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
473 networkSignalStrengths.clear();
474 foreach (QNetworkInfo::NetworkMode mode, modes) {
475 int count = networkInterfaceCount(mode);
476 for (int i = 0; i < count; ++i)
477 networkSignalStrengths[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkSignalStrength(mode, interface: i);
478 }
479
480 watchNetworkSignalStrength = true;
481 } else if (signal == networkStatusChangedSignal) {
482 QList<QNetworkInfo::NetworkMode> modes;
483 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
484 networkStatuses.clear();
485 foreach (QNetworkInfo::NetworkMode mode, modes) {
486 int count = networkInterfaceCount(mode);
487 for (int i = 0; i < count; ++i)
488 networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, interface: i);
489 }
490
491 watchNetworkStatus = true;
492 } else if (signal == networkNameChangedSignal) {
493 QList<QNetworkInfo::NetworkMode> modes;
494 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
495 networkNames.clear();
496 foreach (QNetworkInfo::NetworkMode mode, modes) {
497 int count = networkInterfaceCount(mode);
498 for (int i = 0; i < count; ++i)
499 networkNames[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkName(mode, interface: i);
500 }
501
502 watchNetworkName = true;
503 } else if (signal == currentNetworkModeChangedSignal) {
504 currentMode = getCurrentNetworkMode();
505 watchCurrentNetworkMode = true;
506 } else {
507 return;
508 }
509
510 if (!timer) {
511 timer = new QTimer(this);
512 timer->setInterval(2000);
513 connect(sender: timer, SIGNAL(timeout()), receiver: this, SLOT(onTimeout()));
514 }
515
516 if (!timer->isActive())
517 timer->start();
518}
519
520void QNetworkInfoPrivate::disconnectNotify(const QMetaMethod &signal)
521{
522#if !defined(QT_NO_OFONO)
523 if (!QOfonoWrapper::isOfonoAvailable() || !ofonoWrapper)
524 return;
525
526 {
527 QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
528 disconnect(ofonoWrapper, sourceSignal, this, signal);
529 }
530#endif
531
532 static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::currentNetworkModeChanged);
533 static const QMetaMethod networkInterfaceCountChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkInterfaceCountChanged);
534 static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkNameChanged);
535 static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkSignalStrengthChanged);
536 static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(signal: &QNetworkInfoPrivate::networkStatusChanged);
537
538 if (signal == networkInterfaceCountChangedSignal
539 && !watchNetworkStatus && !watchNetworkName && !watchNetworkSignalStrength ) {
540#if !defined(QT_NO_UDEV)
541 udevNotifier->setEnabled(false);
542 watchNetworkInterfaceCount = false;
543 return;
544#endif // QT_NO_UDEV
545 watchNetworkInterfaceCount = false;
546 } else if (signal == networkSignalStrengthChangedSignal) {
547 watchNetworkSignalStrength = false;
548 } else if ((!watchCurrentNetworkMode) && (signal == networkStatusChangedSignal)) {
549 watchNetworkStatus = false;
550 } else if (signal == networkNameChangedSignal) {
551 watchNetworkName = false;
552 } else if (signal == currentNetworkModeChangedSignal) {
553 watchCurrentNetworkMode = false;
554 } else {
555 return;
556 }
557
558 if (!watchNetworkInterfaceCount && !watchNetworkSignalStrength && !watchNetworkStatus && !watchNetworkName && !watchCurrentNetworkMode)
559 timer->stop();
560}
561
562#if !defined(QT_NO_UDEV)
563void QNetworkInfoPrivate::onUdevChanged()
564{
565 struct udev_device *udevDevice = udev_monitor_receive_device(udevMonitor);
566 if (!udevDevice)
567 return;
568
569 if (0 != strcmp(udev_device_get_subsystem(udevDevice), "net"))
570 return;
571
572 QString sysname(QString::fromLocal8Bit(udev_device_get_sysname(udevDevice)));
573 if (watchNetworkInterfaceCount) {
574 if (sysname.startsWith(QLatin1String("eth"))
575 || sysname.startsWith(QLatin1String("usb"))
576 || sysname.startsWith(QLatin1String("enp"))) {
577 if (0 == strcmp(udev_device_get_action(udevDevice), "add"))
578 ++networkInterfaceCounts[QNetworkInfo::EthernetMode];
579 else if (0 == strcmp(udev_device_get_action(udevDevice), "remove"))
580 --networkInterfaceCounts[QNetworkInfo::EthernetMode];
581 emit networkInterfaceCountChanged(QNetworkInfo::EthernetMode,
582 networkInterfaceCounts[QNetworkInfo::EthernetMode]);
583 } else if (sysname.startsWith(QLatin1String("wlan")) || sysname.startsWith(QLatin1String("wlp"))) {
584 if (0 == strcmp(udev_device_get_action(udevDevice), "add"))
585 ++networkInterfaceCounts[QNetworkInfo::WlanMode];
586 else if (0 == strcmp(udev_device_get_action(udevDevice), "remove"))
587 --networkInterfaceCounts[QNetworkInfo::WlanMode];
588 emit networkInterfaceCountChanged(QNetworkInfo::WlanMode,
589 networkInterfaceCounts[QNetworkInfo::WlanMode]);
590 }
591 }
592
593 udev_device_unref(udevDevice);
594}
595#endif // QT_NO_UDEV
596
597void QNetworkInfoPrivate::onTimeout()
598{
599#if defined(QT_NO_UDEV)
600 if (watchNetworkInterfaceCount) {
601 QList<QNetworkInfo::NetworkMode> modes;
602 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
603 foreach (QNetworkInfo::NetworkMode mode, modes) {
604 int value = getNetworkInterfaceCount(mode);
605 if (networkInterfaceCounts.value(akey: mode) != value) {
606 networkInterfaceCounts[mode] = value;
607 emit networkInterfaceCountChanged(mode, count: value);
608 }
609 }
610 }
611#endif // QT_NO_UDEV
612
613 if (!watchNetworkSignalStrength && !watchNetworkStatus && !watchNetworkName && !watchCurrentNetworkMode)
614 return;
615
616 QList<QNetworkInfo::NetworkMode> modes;
617 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
618 foreach (QNetworkInfo::NetworkMode mode, modes) {
619 int count = networkInterfaceCount(mode);
620 for (int i = 0; i < count; ++i) {
621 if (watchNetworkSignalStrength) {
622 int value = getNetworkSignalStrength(mode, interface: i);
623 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
624 if (networkSignalStrengths.value(akey: key) != value) {
625 networkSignalStrengths[key] = value;
626 emit networkSignalStrengthChanged(mode, interface: i, strength: value);
627 }
628 }
629
630 if (watchNetworkStatus) {
631 QNetworkInfo::NetworkStatus value = getNetworkStatus(mode, interface: i);
632 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
633 if (networkStatuses.value(akey: key) != value) {
634 networkStatuses[key] = value;
635 emit networkStatusChanged(mode, interface: i, status: value);
636 }
637 }
638
639 if (watchNetworkName) {
640 QString value = getNetworkName(mode, interface: i);
641 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
642 if (networkNames.value(akey: key) != value) {
643 networkNames[key] = value;
644 emit networkNameChanged(mode, interface: i, name: value);
645 }
646 }
647 }
648 }
649
650 if (watchCurrentNetworkMode) {
651 QNetworkInfo::NetworkMode value = getCurrentNetworkMode();
652 if (currentMode != value) {
653 currentMode = value;
654 emit currentNetworkModeChanged(mode: value);
655 }
656 }
657
658}
659
660int QNetworkInfoPrivate::getNetworkInterfaceCount(QNetworkInfo::NetworkMode mode)
661{
662 switch (mode) {
663 case QNetworkInfo::WlanMode:
664 return QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *WLAN_MASK()).size();
665
666 case QNetworkInfo::EthernetMode:
667 return QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *ETHERNET_MASK()).size();
668
669 case QNetworkInfo::BluetoothMode: {
670 int count = -1;
671#if !defined(QT_NO_BLUEZ)
672 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
673 if (ctl < 0)
674 return count;
675 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
676 deviceList->dev_num = HCI_MAX_DEV;
677 if (ioctl(fd: ctl, HCIGETDEVLIST, deviceList) == 0)
678 count = deviceList->dev_num;
679 free(ptr: deviceList);
680 close(fd: ctl);
681#endif // QT_NO_BLUEZ
682 return count;
683 }
684
685 case QNetworkInfo::GsmMode:
686 case QNetworkInfo::CdmaMode:
687 case QNetworkInfo::WcdmaMode:
688 case QNetworkInfo::LteMode:
689 case QNetworkInfo::TdscdmaMode:
690#if !defined(QT_NO_OFONO)
691 if (QOfonoWrapper::isOfonoAvailable()) {
692 if (!ofonoWrapper)
693 ofonoWrapper = new QOfonoWrapper(this);
694 return ofonoWrapper->allModems().size();
695 }
696#endif
697
698// case QNetworkInfo::WimaxMode:
699 default:
700 return -1;
701 };
702}
703
704int QNetworkInfoPrivate::getNetworkSignalStrength(QNetworkInfo::NetworkMode mode, int interface)
705{
706 switch (mode) {
707 case QNetworkInfo::WlanMode: {
708 QFile file(QString(QStringLiteral("/proc/net/wireless")));
709 if (!file.open(flags: QIODevice::ReadOnly | QIODevice::Text))
710 return -1;
711
712 QTextStream in(&file);
713 QString interfaceName = interfaceForMode(mode: QNetworkInfo::WlanMode, interface).name();
714
715 QStringList lines = in.readAll().split(QStringLiteral("\n"));
716 for (int i = 0; i < lines.size(); i++) {
717 QString line = lines.at(i);
718 if (!line.isNull() && line.left(n: 6).contains(s: interfaceName)) {
719 // A typical wireless received signal power over a network falls into the range of (-120, -20),
720 // we shift the dbm value, which is read from the field "Quality - level" in "/proc/net/wireless",
721 // from (-120, -20) to (0, 100) by adding 120. In case of outliers, we restrict them to the
722 // corresponding boundary value.
723 QString token = line.section(in_sep: QString(QStringLiteral(" ")), start: 3, end: 3, flags: QString::SectionSkipEmpty).simplified();
724 token.chop(n: 1);
725 bool ok;
726 int signalStrength = token.toInt(ok: &ok);
727 if (ok) {
728 signalStrength += 120;
729 if (signalStrength > 100)
730 signalStrength = 100;
731 else if (signalStrength < 0)
732 signalStrength = 0;
733 return signalStrength;
734 } else {
735 return -1;
736 }
737 }
738 }
739
740 break;
741 }
742
743 case QNetworkInfo::EthernetMode:
744 if (networkStatus(mode: QNetworkInfo::EthernetMode, interface) == QNetworkInfo::HomeNetwork)
745 return 100;
746 else
747 return -1;
748
749 case QNetworkInfo::GsmMode:
750 case QNetworkInfo::CdmaMode:
751 case QNetworkInfo::WcdmaMode:
752 case QNetworkInfo::LteMode:
753 case QNetworkInfo::TdscdmaMode:
754#if !defined(QT_NO_OFONO)
755 if (QOfonoWrapper::isOfonoAvailable()) {
756 if (!ofonoWrapper)
757 ofonoWrapper = new QOfonoWrapper(this);
758 QStringList modems = ofonoWrapper->allModems();
759 if (interface < modems.size()) {
760 QString modem = ofonoWrapper->allModems().at(interface);
761 if (!modem.isEmpty())
762 return ofonoWrapper->signalStrength(modem);
763 }
764 }
765#endif
766 break;
767
768 case QNetworkInfo::BluetoothMode: {
769 int signalStrength = -1;
770#if !defined(QT_NO_BLUEZ)
771 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
772 if (ctl < 0)
773 break;
774 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
775 deviceList->dev_num = HCI_MAX_DEV;
776 if (ioctl(fd: ctl, HCIGETDEVLIST, deviceList) == 0) {
777 int count = deviceList->dev_num;
778 if (interface < count) {
779 signalStrength = 0; // Valid interface
780
781 struct hci_conn_list_req *connectionList = (struct hci_conn_list_req *)malloc(size: sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
782 connectionList->dev_id = (deviceList->dev_req + interface)->dev_id;
783 connectionList->conn_num = 1;
784 if (ioctl(fd: ctl, HCIGETCONNLIST, connectionList) == 0) {
785 if (connectionList->conn_num == 1) {
786 int fd = hci_open_dev(dev_id: (deviceList->dev_req + interface)->dev_id);
787 if (fd > 0) {
788 struct hci_conn_info_req *connectionInfo = (struct hci_conn_info_req *)malloc(size: sizeof(struct hci_conn_info_req) + sizeof(struct hci_conn_info));
789 bacpy(dst: &connectionInfo->bdaddr, src: &connectionList->conn_info->bdaddr);
790 connectionInfo->type = ACL_LINK;
791 if (ioctl(fd: fd, HCIGETCONNINFO, connectionInfo) == 0) {
792 uint8_t linkQuality;
793 if (hci_read_link_quality(dd: fd, htobs(connectionInfo->conn_info->handle), link_quality: &linkQuality, to: 0) == 0)
794 signalStrength = linkQuality * 100 / 255;
795 }
796 free(ptr: connectionInfo);
797 }
798 }
799 }
800 free (ptr: connectionList);
801 }
802 }
803 free(ptr: deviceList);
804 close(fd: ctl);
805#endif // QT_NO_BLUEZ
806 return signalStrength;
807 }
808
809// case QNetworkInfo::WimaxMode:
810 default:
811 break;
812 };
813
814 return -1;
815}
816
817QNetworkInfo::NetworkMode QNetworkInfoPrivate::getCurrentNetworkMode()
818{
819 // TODO multiple-interface support
820 if (networkStatus(mode: QNetworkInfo::EthernetMode, interface: 0) == QNetworkInfo::HomeNetwork)
821 return QNetworkInfo::EthernetMode;
822 else if (networkStatus(mode: QNetworkInfo::WlanMode, interface: 0) == QNetworkInfo::HomeNetwork)
823 return QNetworkInfo::WlanMode;
824 else if (networkStatus(mode: QNetworkInfo::BluetoothMode, interface: 0) == QNetworkInfo::HomeNetwork)
825 return QNetworkInfo::BluetoothMode;
826 else if (networkStatus(mode: QNetworkInfo::WimaxMode, interface: 0) == QNetworkInfo::HomeNetwork)
827 return QNetworkInfo::WimaxMode;
828 else if (networkStatus(mode: QNetworkInfo::LteMode, interface: 0) == QNetworkInfo::HomeNetwork)
829 return QNetworkInfo::LteMode;
830 else if (networkStatus(mode: QNetworkInfo::WcdmaMode, interface: 0) == QNetworkInfo::HomeNetwork)
831 return QNetworkInfo::WcdmaMode;
832 else if (networkStatus(mode: QNetworkInfo::CdmaMode, interface: 0) == QNetworkInfo::HomeNetwork)
833 return QNetworkInfo::CdmaMode;
834 else if (networkStatus(mode: QNetworkInfo::GsmMode, interface: 0) == QNetworkInfo::HomeNetwork)
835 return QNetworkInfo::GsmMode;
836 else if (networkStatus(mode: QNetworkInfo::TdscdmaMode, interface: 0) == QNetworkInfo::HomeNetwork)
837 return QNetworkInfo::TdscdmaMode;
838 else if (networkStatus(mode: QNetworkInfo::WimaxMode, interface: 0) == QNetworkInfo::Roaming)
839 return QNetworkInfo::WimaxMode;
840 else if (networkStatus(mode: QNetworkInfo::LteMode, interface: 0) == QNetworkInfo::Roaming)
841 return QNetworkInfo::LteMode;
842 else if (networkStatus(mode: QNetworkInfo::WcdmaMode, interface: 0) == QNetworkInfo::Roaming)
843 return QNetworkInfo::WcdmaMode;
844 else if (networkStatus(mode: QNetworkInfo::CdmaMode, interface: 0) == QNetworkInfo::Roaming)
845 return QNetworkInfo::CdmaMode;
846 else if (networkStatus(mode: QNetworkInfo::GsmMode, interface: 0) == QNetworkInfo::Roaming)
847 return QNetworkInfo::GsmMode;
848 else if (networkStatus(mode: QNetworkInfo::TdscdmaMode, interface: 0) == QNetworkInfo::Roaming)
849 return QNetworkInfo::TdscdmaMode;
850 else
851 return QNetworkInfo::UnknownMode;
852}
853
854QNetworkInfo::NetworkStatus QNetworkInfoPrivate::getNetworkStatus(QNetworkInfo::NetworkMode mode, int interface)
855{
856 switch (mode) {
857 case QNetworkInfo::WlanMode: {
858 if (interface < networkInterfaceCount(mode: QNetworkInfo::WlanMode)) {
859 const QString fileName = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *WLAN_MASK()).at(i: interface);
860 QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
861 if (carrier.open(flags: QIODevice::ReadOnly)) {
862 char state;
863 if ((carrier.read(data: &state, maxlen: 1) == 1) &&
864 (state == '1')) {
865 return QNetworkInfo::HomeNetwork;
866 }
867 }
868 }
869 return QNetworkInfo::NoNetworkAvailable;
870 }
871
872 case QNetworkInfo::EthernetMode: {
873 if (interface < networkInterfaceCount(mode: QNetworkInfo::EthernetMode)) {
874 const QString fileName = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *ETHERNET_MASK()).at(i: interface);
875 QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
876 if (carrier.open(flags: QIODevice::ReadOnly)) {
877 char state;
878 if ((carrier.read(data: &state, maxlen: 1) == 1) && (state == '1'))
879 return QNetworkInfo::HomeNetwork;
880 }
881 }
882 return QNetworkInfo::NoNetworkAvailable;
883 }
884
885 case QNetworkInfo::BluetoothMode: {
886 QNetworkInfo::NetworkStatus status = QNetworkInfo::UnknownStatus;
887
888#if !defined(QT_NO_BLUEZ)
889 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
890 if (ctl < 0)
891 break;
892 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
893 deviceList->dev_num = HCI_MAX_DEV;
894 if (ioctl(fd: ctl, HCIGETDEVLIST, deviceList) == 0) {
895 int count = deviceList->dev_num;
896 if (interface < count) {
897 status = QNetworkInfo::NoNetworkAvailable; // Valid interface, so either not connected or connected
898 // TODO add support for searching and denied
899 struct hci_conn_list_req *connectionList = (struct hci_conn_list_req *)malloc(size: sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
900 connectionList->dev_id = (deviceList->dev_req + interface)->dev_id;
901 connectionList->conn_num = 1;
902 if (ioctl(fd: ctl, HCIGETCONNLIST, connectionList) == 0) {
903 if (connectionList->conn_num == 1)
904 status = QNetworkInfo::HomeNetwork;
905 }
906 free (ptr: connectionList);
907 }
908 }
909 free(ptr: deviceList);
910 close(fd: ctl);
911#endif // QT_NO_BLUEZ
912
913 return status;
914 }
915
916 case QNetworkInfo::GsmMode:
917 case QNetworkInfo::CdmaMode:
918 case QNetworkInfo::WcdmaMode:
919 case QNetworkInfo::LteMode:
920 case QNetworkInfo::TdscdmaMode:
921#if !defined(QT_NO_OFONO)
922 if (QOfonoWrapper::isOfonoAvailable()) {
923 if (!ofonoWrapper)
924 ofonoWrapper = new QOfonoWrapper(this);
925 QStringList modems = ofonoWrapper->allModems();
926 if (interface < modems.size()) {
927 QString modem = ofonoWrapper->allModems().at(interface);
928 if (!modem.isEmpty())
929 return ofonoWrapper->networkStatus(modem);
930 }
931 }
932#endif
933 break;
934
935// case QNetworkInfo::WimaxMode:
936 default:
937 break;
938 };
939
940 return QNetworkInfo::UnknownStatus;
941}
942
943QString QNetworkInfoPrivate::getNetworkName(QNetworkInfo::NetworkMode mode, int interface)
944{
945 switch (mode) {
946 case QNetworkInfo::WlanMode: {
947 if (interface < networkInterfaceCount(mode: QNetworkInfo::WlanMode)) {
948 int sock = socket(PF_INET, SOCK_DGRAM, protocol: 0);
949 if (sock > 0) {
950 char buffer[IW_ESSID_MAX_SIZE + 1];
951 iwreq iwInfo;
952
953 iwInfo.u.essid.pointer = (caddr_t)&buffer;
954 iwInfo.u.essid.length = IW_ESSID_MAX_SIZE + 1;
955 iwInfo.u.essid.flags = 0;
956 for (int i = 0; i < WLAN_MASK()->count(); i++) {
957 const QString fileName = QDir(*NETWORK_SYSFS_PATH()).entryList(nameFilters: *WLAN_MASK()).at(i: interface);
958 strncpy(dest: iwInfo.ifr_name, src: fileName.toLocal8Bit().constData(), IFNAMSIZ);
959 if (ioctl(fd: sock, SIOCGIWESSID, &iwInfo) == 0) {
960 close(fd: sock);
961 return QString::fromLatin1(str: (const char *)iwInfo.u.essid.pointer);
962 } else {
963 qDebug() << "ioctl failed";
964 }
965
966 close(fd: sock);
967
968 }
969 }
970 }
971 break;
972 }
973
974 case QNetworkInfo::EthernetMode: {
975 // TODO multiple-interface support
976 char domainName[64];
977 if (getdomainname(name: domainName, len: 64) == 0) {
978 if (strcmp(s1: domainName, s2: "(none)") != 0)
979 return QString::fromLatin1(str: domainName);
980 else
981 return QStringLiteral("Unknown");
982 }
983 break;
984 }
985
986 case QNetworkInfo::BluetoothMode: {
987#if !defined(QT_NO_BLUEZ)
988 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
989 if (ctl < 0)
990 break;
991 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
992 deviceList->dev_num = HCI_MAX_DEV;
993 QString networkName;
994 if (ioctl(fd: ctl, HCIGETDEVLIST, deviceList) == 0) {
995 int count = deviceList->dev_num;
996 if (interface < count) {
997 int fd = hci_open_dev(dev_id: (deviceList->dev_req + interface)->dev_id);
998 if (fd > 0) {
999 char name[249];
1000 if (hci_read_local_name(dd: fd, len: sizeof(name), name, to: 0) == 0)
1001 networkName = QString::fromLatin1(str: name);
1002 }
1003 }
1004 }
1005 free(ptr: deviceList);
1006 close(fd: ctl);
1007 return networkName;
1008#endif // QT_NO_BLUEZ
1009 break;
1010 }
1011
1012 case QNetworkInfo::GsmMode:
1013 case QNetworkInfo::CdmaMode:
1014 case QNetworkInfo::WcdmaMode:
1015 case QNetworkInfo::LteMode:
1016 case QNetworkInfo::TdscdmaMode:
1017#if !defined(QT_NO_OFONO)
1018 if (QOfonoWrapper::isOfonoAvailable()) {
1019 if (!ofonoWrapper)
1020 ofonoWrapper = new QOfonoWrapper(this);
1021 QStringList modems = ofonoWrapper->allModems();
1022 if (interface < modems.size()) {
1023 QString modem = ofonoWrapper->allModems().at(interface);
1024 if (!modem.isEmpty())
1025 return ofonoWrapper->operatorName(modem);
1026 }
1027 }
1028#endif
1029 break;
1030
1031// case QNetworkInfo::WimaxMode:
1032 default:
1033 break;
1034 };
1035
1036 return QString();
1037}
1038
1039QT_END_NAMESPACE
1040

source code of qtsystems/src/systeminfo/linux/qnetworkinfo_linux.cpp