File indexing completed on 2025-03-16 12:58:26
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 }