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 <cmath>
65 #include <linux/wireless.h>
66 #include <sys/ioctl.h>
67 #include <sys/socket.h>
68 #include <sys/types.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 
QNetworkInfoPrivate(QNetworkInfo * parent)78 QNetworkInfoPrivate::QNetworkInfoPrivate(QNetworkInfo *parent)
79     : QObject(parent)
80     , q_ptr(parent)
81 #if !defined(QT_NO_OFONO)
82     , ofonoWrapper(0)
83 #endif
84 #if !defined(QT_NO_UDEV)
85     , udevNotifier(0)
86     , udevHandle(0)
87     , udevMonitor(0)
88 #endif // QT_NO_UDEV
89 {
90 }
91 
~QNetworkInfoPrivate()92 QNetworkInfoPrivate::~QNetworkInfoPrivate()
93 {
94 #if !defined(QT_NO_UDEV)
95     if (udevMonitor)
96         udev_monitor_unref(udevMonitor);
97 
98     if (udevHandle)
99         udev_unref(udevHandle);
100 #endif // QT_NO_UDEV
101 }
102 
networkInterfaceCount(QNetworkInfo::NetworkMode mode)103 int QNetworkInfoPrivate::networkInterfaceCount(QNetworkInfo::NetworkMode mode)
104 {
105     if (watchNetworkInterfaceCount && (mode == QNetworkInfo::WlanMode
106                                        || mode == QNetworkInfo::EthernetMode
107                                        || mode == QNetworkInfo::BluetoothMode)) {
108         return networkInterfaceCounts.value(mode);
109     } else
110         return getNetworkInterfaceCount(mode);
111 }
112 
networkSignalStrength(QNetworkInfo::NetworkMode mode,int interface)113 int QNetworkInfoPrivate::networkSignalStrength(QNetworkInfo::NetworkMode mode, int interface)
114 {
115     if (watchNetworkSignalStrength && (mode == QNetworkInfo::WlanMode
116                                        || mode == QNetworkInfo::EthernetMode
117                                        || mode == QNetworkInfo::BluetoothMode)) {
118         return networkSignalStrengths.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
119     } else
120         return getNetworkSignalStrength(mode, interface);
121 }
122 
currentCellDataTechnology(int interface)123 QNetworkInfo::CellDataTechnology QNetworkInfoPrivate::currentCellDataTechnology(int interface)
124 {
125 #if !defined(QT_NO_OFONO)
126     if (QOfonoWrapper::isOfonoAvailable()) {
127         if (!ofonoWrapper)
128             ofonoWrapper = new QOfonoWrapper(this);
129         QStringList modems = ofonoWrapper->allModems();
130         if (interface < modems.size()) {
131             QString modem = ofonoWrapper->allModems().at(interface);
132             if (!modem.isEmpty())
133                 return ofonoWrapper->currentCellDataTechnology(modem);
134         }
135     }
136 #else
137     Q_UNUSED(interface)
138 #endif
139     return QNetworkInfo::UnknownDataTechnology;
140 }
141 
currentNetworkMode()142 QNetworkInfo::NetworkMode QNetworkInfoPrivate::currentNetworkMode()
143 {
144     if (watchCurrentNetworkMode)
145         return currentMode;
146     else
147         return getCurrentNetworkMode();
148 }
149 
networkStatus(QNetworkInfo::NetworkMode mode,int interface)150 QNetworkInfo::NetworkStatus QNetworkInfoPrivate::networkStatus(QNetworkInfo::NetworkMode mode, int interface)
151 {
152     if (watchNetworkStatus && (mode == QNetworkInfo::WlanMode
153                                || mode == QNetworkInfo::EthernetMode
154                                || mode == QNetworkInfo::BluetoothMode)) {
155         return networkStatuses.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
156     } else
157         return getNetworkStatus(mode, interface);
158 }
159 
160 #ifndef QT_NO_NETWORKINTERFACE
interfaceForMode(QNetworkInfo::NetworkMode mode,int interface)161 QNetworkInterface QNetworkInfoPrivate::interfaceForMode(QNetworkInfo::NetworkMode mode, int interface)
162 {
163     switch (mode) {
164     case QNetworkInfo::WlanMode: {
165         QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK());
166         if (interface < dirs.size()) {
167             QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(dirs.at(interface));
168             if (networkInterface.isValid())
169                 return networkInterface;
170         }
171         break;
172     }
173 
174     case QNetworkInfo::EthernetMode: {
175         QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*ETHERNET_MASK());
176         if (interface < dirs.size()) {
177             QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(dirs.at(interface));
178             if (networkInterface.isValid())
179                 return networkInterface;
180         }
181         break;
182     }
183 
184 //    case QNetworkInfo::BluetoothMode:
185 //    case QNetworkInfo::GsmMode:
186 //    case QNetworkInfo::CdmaMode:
187 //    case QNetworkInfo::WcdmaMode:
188 //    case QNetworkInfo::WimaxMode:
189 //    case QNetworkInfo::LteMode:
190 //    case QNetworkInfo::TdscdmaMode:
191     default:
192         break;
193     };
194 
195     return QNetworkInterface();
196 }
197 #endif // QT_NO_NETWORKINTERFACE
198 
cellId(int interface)199 QString QNetworkInfoPrivate::cellId(int interface)
200 {
201 #if !defined(QT_NO_OFONO)
202     if (QOfonoWrapper::isOfonoAvailable()) {
203         if (!ofonoWrapper)
204             ofonoWrapper = new QOfonoWrapper(this);
205         QStringList modems = ofonoWrapper->allModems();
206         if (interface < modems.size()) {
207             QString modem = ofonoWrapper->allModems().at(interface);
208             if (!modem.isEmpty())
209                 return ofonoWrapper->cellId(modem);
210         }
211     }
212 #else
213     Q_UNUSED(interface)
214 #endif
215     return QString();
216 }
217 
currentMobileCountryCode(int interface)218 QString QNetworkInfoPrivate::currentMobileCountryCode(int interface)
219 {
220 #if !defined(QT_NO_OFONO)
221     if (QOfonoWrapper::isOfonoAvailable()) {
222         if (!ofonoWrapper)
223             ofonoWrapper = new QOfonoWrapper(this);
224         QStringList modems = ofonoWrapper->allModems();
225         if (interface < modems.size()) {
226             QString modem = ofonoWrapper->allModems().at(interface);
227             if (!modem.isEmpty())
228                 return ofonoWrapper->currentMcc(modem);
229         }
230     }
231 #else
232     Q_UNUSED(interface)
233 #endif
234     return QString();
235 }
236 
currentMobileNetworkCode(int interface)237 QString QNetworkInfoPrivate::currentMobileNetworkCode(int interface)
238 {
239 #if !defined(QT_NO_OFONO)
240     if (QOfonoWrapper::isOfonoAvailable()) {
241         if (!ofonoWrapper)
242             ofonoWrapper = new QOfonoWrapper(this);
243         QStringList modems = ofonoWrapper->allModems();
244         if (interface < modems.size()) {
245             QString modem = ofonoWrapper->allModems().at(interface);
246             if (!modem.isEmpty())
247                 return ofonoWrapper->currentMnc(modem);
248         }
249     }
250 #else
251     Q_UNUSED(interface)
252 #endif
253     return QString();
254 }
255 
homeMobileCountryCode(int interface)256 QString QNetworkInfoPrivate::homeMobileCountryCode(int interface)
257 {
258 #if !defined(QT_NO_OFONO)
259     if (QOfonoWrapper::isOfonoAvailable()) {
260         if (!ofonoWrapper)
261             ofonoWrapper = new QOfonoWrapper(this);
262         QStringList modems = ofonoWrapper->allModems();
263         if (interface < modems.size()) {
264             QString modem = ofonoWrapper->allModems().at(interface);
265             if (!modem.isEmpty())
266                 return ofonoWrapper->homeMcc(modem);
267         }
268     }
269 #else
270     Q_UNUSED(interface)
271 #endif
272     return QString();
273 }
274 
homeMobileNetworkCode(int interface)275 QString QNetworkInfoPrivate::homeMobileNetworkCode(int interface)
276 {
277 #if !defined(QT_NO_OFONO)
278     if (QOfonoWrapper::isOfonoAvailable()) {
279         if (!ofonoWrapper)
280             ofonoWrapper = new QOfonoWrapper(this);
281         QStringList modems = ofonoWrapper->allModems();
282         if (interface < modems.size()) {
283             QString modem = ofonoWrapper->allModems().at(interface);
284             if (!modem.isEmpty())
285                 return ofonoWrapper->homeMnc(modem);
286         }
287     }
288 #else
289     Q_UNUSED(interface)
290 #endif
291     return QString();
292 }
293 
imsi(int interface)294 QString QNetworkInfoPrivate::imsi(int interface)
295 {
296 #if !defined(QT_NO_OFONO)
297     if (QOfonoWrapper::isOfonoAvailable()) {
298         if (!ofonoWrapper)
299             ofonoWrapper = new QOfonoWrapper(this);
300         QStringList modems = ofonoWrapper->allModems();
301         if (interface < modems.size()) {
302             QString modem = ofonoWrapper->allModems().at(interface);
303             if (!modem.isEmpty())
304                 return ofonoWrapper->imsi(modem);
305         }
306     }
307 #else
308     Q_UNUSED(interface)
309 #endif
310     return QString();
311 }
312 
locationAreaCode(int interface)313 QString QNetworkInfoPrivate::locationAreaCode(int interface)
314 {
315 #if !defined(QT_NO_OFONO)
316     if (QOfonoWrapper::isOfonoAvailable()) {
317         if (!ofonoWrapper)
318             ofonoWrapper = new QOfonoWrapper(this);
319         QStringList modems = ofonoWrapper->allModems();
320         if (interface < modems.size()) {
321             QString modem = ofonoWrapper->allModems().at(interface);
322             if (!modem.isEmpty())
323                 return ofonoWrapper->lac(modem);
324         }
325     }
326 #else
327     Q_UNUSED(interface)
328 #endif
329     return QString();
330 }
331 
macAddress(QNetworkInfo::NetworkMode mode,int interface)332 QString QNetworkInfoPrivate::macAddress(QNetworkInfo::NetworkMode mode, int interface)
333 {
334     switch (mode) {
335     case QNetworkInfo::WlanMode: {
336         QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK());
337         if (interface < dirs.size()) {
338             QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(interface) + QString(QStringLiteral("/address")));
339             if (carrier.open(QIODevice::ReadOnly))
340                 return QString::fromLatin1(carrier.readAll().simplified().data());
341         }
342         break;
343     }
344 
345     case QNetworkInfo::EthernetMode: {
346         QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*ETHERNET_MASK());
347         if (interface < dirs.size()) {
348             QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(interface) + QString(QStringLiteral("/address")));
349             if (carrier.open(QIODevice::ReadOnly))
350                 return QString::fromLatin1(carrier.readAll().simplified().data());
351         }
352         break;
353     }
354 
355     case QNetworkInfo::BluetoothMode: {
356 #if !defined(QT_NO_BLUEZ)
357         int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
358         if (ctl < 0)
359             break;
360         struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
361         deviceList->dev_num = HCI_MAX_DEV;
362         QString macAddress;
363         if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
364             int count = deviceList->dev_num;
365             if (interface < count) {
366                 struct hci_dev_info deviceInfo;
367                 deviceInfo.dev_id = (deviceList->dev_req + interface)->dev_id;
368                 if (ioctl(ctl, HCIGETDEVINFO, &deviceInfo) == 0) {
369                     // do not use BDADDR_ANY, fails with gcc 4.6
370                     bdaddr_t bdaddr_any = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};
371                     if (hci_test_bit(HCI_RAW, &deviceInfo.flags) && !bacmp(&deviceInfo.bdaddr, &bdaddr_any)) {
372                         int hciDevice = hci_open_dev(deviceInfo.dev_id);
373                         hci_read_bd_addr(hciDevice, &deviceInfo.bdaddr, 1000);
374                         hci_close_dev(hciDevice);
375                     }
376                     char address[18];
377                     ba2str(&deviceInfo.bdaddr, address);
378                     macAddress = QString::fromLatin1(address);
379                 }
380             }
381         }
382         free(deviceList);
383         close(ctl);
384         return macAddress;
385 #else
386         break;
387 #endif // QT_NO_BLUEZ
388     }
389 
390 //    case QNetworkInfo::GsmMode:
391 //    case QNetworkInfo::CdmaMode:
392 //    case QNetworkInfo::WcdmaMode:
393 //    case QNetworkInfo::WimaxMode:
394 //    case QNetworkInfo::LteMode:
395 //    case QNetworkInfo::TdscdmaMode:
396     default:
397         break;
398     };
399 
400     return QString();
401 }
402 
networkName(QNetworkInfo::NetworkMode mode,int interface)403 QString QNetworkInfoPrivate::networkName(QNetworkInfo::NetworkMode mode, int interface)
404 {
405     if (watchNetworkName && (mode == QNetworkInfo::WlanMode
406                              || mode == QNetworkInfo::EthernetMode
407                              || mode == QNetworkInfo::BluetoothMode)) {
408         return networkNames.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
409     } else
410         return getNetworkName(mode, interface);
411 }
412 
413 extern QMetaMethod proxyToSourceSignal(const QMetaMethod &, QObject *);
414 
connectNotify(const QMetaMethod & signal)415 void QNetworkInfoPrivate::connectNotify(const QMetaMethod &signal)
416 {
417 #if !defined(QT_NO_OFONO)
418     if (QOfonoWrapper::isOfonoAvailable()) {
419         if (!ofonoWrapper)
420             ofonoWrapper = new QOfonoWrapper(this);
421         QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
422         connect(ofonoWrapper, sourceSignal, this, signal, Qt::UniqueConnection);
423     }
424 #endif
425 
426     static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::currentNetworkModeChanged);
427     static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkNameChanged);
428     static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkSignalStrengthChanged);
429     static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkStatusChanged);
430 
431     //    we always monitor "networkInterfaceCount" , as long as users connect any signals,
432     //    with update to date network interface counts, we can compute network mode, strength,
433     //    status, name properties in an efficient way
434     if (!watchNetworkInterfaceCount) {
435         QList<QNetworkInfo::NetworkMode> modes;
436         modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
437         networkInterfaceCounts.clear();
438         foreach (QNetworkInfo::NetworkMode mode, modes)
439             networkInterfaceCounts[mode] = getNetworkInterfaceCount(mode);
440 #if !defined(QT_NO_UDEV)
441         if (!udevHandle) {
442             udevHandle = udev_new();
443             udevMonitor = udev_monitor_new_from_netlink(udevHandle, "udev");
444             udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "net", NULL);
445             udev_monitor_enable_receiving(udevMonitor);
446             udevNotifier = new QSocketNotifier(udev_monitor_get_fd(udevMonitor), QSocketNotifier::Read, this);
447             connect(udevNotifier, SIGNAL(activated(int)), this, SLOT(onUdevChanged()));
448         }
449         udevNotifier->setEnabled(true);
450 
451 #endif // QT_NO_UDEV
452         watchNetworkInterfaceCount = true;
453     }
454 
455     if (signal == currentNetworkModeChangedSignal) {
456 //        we monitor "networkStatus" by default, as long as currentNetworkModeChanged signal
457 //        is connected, with always up to date network status, current network mode can
458 //        be fast computed.
459         if (!watchNetworkStatus) {
460             QList<QNetworkInfo::NetworkMode> modes;
461             modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
462             networkStatuses.clear();
463             foreach (QNetworkInfo::NetworkMode mode, modes) {
464                 int count = networkInterfaceCount(mode);
465                 for (int i = 0; i < count; ++i)
466                     networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, i);
467             }
468             watchNetworkStatus = true;
469         }
470         currentMode = getCurrentNetworkMode();
471         watchCurrentNetworkMode = true;
472     } else if (signal == networkSignalStrengthChangedSignal) {
473         QList<QNetworkInfo::NetworkMode> modes;
474         modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
475         networkSignalStrengths.clear();
476         foreach (QNetworkInfo::NetworkMode mode, modes) {
477             int count = networkInterfaceCount(mode);
478             for (int i = 0; i < count; ++i)
479                 networkSignalStrengths[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkSignalStrength(mode, i);
480         }
481 
482         watchNetworkSignalStrength = true;
483     } else if (signal == networkStatusChangedSignal) {
484         QList<QNetworkInfo::NetworkMode> modes;
485         modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
486         networkStatuses.clear();
487         foreach (QNetworkInfo::NetworkMode mode, modes) {
488             int count = networkInterfaceCount(mode);
489             for (int i = 0; i < count; ++i)
490                 networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, i);
491         }
492 
493         watchNetworkStatus = true;
494     } else if (signal == networkNameChangedSignal) {
495         QList<QNetworkInfo::NetworkMode> modes;
496         modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
497         networkNames.clear();
498         foreach (QNetworkInfo::NetworkMode mode, modes) {
499             int count = networkInterfaceCount(mode);
500             for (int i = 0; i < count; ++i)
501                 networkNames[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkName(mode, i);
502         }
503 
504         watchNetworkName = true;
505     } else if (signal == currentNetworkModeChangedSignal) {
506         currentMode = getCurrentNetworkMode();
507         watchCurrentNetworkMode = true;
508     } else {
509         return;
510     }
511 
512     if (!timer) {
513         timer = new QTimer(this);
514         timer->setInterval(2000);
515         connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
516     }
517 
518     if (!timer->isActive())
519         timer->start();
520 }
521 
disconnectNotify(const QMetaMethod & signal)522 void QNetworkInfoPrivate::disconnectNotify(const QMetaMethod &signal)
523 {
524 #if !defined(QT_NO_OFONO)
525     if (!QOfonoWrapper::isOfonoAvailable() || !ofonoWrapper)
526         return;
527 
528     {
529         QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
530         disconnect(ofonoWrapper, sourceSignal, this, signal);
531     }
532 #endif
533 
534     static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::currentNetworkModeChanged);
535     static const QMetaMethod networkInterfaceCountChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkInterfaceCountChanged);
536     static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkNameChanged);
537     static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkSignalStrengthChanged);
538     static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkStatusChanged);
539 
540     if (signal == networkInterfaceCountChangedSignal
541             && !watchNetworkStatus && !watchNetworkName && !watchNetworkSignalStrength ) {
542 #if !defined(QT_NO_UDEV)
543         udevNotifier->setEnabled(false);
544         watchNetworkInterfaceCount = false;
545         return;
546 #endif // QT_NO_UDEV
547         watchNetworkInterfaceCount = false;
548     } else if (signal == networkSignalStrengthChangedSignal) {
549         watchNetworkSignalStrength = false;
550     } else if ((!watchCurrentNetworkMode) && (signal == networkStatusChangedSignal)) {
551         watchNetworkStatus = false;
552     } else if (signal == networkNameChangedSignal) {
553         watchNetworkName = false;
554     } else if (signal == currentNetworkModeChangedSignal) {
555         watchCurrentNetworkMode = false;
556     } else {
557         return;
558     }
559 
560     if (!watchNetworkInterfaceCount && !watchNetworkSignalStrength && !watchNetworkStatus && !watchNetworkName && !watchCurrentNetworkMode)
561         timer->stop();
562 }
563 
564 #if !defined(QT_NO_UDEV)
onUdevChanged()565 void QNetworkInfoPrivate::onUdevChanged()
566 {
567     struct udev_device *udevDevice = udev_monitor_receive_device(udevMonitor);
568     if (!udevDevice)
569         return;
570 
571     if (0 != strcmp(udev_device_get_subsystem(udevDevice), "net"))
572         return;
573 
574     QString sysname(QString::fromLocal8Bit(udev_device_get_sysname(udevDevice)));
575     if (watchNetworkInterfaceCount) {
576         if (sysname.startsWith(QString(QStringLiteral("eth"))) || sysname.startsWith(QString(QStringLiteral("usb")))) {
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(QString(QStringLiteral("wlan")))) {
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 
onTimeout()597 void 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(mode) != value) {
606                 networkInterfaceCounts[mode] = value;
607                 emit networkInterfaceCountChanged(mode, 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, i);
623                 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
624                 if (networkSignalStrengths.value(key) != value) {
625                     networkSignalStrengths[key] = value;
626                     emit networkSignalStrengthChanged(mode, i, value);
627                 }
628             }
629 
630             if (watchNetworkStatus) {
631                 QNetworkInfo::NetworkStatus value = getNetworkStatus(mode, i);
632                 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
633                 if (networkStatuses.value(key) != value) {
634                     networkStatuses[key] = value;
635                     emit networkStatusChanged(mode, i, value);
636                 }
637             }
638 
639             if (watchNetworkName) {
640                 QString value = getNetworkName(mode, i);
641                 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
642                 if (networkNames.value(key) != value) {
643                     networkNames[key] = value;
644                     emit networkNameChanged(mode, i, value);
645                 }
646             }
647         }
648     }
649 
650     if (watchCurrentNetworkMode) {
651         QNetworkInfo::NetworkMode value = getCurrentNetworkMode();
652         if (currentMode != value) {
653             currentMode = value;
654             emit currentNetworkModeChanged(value);
655         }
656     }
657 
658 }
659 
getNetworkInterfaceCount(QNetworkInfo::NetworkMode mode)660 int QNetworkInfoPrivate::getNetworkInterfaceCount(QNetworkInfo::NetworkMode mode)
661 {
662     switch (mode) {
663     case QNetworkInfo::WlanMode:
664         return QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK()).size();
665 
666     case QNetworkInfo::EthernetMode:
667         return QDir(*NETWORK_SYSFS_PATH()).entryList(*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(ctl, HCIGETDEVLIST, deviceList) == 0)
678             count = deviceList->dev_num;
679         free(deviceList);
680         close(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 
getNetworkSignalStrength(QNetworkInfo::NetworkMode mode,int interface)704 int 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(QIODevice::ReadOnly | QIODevice::Text))
710             return -1;
711 
712         QTextStream in(&file);
713         QString interfaceName = interfaceForMode(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(6).contains(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(QString(QStringLiteral(" ")), 3, 3, QString::SectionSkipEmpty).simplified();
724                 token.chop(1);
725                 bool ok;
726                 int signalStrength = token.toInt(&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(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(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(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(ctl, HCIGETCONNLIST, connectionList) == 0) {
785                     if (connectionList->conn_num == 1) {
786                         int fd = hci_open_dev((deviceList->dev_req + interface)->dev_id);
787                         if (fd > 0) {
788                             struct hci_conn_info_req *connectionInfo = (struct hci_conn_info_req *)malloc(sizeof(struct hci_conn_info_req) + sizeof(struct hci_conn_info));
789                             bacpy(&connectionInfo->bdaddr, &connectionList->conn_info->bdaddr);
790                             connectionInfo->type = ACL_LINK;
791                             if (ioctl(fd, HCIGETCONNINFO, connectionInfo) == 0) {
792                                 uint8_t linkQuality;
793                                 if (hci_read_link_quality(fd, htobs(connectionInfo->conn_info->handle), &linkQuality, 0) == 0)
794                                     signalStrength = linkQuality * 100 / 255;
795                             }
796                             free(connectionInfo);
797                         }
798                     }
799                 }
800                 free (connectionList);
801             }
802         }
803         free(deviceList);
804         close(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 
getCurrentNetworkMode()817 QNetworkInfo::NetworkMode QNetworkInfoPrivate::getCurrentNetworkMode()
818 {
819     // TODO multiple-interface support
820     if (networkStatus(QNetworkInfo::EthernetMode, 0) == QNetworkInfo::HomeNetwork)
821         return QNetworkInfo::EthernetMode;
822     else if (networkStatus(QNetworkInfo::WlanMode, 0) == QNetworkInfo::HomeNetwork)
823         return QNetworkInfo::WlanMode;
824     else if (networkStatus(QNetworkInfo::BluetoothMode, 0) == QNetworkInfo::HomeNetwork)
825         return QNetworkInfo::BluetoothMode;
826     else if (networkStatus(QNetworkInfo::WimaxMode, 0) == QNetworkInfo::HomeNetwork)
827         return QNetworkInfo::WimaxMode;
828     else if (networkStatus(QNetworkInfo::LteMode, 0) == QNetworkInfo::HomeNetwork)
829         return QNetworkInfo::LteMode;
830     else if (networkStatus(QNetworkInfo::WcdmaMode, 0) == QNetworkInfo::HomeNetwork)
831         return QNetworkInfo::WcdmaMode;
832     else if (networkStatus(QNetworkInfo::CdmaMode, 0) == QNetworkInfo::HomeNetwork)
833         return QNetworkInfo::CdmaMode;
834     else if (networkStatus(QNetworkInfo::GsmMode, 0) == QNetworkInfo::HomeNetwork)
835         return QNetworkInfo::GsmMode;
836     else if (networkStatus(QNetworkInfo::TdscdmaMode, 0) == QNetworkInfo::HomeNetwork)
837         return QNetworkInfo::TdscdmaMode;
838     else if (networkStatus(QNetworkInfo::WimaxMode, 0) == QNetworkInfo::Roaming)
839         return QNetworkInfo::WimaxMode;
840     else if (networkStatus(QNetworkInfo::LteMode, 0) == QNetworkInfo::Roaming)
841         return QNetworkInfo::LteMode;
842     else if (networkStatus(QNetworkInfo::WcdmaMode, 0) == QNetworkInfo::Roaming)
843         return QNetworkInfo::WcdmaMode;
844     else if (networkStatus(QNetworkInfo::CdmaMode, 0) == QNetworkInfo::Roaming)
845         return QNetworkInfo::CdmaMode;
846     else if (networkStatus(QNetworkInfo::GsmMode, 0) == QNetworkInfo::Roaming)
847         return QNetworkInfo::GsmMode;
848     else if (networkStatus(QNetworkInfo::TdscdmaMode, 0) == QNetworkInfo::Roaming)
849         return QNetworkInfo::TdscdmaMode;
850     else
851         return QNetworkInfo::UnknownMode;
852 }
853 
getNetworkStatus(QNetworkInfo::NetworkMode mode,int interface)854 QNetworkInfo::NetworkStatus QNetworkInfoPrivate::getNetworkStatus(QNetworkInfo::NetworkMode mode, int interface)
855 {
856     switch (mode) {
857     case QNetworkInfo::WlanMode: {
858        if (interface < networkInterfaceCount(QNetworkInfo::WlanMode)) {
859             QString fileName = (*WLAN_MASK()).at(0);
860             fileName.chop(1);
861             fileName.append(QString::number(interface));
862             QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
863             if (carrier.open(QIODevice::ReadOnly)) {
864                 char state;
865                 if ((carrier.read(&state, 1) == 1) &&
866                         (state == '1')) {
867                     return QNetworkInfo::HomeNetwork;
868                 }
869             }
870         }
871         return QNetworkInfo::NoNetworkAvailable;
872     }
873 
874     case QNetworkInfo::EthernetMode: {
875         if (interface < networkInterfaceCount(QNetworkInfo::EthernetMode)) {
876             for (int i = 0; i < (*ETHERNET_MASK()).length(); i++) {
877                 QString fileName = (*ETHERNET_MASK()).at(i);
878                 fileName.chop(1);
879                 fileName.append(QString::number(interface));
880                 QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
881                 if (carrier.open(QIODevice::ReadOnly)) {
882                     char state;
883                     if ((carrier.read(&state, 1) == 1) && (state == '1'))
884                         return QNetworkInfo::HomeNetwork;
885                 }
886             }
887         }
888         return QNetworkInfo::NoNetworkAvailable;
889     }
890 
891     case QNetworkInfo::BluetoothMode: {
892         QNetworkInfo::NetworkStatus status = QNetworkInfo::UnknownStatus;
893 
894 #if !defined(QT_NO_BLUEZ)
895         int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
896         if (ctl < 0)
897             break;
898         struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
899         deviceList->dev_num = HCI_MAX_DEV;
900         if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
901             int count = deviceList->dev_num;
902             if (interface < count) {
903                 status = QNetworkInfo::NoNetworkAvailable; // Valid interface, so either not connected or connected
904                                                            // TODO add support for searching and denied
905                 struct hci_conn_list_req *connectionList = (struct hci_conn_list_req *)malloc(sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
906                 connectionList->dev_id = (deviceList->dev_req + interface)->dev_id;
907                 connectionList->conn_num = 1;
908                 if (ioctl(ctl, HCIGETCONNLIST, connectionList) == 0) {
909                     if (connectionList->conn_num == 1)
910                         status = QNetworkInfo::HomeNetwork;
911                 }
912                 free (connectionList);
913             }
914         }
915         free(deviceList);
916         close(ctl);
917 #endif // QT_NO_BLUEZ
918 
919         return status;
920     }
921 
922     case QNetworkInfo::GsmMode:
923     case QNetworkInfo::CdmaMode:
924     case QNetworkInfo::WcdmaMode:
925     case QNetworkInfo::LteMode:
926     case QNetworkInfo::TdscdmaMode:
927 #if !defined(QT_NO_OFONO)
928         if (QOfonoWrapper::isOfonoAvailable()) {
929             if (!ofonoWrapper)
930                 ofonoWrapper = new QOfonoWrapper(this);
931             QStringList modems = ofonoWrapper->allModems();
932             if (interface < modems.size()) {
933                 QString modem = ofonoWrapper->allModems().at(interface);
934                 if (!modem.isEmpty())
935                     return ofonoWrapper->networkStatus(modem);
936             }
937     }
938 #endif
939         break;
940 
941 //    case QNetworkInfo::WimaxMode:
942     default:
943         break;
944     };
945 
946     return QNetworkInfo::UnknownStatus;
947 }
948 
getNetworkName(QNetworkInfo::NetworkMode mode,int interface)949 QString QNetworkInfoPrivate::getNetworkName(QNetworkInfo::NetworkMode mode, int interface)
950 {
951     switch (mode) {
952     case QNetworkInfo::WlanMode: {
953         if (interface < networkInterfaceCount(QNetworkInfo::WlanMode)) {
954             int sock = socket(PF_INET, SOCK_DGRAM, 0);
955             if (sock > 0) {
956                 char buffer[IW_ESSID_MAX_SIZE + 1];
957                 iwreq iwInfo;
958 
959                 iwInfo.u.essid.pointer = (caddr_t)&buffer;
960                 iwInfo.u.essid.length = IW_ESSID_MAX_SIZE + 1;
961                 iwInfo.u.essid.flags = 0;
962                 QString fileName = (*WLAN_MASK()).at(0);
963                 fileName.chop(1);
964                 fileName.append(QString::number(interface));
965                 strncpy(iwInfo.ifr_name, fileName.toLocal8Bit().constData(), IFNAMSIZ);
966                 if (ioctl(sock, SIOCGIWESSID, &iwInfo) == 0) {
967                     close(sock);
968                     return QString::fromLatin1((const char *)iwInfo.u.essid.pointer);
969                 }
970 
971                 close(sock);
972             }
973         }
974         break;
975     }
976 
977     case QNetworkInfo::EthernetMode: {
978         // TODO multiple-interface support
979         char domainName[64];
980         if (getdomainname(domainName, 64) == 0) {
981             if (strcmp(domainName, "(none)") != 0)
982                 return QString::fromLatin1(domainName);
983         }
984         break;
985     }
986 
987     case QNetworkInfo::BluetoothMode: {
988 #if !defined(QT_NO_BLUEZ)
989         int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
990         if (ctl < 0)
991             break;
992         struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
993         deviceList->dev_num = HCI_MAX_DEV;
994         QString networkName;
995         if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
996             int count = deviceList->dev_num;
997             if (interface < count) {
998                 int fd = hci_open_dev((deviceList->dev_req + interface)->dev_id);
999                 if (fd > 0) {
1000                     char name[249];
1001                     if (hci_read_local_name(fd, sizeof(name), name, 0) == 0)
1002                         networkName = QString::fromLatin1(name);
1003                 }
1004             }
1005         }
1006         free(deviceList);
1007         close(ctl);
1008         return networkName;
1009 #endif // QT_NO_BLUEZ
1010         break;
1011     }
1012 
1013     case QNetworkInfo::GsmMode:
1014     case QNetworkInfo::CdmaMode:
1015     case QNetworkInfo::WcdmaMode:
1016     case QNetworkInfo::LteMode:
1017     case QNetworkInfo::TdscdmaMode:
1018 #if !defined(QT_NO_OFONO)
1019         if (QOfonoWrapper::isOfonoAvailable()) {
1020             if (!ofonoWrapper)
1021                 ofonoWrapper = new QOfonoWrapper(this);
1022             QStringList modems = ofonoWrapper->allModems();
1023             if (interface < modems.size()) {
1024                 QString modem = ofonoWrapper->allModems().at(interface);
1025                 if (!modem.isEmpty())
1026                     return ofonoWrapper->operatorName(modem);
1027             }
1028         }
1029 #endif
1030         break;
1031 
1032 //    case QNetworkInfo::WimaxMode:
1033     default:
1034         break;
1035     };
1036 
1037     return QString();
1038 }
1039 
1040 QT_END_NAMESPACE
1041