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