File indexing completed on 2024-04-28 11:48:00

0001 /*
0002     SPDX-FileCopyrightText: 2009 Will Stephenson <wstephenson@kde.org>
0003     SPDX-FileCopyrightText: 2012-2013 Jan Grulich <jgrulich@redhat.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include <QRegularExpression>
0009 
0010 #include "time.h"
0011 #include "utils.h"
0012 
0013 QHostAddress NetworkManager::ipv6AddressAsHostAddress(const QByteArray &address)
0014 {
0015     //     Q_ASSERT(address.size() == 16);
0016     Q_IPV6ADDR tmp;
0017     for (int i = 0; i < 16; ++i) {
0018         tmp[i] = address[i];
0019     }
0020     QHostAddress hostaddress(tmp);
0021     Q_ASSERT(hostaddress.protocol() == QAbstractSocket::IPv6Protocol);
0022 
0023     return hostaddress;
0024 }
0025 
0026 QByteArray NetworkManager::ipv6AddressFromHostAddress(const QHostAddress &address)
0027 {
0028     //     Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
0029     Q_IPV6ADDR tmp = address.toIPv6Address();
0030     QByteArray assembledAddress;
0031     assembledAddress.reserve(16);
0032     for (int i = 0; i < 16; ++i) {
0033         assembledAddress.push_back(tmp[i]);
0034     }
0035 
0036     return assembledAddress;
0037 }
0038 
0039 QString NetworkManager::macAddressAsString(const QByteArray &ba)
0040 {
0041     QStringList mac;
0042 
0043     for (int i = 0; i < ba.size(); ++i) {
0044         mac << QString("%1").arg((quint8)ba[i], 2, 16, QLatin1Char('0')).toUpper();
0045     }
0046 
0047     return mac.join(":");
0048 }
0049 
0050 QByteArray NetworkManager::macAddressFromString(const QString &s)
0051 {
0052     const QStringList macStringList = s.split(':');
0053     //     Q_ASSERT(macStringList.size() == 6);
0054     QByteArray ba;
0055     if (!s.isEmpty()) {
0056         ba.resize(6);
0057         int i = 0;
0058 
0059         for (const QString &macPart : macStringList) {
0060             ba[i++] = macPart.toUInt(nullptr, 16);
0061         }
0062     }
0063     return ba;
0064 }
0065 
0066 bool NetworkManager::macAddressIsValid(const QString &macAddress)
0067 {
0068     QRegularExpression macAddressCheck(QStringLiteral("([a-fA-F0-9][a-fA-F0-9]:){5}[0-9a-fA-F][0-9a-fA-F]"));
0069 
0070     return macAddressCheck.match(macAddress).hasMatch();
0071 }
0072 
0073 bool NetworkManager::macAddressIsValid(const QByteArray &macAddress)
0074 {
0075     return macAddressIsValid(macAddressAsString(macAddress));
0076 }
0077 
0078 int NetworkManager::findChannel(int freq)
0079 {
0080     int channel;
0081     if (freq < 2500) {
0082         channel = 0;
0083         int i = 0;
0084         QList<QPair<int, int>> bFreqs = getBFreqs();
0085         while (i < bFreqs.size()) {
0086             if (bFreqs.at(i).second <= freq) {
0087                 channel = bFreqs.at(i).first;
0088             } else {
0089                 break;
0090             }
0091             i++;
0092         }
0093         return channel;
0094     }
0095     channel = 0;
0096     int i = 0;
0097     QList<QPair<int, int>> aFreqs = getAFreqs();
0098     while (i < aFreqs.size()) {
0099         if (aFreqs.at(i).second <= freq) {
0100             channel = aFreqs.at(i).first;
0101         } else {
0102             break;
0103         }
0104         i++;
0105     }
0106 
0107     return channel;
0108 }
0109 
0110 NetworkManager::WirelessSetting::FrequencyBand NetworkManager::findFrequencyBand(int freq)
0111 {
0112     if (freq < 2500) {
0113         return WirelessSetting::Bg;
0114     }
0115 
0116     return WirelessSetting::A;
0117 }
0118 
0119 bool NetworkManager::deviceSupportsApCiphers(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
0120                                              NetworkManager::AccessPoint::WpaFlags apCiphers,
0121                                              WirelessSecurityType type)
0122 {
0123     bool havePair = false;
0124     bool haveGroup = true;
0125 
0126     if (type == NetworkManager::StaticWep) {
0127         havePair = true;
0128     } else {
0129         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep40)) {
0130             havePair = true;
0131         }
0132         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep104)) {
0133             havePair = true;
0134         }
0135         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::PairTkip)) {
0136             havePair = true;
0137         }
0138         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::PairCcmp)) {
0139             havePair = true;
0140         }
0141     }
0142 
0143     if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep40)) {
0144         haveGroup = true;
0145     }
0146     if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep104)) {
0147         haveGroup = true;
0148     }
0149     if (type != StaticWep) {
0150         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupTkip)) {
0151             haveGroup = true;
0152         }
0153         if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupCcmp)) {
0154             haveGroup = true;
0155         }
0156     }
0157 
0158     return (havePair && haveGroup);
0159 }
0160 
0161 // Keep this in sync with NetworkManager/libnm-core/nm-utils.c:nm_utils_security_valid()
0162 bool NetworkManager::securityIsValid(WirelessSecurityType type,
0163                                      NetworkManager::WirelessDevice::Capabilities interfaceCaps,
0164                                      bool haveAp,
0165                                      bool adhoc,
0166                                      NetworkManager::AccessPoint::Capabilities apCaps,
0167                                      NetworkManager::AccessPoint::WpaFlags apWpa,
0168                                      NetworkManager::AccessPoint::WpaFlags apRsn)
0169 {
0170     bool good = true;
0171 
0172     // kDebug() << "type(" << type << ") interfaceCaps(" << interfaceCaps << ") haveAp(" << haveAp << ") adhoc(" << adhoc << ") apCaps(" << apCaps << ") apWpa("
0173     // << apWpa << " apRsn(" << apRsn << ")";
0174 
0175     if (!haveAp) {
0176         if (type == NoneSecurity) {
0177             return true;
0178         }
0179         if ((type == StaticWep) //
0180             || ((type == DynamicWep) && !adhoc) //
0181             || ((type == Leap) && !adhoc)) {
0182             if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) || interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104)) {
0183                 return true;
0184             } else {
0185                 return false;
0186             }
0187         }
0188 
0189         // apCaps.testFlag(Privacy) == true for StaticWep, Leap and DynamicWep
0190         // see libs/internals/wirelessinterfaceconnectionhelpers.cpp
0191 
0192         // TODO: this is not in nm-utils.c
0193         //         if (type == Knm::WirelessSecurity::WpaPsk
0194         //                 || ((type == Knm::WirelessSecurity::WpaEap) && !adhoc)) {
0195         //             if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa) &&
0196         //                 !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
0197         //                 return true;
0198         //             }
0199         //         }
0200         //         if (type == Knm::WirelessSecurity::Wpa2Psk
0201         //                 || ((type == Knm::WirelessSecurity::Wpa2Eap) && !adhoc)) {
0202         //             if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn) &&
0203         //                 !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
0204         //                 return true;
0205         //             }
0206         //         }
0207     }
0208 
0209     switch (type) {
0210     case NoneSecurity:
0211         Q_ASSERT(haveAp);
0212         if (apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
0213             return false;
0214         }
0215         if (apWpa || apRsn) {
0216             return false;
0217         }
0218         break;
0219     case Leap: /* require PRIVACY bit for LEAP? */
0220         if (adhoc) {
0221             return false;
0222         }
0223     /* Fall through */
0224     case StaticWep:
0225         Q_ASSERT(haveAp);
0226         if (!apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
0227             return false;
0228         }
0229         if (apWpa || apRsn) {
0230             if (!deviceSupportsApCiphers(interfaceCaps, apWpa, StaticWep)) {
0231                 if (!deviceSupportsApCiphers(interfaceCaps, apRsn, StaticWep)) {
0232                     return false;
0233                 }
0234             }
0235         }
0236         break;
0237     case DynamicWep:
0238         if (adhoc) {
0239             return false;
0240         }
0241         Q_ASSERT(haveAp);
0242         if (apRsn || !(apCaps.testFlag(NetworkManager::AccessPoint::Privacy))) {
0243             return false;
0244         }
0245         /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
0246         if (apWpa) {
0247             if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
0248                 return false;
0249             }
0250             if (!deviceSupportsApCiphers(interfaceCaps, apWpa, DynamicWep)) {
0251                 return false;
0252             }
0253         }
0254         break;
0255     case WpaPsk:
0256         if (adhoc) {
0257             return false;
0258         }
0259 
0260         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
0261             return false;
0262         }
0263         if (haveAp) {
0264             if (apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
0265                 if (apWpa.testFlag(NetworkManager::AccessPoint::PairTkip) //
0266                     && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip)) {
0267                     return true;
0268                 }
0269                 if (apWpa.testFlag(NetworkManager::AccessPoint::PairCcmp) //
0270                     && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp)) {
0271                     return true;
0272                 }
0273             }
0274             return false;
0275         }
0276         break;
0277     case Wpa2Psk:
0278         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
0279             return false;
0280         }
0281         if (haveAp) {
0282             if (adhoc) {
0283                 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::IBSSRsn)) {
0284                     return false;
0285                 }
0286                 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
0287                     && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp)) {
0288                     return true;
0289                 }
0290             } else {
0291                 if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
0292                     if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
0293                         && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip)) {
0294                         return true;
0295                     }
0296                     if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
0297                         && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp)) {
0298                         return true;
0299                     }
0300                 }
0301             }
0302             return false;
0303         }
0304         break;
0305     case WpaEap:
0306         if (adhoc) {
0307             return false;
0308         }
0309         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
0310             return false;
0311         }
0312         if (haveAp) {
0313             if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
0314                 return false;
0315             }
0316             /* Ensure at least one WPA cipher is supported */
0317             if (!deviceSupportsApCiphers(interfaceCaps, apWpa, WpaEap)) {
0318                 return false;
0319             }
0320         }
0321         break;
0322     case Wpa2Eap:
0323         if (adhoc) {
0324             return false;
0325         }
0326         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
0327             return false;
0328         }
0329         if (haveAp) {
0330             if (!apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
0331                 return false;
0332             }
0333             /* Ensure at least one WPA cipher is supported */
0334             if (!deviceSupportsApCiphers(interfaceCaps, apRsn, Wpa2Eap)) {
0335                 return false;
0336             }
0337         }
0338         break;
0339     case SAE:
0340         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
0341             return false;
0342         }
0343         if (haveAp) {
0344             if (adhoc) {
0345                 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::IBSSRsn)) {
0346                     return false;
0347                 }
0348                 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
0349                     && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp)) {
0350                     return true;
0351                 }
0352             } else {
0353                 if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtSAE)) {
0354                     if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
0355                         && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip)) {
0356                         return true;
0357                     }
0358                     if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
0359                         && interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp)) {
0360                         return true;
0361                     }
0362                 }
0363             }
0364             return false;
0365         }
0366         break;
0367     case Wpa3SuiteB192:
0368         if (adhoc) {
0369             return false;
0370         }
0371         if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
0372             return false;
0373         }
0374         if (haveAp && !apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtEapSuiteB192)) {
0375             return false;
0376         }
0377         break;
0378     default:
0379         good = false;
0380         break;
0381     }
0382 
0383     return good;
0384 }
0385 
0386 NetworkManager::WirelessSecurityType NetworkManager::findBestWirelessSecurity(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
0387                                                                               bool haveAp,
0388                                                                               bool adHoc,
0389                                                                               NetworkManager::AccessPoint::Capabilities apCaps,
0390                                                                               NetworkManager::AccessPoint::WpaFlags apWpa,
0391                                                                               NetworkManager::AccessPoint::WpaFlags apRsn)
0392 {
0393     // The ordering of this list is a pragmatic combination of security level and popularity.
0394     // Therefore static WEP is before LEAP and Dynamic WEP because there is no way to detect
0395     // if an AP is capable of Dynamic WEP and showing Dynamic WEP first would confuse
0396     // Static WEP users.
0397     const QList<NetworkManager::WirelessSecurityType> types = {NetworkManager::Wpa3SuiteB192,
0398                                                                NetworkManager::SAE,
0399                                                                NetworkManager::Wpa2Eap,
0400                                                                NetworkManager::Wpa2Psk,
0401                                                                NetworkManager::WpaEap,
0402                                                                NetworkManager::WpaPsk,
0403                                                                NetworkManager::StaticWep,
0404                                                                NetworkManager::DynamicWep,
0405                                                                NetworkManager::Leap,
0406                                                                NetworkManager::NoneSecurity};
0407 
0408     for (NetworkManager::WirelessSecurityType type : types) {
0409         if (NetworkManager::securityIsValid(type, interfaceCaps, haveAp, adHoc, apCaps, apWpa, apRsn)) {
0410             return type;
0411         }
0412     }
0413     return NetworkManager::UnknownSecurity;
0414 }
0415 
0416 bool NetworkManager::wepKeyIsValid(const QString &key, NetworkManager::WirelessSecuritySetting::WepKeyType type)
0417 {
0418     if (key.isEmpty()) {
0419         return false;
0420     }
0421 
0422     const int keylen = key.length();
0423 
0424     if (type != WirelessSecuritySetting::NotSpecified) {
0425         if (type == WirelessSecuritySetting::Hex) {
0426             if (keylen == 10 || keylen == 26) {
0427                 /* Hex key */
0428                 for (int i = 0; i < keylen; ++i) {
0429                     if (!(key.at(i).isDigit() || (key.at(i) >= 'A' && key.at(i) <= 'F') || (key.at(i) >= 'a' && key.at(i) <= 'f'))) {
0430                         return false;
0431                     }
0432                 }
0433                 return true;
0434             } else if (keylen == 5 || keylen == 13) {
0435                 /* ASCII KEY */
0436                 for (int i = 0; i < keylen; ++i) {
0437                     if (!key.at(i).isPrint()) {
0438                         return false;
0439                     }
0440                 }
0441                 return true;
0442             }
0443 
0444             return false;
0445         } else if (type == WirelessSecuritySetting::Passphrase) {
0446             if (!keylen || keylen > 64) {
0447                 return false;
0448             }
0449 
0450             return true;
0451         }
0452     }
0453 
0454     return false;
0455 }
0456 
0457 bool NetworkManager::wpaPskIsValid(const QString &psk)
0458 {
0459     if (psk.isEmpty()) {
0460         return false;
0461     }
0462 
0463     const int psklen = psk.length();
0464 
0465     if (psklen < 8 || psklen > 64) {
0466         return false;
0467     }
0468 
0469     if (psklen == 64) {
0470         /* Hex PSK */
0471         for (int i = 0; i < psklen; ++i) {
0472             if (!psk.at(i).isLetterOrNumber()) {
0473                 return false;
0474             }
0475         }
0476     }
0477 
0478     return true;
0479 }
0480 
0481 NetworkManager::WirelessSecurityType NetworkManager::securityTypeFromConnectionSetting(const NetworkManager::ConnectionSettings::Ptr &settings)
0482 {
0483     NetworkManager::WirelessSecuritySetting::Ptr wifiSecuritySetting = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>();
0484     if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Wep) {
0485         return StaticWep;
0486     } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Ieee8021x) {
0487         if (wifiSecuritySetting->authAlg() == WirelessSecuritySetting::Leap) {
0488             return Leap;
0489         } else {
0490             return DynamicWep;
0491         }
0492     } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaPsk) {
0493         if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
0494             return WpaPsk;
0495         }
0496         return Wpa2Psk;
0497     } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEap) {
0498         if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
0499             return WpaEap;
0500         }
0501         return Wpa2Eap;
0502     } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::SAE) {
0503         return SAE;
0504     } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEapSuiteB192) {
0505         return Wpa3SuiteB192;
0506     }
0507 
0508     return NoneSecurity;
0509 }
0510 
0511 QList<QPair<int, int>> NetworkManager::getBFreqs()
0512 {
0513     QList<QPair<int, int>> freqs;
0514 
0515     freqs.append(QPair<int, int>(1, 2412));
0516     freqs.append(QPair<int, int>(2, 2417));
0517     freqs.append(QPair<int, int>(3, 2422));
0518     freqs.append(QPair<int, int>(4, 2427));
0519     freqs.append(QPair<int, int>(5, 2432));
0520     freqs.append(QPair<int, int>(6, 2437));
0521     freqs.append(QPair<int, int>(7, 2442));
0522     freqs.append(QPair<int, int>(8, 2447));
0523     freqs.append(QPair<int, int>(9, 2452));
0524     freqs.append(QPair<int, int>(10, 2457));
0525     freqs.append(QPair<int, int>(11, 2462));
0526     freqs.append(QPair<int, int>(12, 2467));
0527     freqs.append(QPair<int, int>(13, 2472));
0528     freqs.append(QPair<int, int>(14, 2484));
0529 
0530     return freqs;
0531 }
0532 
0533 QList<QPair<int, int>> NetworkManager::getAFreqs()
0534 {
0535     QList<QPair<int, int>> freqs;
0536 
0537     freqs.append(QPair<int, int>(7, 5035));
0538     freqs.append(QPair<int, int>(8, 5040));
0539     freqs.append(QPair<int, int>(9, 5045));
0540     freqs.append(QPair<int, int>(11, 5055));
0541     freqs.append(QPair<int, int>(12, 5060));
0542     freqs.append(QPair<int, int>(16, 5080));
0543     freqs.append(QPair<int, int>(34, 5170));
0544     freqs.append(QPair<int, int>(36, 5180));
0545     freqs.append(QPair<int, int>(38, 5190));
0546     freqs.append(QPair<int, int>(40, 5200));
0547     freqs.append(QPair<int, int>(42, 5210));
0548     freqs.append(QPair<int, int>(44, 5220));
0549     freqs.append(QPair<int, int>(46, 5230));
0550     freqs.append(QPair<int, int>(48, 5240));
0551     freqs.append(QPair<int, int>(52, 5260));
0552     freqs.append(QPair<int, int>(56, 5280));
0553     freqs.append(QPair<int, int>(60, 5300));
0554     freqs.append(QPair<int, int>(64, 5320));
0555     freqs.append(QPair<int, int>(100, 5500));
0556     freqs.append(QPair<int, int>(104, 5520));
0557     freqs.append(QPair<int, int>(108, 5540));
0558     freqs.append(QPair<int, int>(112, 5560));
0559     freqs.append(QPair<int, int>(116, 5580));
0560     freqs.append(QPair<int, int>(120, 5600));
0561     freqs.append(QPair<int, int>(124, 5620));
0562     freqs.append(QPair<int, int>(128, 5640));
0563     freqs.append(QPair<int, int>(132, 5660));
0564     freqs.append(QPair<int, int>(136, 5680));
0565     freqs.append(QPair<int, int>(140, 5700));
0566     freqs.append(QPair<int, int>(149, 5745));
0567     freqs.append(QPair<int, int>(153, 5765));
0568     freqs.append(QPair<int, int>(157, 5785));
0569     freqs.append(QPair<int, int>(161, 5805));
0570     freqs.append(QPair<int, int>(165, 5825));
0571     freqs.append(QPair<int, int>(183, 4915));
0572     freqs.append(QPair<int, int>(184, 4920));
0573     freqs.append(QPair<int, int>(185, 4925));
0574     freqs.append(QPair<int, int>(187, 4935));
0575     freqs.append(QPair<int, int>(188, 4940));
0576     freqs.append(QPair<int, int>(189, 4945));
0577     freqs.append(QPair<int, int>(192, 4960));
0578     freqs.append(QPair<int, int>(196, 4980));
0579 
0580     return freqs;
0581 }
0582 
0583 QDateTime NetworkManager::clockBootTimeToDateTime(qlonglong clockBootime)
0584 {
0585     clockid_t clk_id = CLOCK_BOOTTIME;
0586     struct timespec tp;
0587     int r;
0588 
0589     // now is used as a point of reference
0590     // with the timespec that contains the number of msec since boot
0591     QDateTime now = QDateTime::currentDateTime();
0592     r = clock_gettime(clk_id, &tp);
0593     if (r == -1 && errno == EINVAL) {
0594         clk_id = CLOCK_MONOTONIC;
0595         r = clock_gettime(clk_id, &tp);
0596     }
0597 
0598     // convert to msecs
0599     long now_msecs = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
0600 
0601     // diff the msecs and construct a QDateTime based on the offset
0602     QDateTime res;
0603     if (clockBootime > now_msecs) {
0604         qlonglong offset = clockBootime - now_msecs;
0605         res = QDateTime::fromMSecsSinceEpoch(now.toMSecsSinceEpoch() + offset);
0606     } else {
0607         qlonglong offset = now_msecs - clockBootime;
0608         res = QDateTime::fromMSecsSinceEpoch(now.toMSecsSinceEpoch() - offset);
0609     }
0610 
0611     return res;
0612 }