source: trunk/src/plugins/bearer/icd/qicdengine.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 38.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qicdengine.h"
43#include "qnetworksession_impl.h"
44
45#include <wlancond.h>
46#include <wlan-utils.h>
47#include <iapconf.h>
48#include <iapmonitor.h>
49
50#ifndef QT_NO_BEARERMANAGEMENT
51
52QT_BEGIN_NAMESPACE
53
54IcdNetworkConfigurationPrivate::IcdNetworkConfigurationPrivate()
55: service_attrs(0), network_attrs(0)
56{
57}
58
59IcdNetworkConfigurationPrivate::~IcdNetworkConfigurationPrivate()
60{
61}
62
63QString IcdNetworkConfigurationPrivate::bearerTypeName() const
64{
65 QMutexLocker locker(&mutex);
66
67 return iap_type;
68}
69
70/******************************************************************************/
71/** IapAddTimer specific */
72/******************************************************************************/
73
74/* The IapAddTimer is a helper class that makes sure we update
75 * the configuration only after all db additions to certain
76 * iap are finished (after a certain timeout)
77 */
78class _IapAddTimer : public QObject
79{
80 Q_OBJECT
81
82public:
83 _IapAddTimer() {}
84 ~_IapAddTimer()
85 {
86 if (timer.isActive()) {
87 QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
88 timer.stop();
89 }
90 }
91
92 void add(QString& iap_id, QIcdEngine *d);
93
94 QString iap_id;
95 QTimer timer;
96 QIcdEngine *d;
97
98public Q_SLOTS:
99 void timeout();
100};
101
102
103void _IapAddTimer::add(QString& id, QIcdEngine *d_ptr)
104{
105 iap_id = id;
106 d = d_ptr;
107
108 if (timer.isActive()) {
109 QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
110 timer.stop();
111 }
112 timer.setSingleShot(true);
113 QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
114 timer.start(1500);
115}
116
117
118void _IapAddTimer::timeout()
119{
120 d->addConfiguration(iap_id);
121}
122
123
124class IapAddTimer {
125 QHash<QString, _IapAddTimer* > timers;
126
127public:
128 IapAddTimer() {}
129 ~IapAddTimer() {}
130
131 void add(QString& iap_id, QIcdEngine *d);
132 void del(QString& iap_id);
133 void removeAll();
134};
135
136
137void IapAddTimer::removeAll()
138{
139 QHashIterator<QString, _IapAddTimer* > i(timers);
140 while (i.hasNext()) {
141 i.next();
142 _IapAddTimer *t = i.value();
143 delete t;
144 }
145 timers.clear();
146}
147
148
149void IapAddTimer::add(QString& iap_id, QIcdEngine *d)
150{
151 if (timers.contains(iap_id)) {
152 _IapAddTimer *iap = timers.value(iap_id);
153 iap->add(iap_id, d);
154 } else {
155 _IapAddTimer *iap = new _IapAddTimer;
156 iap->add(iap_id, d);
157 timers.insert(iap_id, iap);
158 }
159}
160
161void IapAddTimer::del(QString& iap_id)
162{
163 if (timers.contains(iap_id)) {
164 _IapAddTimer *iap = timers.take(iap_id);
165 delete iap;
166 }
167}
168
169/******************************************************************************/
170/** IAPMonitor specific */
171/******************************************************************************/
172
173class IapMonitor : public Maemo::IAPMonitor
174{
175public:
176 IapMonitor() : first_call(true) { }
177
178 void setup(QIcdEngine *d);
179 void cleanup();
180
181protected:
182 void iapAdded(const QString &iapId);
183 void iapRemoved(const QString &iapId);
184
185private:
186 bool first_call;
187
188 QIcdEngine *d;
189 IapAddTimer timers;
190};
191
192void IapMonitor::setup(QIcdEngine *d_ptr)
193{
194 if (first_call) {
195 d = d_ptr;
196 first_call = false;
197 }
198}
199
200
201void IapMonitor::cleanup()
202{
203 if (!first_call) {
204 timers.removeAll();
205 first_call = true;
206 }
207}
208
209
210void IapMonitor::iapAdded(const QString &iap_id)
211{
212 /* We cannot know when the IAP is fully added to db, so a timer is
213 * installed instead. When the timer expires we hope that IAP is added ok.
214 */
215 QString id = iap_id;
216 timers.add(id, d);
217}
218
219
220void IapMonitor::iapRemoved(const QString &iap_id)
221{
222 QString id = iap_id;
223 d->deleteConfiguration(id);
224}
225
226
227/******************************************************************************/
228/** QIcdEngine implementation */
229/******************************************************************************/
230
231QIcdEngine::QIcdEngine(QObject *parent)
232: QBearerEngine(parent), iapMonitor(0), m_dbusInterface(0), m_icdServiceWatcher(0),
233 firstUpdate(true), m_scanGoingOn(false)
234{
235}
236
237QIcdEngine::~QIcdEngine()
238{
239 cleanup();
240 delete iapMonitor;
241}
242
243QNetworkConfigurationManager::Capabilities QIcdEngine::capabilities() const
244{
245 return QNetworkConfigurationManager::CanStartAndStopInterfaces |
246 QNetworkConfigurationManager::DataStatistics |
247 QNetworkConfigurationManager::ForcedRoaming |
248 QNetworkConfigurationManager::NetworkSessionRequired;
249}
250
251bool QIcdEngine::ensureDBusConnection()
252{
253 if (m_dbusInterface)
254 return true;
255
256 // Setup DBus Interface for ICD
257 m_dbusInterface = new QDBusInterface(ICD_DBUS_API_INTERFACE,
258 ICD_DBUS_API_PATH,
259 ICD_DBUS_API_INTERFACE,
260 QDBusConnection::systemBus(),
261 this);
262
263 if (!m_dbusInterface->isValid()) {
264 delete m_dbusInterface;
265 m_dbusInterface = 0;
266
267 if (!m_icdServiceWatcher) {
268 m_icdServiceWatcher = new QDBusServiceWatcher(ICD_DBUS_API_INTERFACE,
269 QDBusConnection::systemBus(),
270 QDBusServiceWatcher::WatchForOwnerChange,
271 this);
272
273 connect(m_icdServiceWatcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
274 this, SLOT(icdServiceOwnerChanged(QString,QString,QString)));
275 }
276
277 return false;
278 }
279
280 connect(&m_scanTimer, SIGNAL(timeout()), this, SLOT(finishAsyncConfigurationUpdate()));
281 m_scanTimer.setSingleShot(true);
282
283 /* Turn on IAP state monitoring */
284 startListeningStateSignalsForAllConnections();
285
286 /* Turn on IAP add/remove monitoring */
287 iapMonitor = new IapMonitor;
288 iapMonitor->setup(this);
289
290 /* We create a default configuration which is a pseudo config */
291 QNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate;
292 cpPriv->name = "UserChoice";
293 cpPriv->state = QNetworkConfiguration::Discovered;
294 cpPriv->isValid = true;
295 cpPriv->id = OSSO_IAP_ANY;
296 cpPriv->type = QNetworkConfiguration::UserChoice;
297 cpPriv->purpose = QNetworkConfiguration::UnknownPurpose;
298 cpPriv->roamingSupported = false;
299
300 QNetworkConfigurationPrivatePointer ptr(cpPriv);
301 userChoiceConfigurations.insert(cpPriv->id, ptr);
302
303 doRequestUpdate();
304
305 getIcdInitialState();
306
307 return true;
308}
309
310void QIcdEngine::initialize()
311{
312 QMutexLocker locker(&mutex);
313
314 if (!ensureDBusConnection()) {
315 locker.unlock();
316 emit updateCompleted();
317 locker.relock();
318 }
319}
320
321static inline QString network_attrs_to_security(uint network_attrs)
322{
323 uint cap = 0;
324 nwattr2cap(network_attrs, &cap); /* from libicd-network-wlan-dev.h */
325 if (cap & WLANCOND_OPEN)
326 return "NONE";
327 else if (cap & WLANCOND_WEP)
328 return "WEP";
329 else if (cap & WLANCOND_WPA_PSK)
330 return "WPA_PSK";
331 else if (cap & WLANCOND_WPA_EAP)
332 return "WPA_EAP";
333 return "";
334}
335
336
337struct SSIDInfo {
338 QString iap_id;
339 QString wlan_security;
340};
341
342
343void QIcdEngine::deleteConfiguration(const QString &iap_id)
344{
345 QMutexLocker locker(&mutex);
346
347 /* Called when IAPs are deleted in db, in this case we do not scan
348 * or read all the IAPs from db because it might take too much power
349 * (multiple applications would need to scan and read all IAPs from db)
350 */
351 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(iap_id);
352 if (ptr) {
353#ifdef BEARER_MANAGEMENT_DEBUG
354 qDebug() << "IAP" << iap_id << "was removed from storage.";
355#endif
356
357 locker.unlock();
358 emit configurationRemoved(ptr);
359 } else {
360#ifdef BEARER_MANAGEMENT_DEBUG
361 qDebug("IAP: %s, already missing from the known list", iap_id.toAscii().data());
362#endif
363 }
364}
365
366
367static quint32 getNetworkAttrs(bool is_iap_id,
368 const QString &iap_id,
369 const QString &iap_type,
370 QString security_method)
371{
372 guint network_attr = 0;
373 dbus_uint32_t cap = 0;
374
375 if (iap_type == "WLAN_INFRA")
376 cap |= WLANCOND_INFRA;
377 else if (iap_type == "WLAN_ADHOC")
378 cap |= WLANCOND_ADHOC;
379
380 if (security_method.isEmpty() && (cap & (WLANCOND_INFRA | WLANCOND_ADHOC))) {
381 Maemo::IAPConf saved_ap(iap_id);
382 security_method = saved_ap.value("wlan_security").toString();
383 }
384
385 if (!security_method.isEmpty()) {
386 if (security_method == "WEP")
387 cap |= WLANCOND_WEP;
388 else if (security_method == "WPA_PSK")
389 cap |= WLANCOND_WPA_PSK;
390 else if (security_method == "WPA_EAP")
391 cap |= WLANCOND_WPA_EAP;
392 else if (security_method == "NONE")
393 cap |= WLANCOND_OPEN;
394
395 if (cap & (WLANCOND_WPA_PSK | WLANCOND_WPA_EAP)) {
396 Maemo::IAPConf saved_iap(iap_id);
397 bool wpa2_only = saved_iap.value("EAP_wpa2_only_mode").toBool();
398 if (wpa2_only) {
399 cap |= WLANCOND_WPA2;
400 }
401 }
402 }
403
404 cap2nwattr(cap, &network_attr);
405 if (is_iap_id)
406 network_attr |= ICD_NW_ATTR_IAPNAME;
407
408 return quint32(network_attr);
409}
410
411
412void QIcdEngine::addConfiguration(QString& iap_id)
413{
414 // Note: When new IAP is created, this function gets called multiple times
415 // in a row.
416 // For example: Empty type & name for WLAN was stored into newly
417 // created IAP data in gconf when this function gets
418 // called for the first time.
419 // WLAN type & name are updated into IAP data in gconf
420 // as soon as WLAN connection is up and running.
421 // => And this function gets called again.
422
423 QMutexLocker locker(&mutex);
424
425 if (!accessPointConfigurations.contains(iap_id)) {
426 Maemo::IAPConf saved_iap(iap_id);
427 QString iap_type = saved_iap.value("type").toString();
428 QString iap_name = saved_iap.value("name").toString();
429 QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray();
430 if (!iap_type.isEmpty() && !iap_name.isEmpty()) {
431 // Check if new IAP is actually Undefined WLAN configuration
432 // Note: SSID is used as an iap id for Undefined WLAN configurations
433 // => configuration must be searched using SSID
434 if (!ssid.isEmpty() && accessPointConfigurations.contains(ssid)) {
435 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(ssid);
436 if (ptr) {
437 ptr->mutex.lock();
438 ptr->id = iap_id;
439 toIcdConfig(ptr)->iap_type = iap_type;
440 ptr->bearerType = bearerTypeFromIapType(iap_type);
441 toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString());
442 toIcdConfig(ptr)->network_id = ssid;
443 toIcdConfig(ptr)->service_id = saved_iap.value("service_id").toString();
444 toIcdConfig(ptr)->service_type = saved_iap.value("service_type").toString();
445 if (m_onlineIapId == iap_id) {
446 ptr->state = QNetworkConfiguration::Active;
447 } else {
448 ptr->state = QNetworkConfiguration::Defined;
449 }
450 ptr->mutex.unlock();
451 accessPointConfigurations.insert(iap_id, ptr);
452
453 locker.unlock();
454 emit configurationChanged(ptr);
455 locker.relock();
456 }
457 } else {
458 IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate;
459 cpPriv->name = saved_iap.value("name").toString();
460 if (cpPriv->name.isEmpty())
461 cpPriv->name = iap_id;
462 cpPriv->isValid = true;
463 cpPriv->id = iap_id;
464 cpPriv->iap_type = iap_type;
465 cpPriv->bearerType = bearerTypeFromIapType(iap_type);
466 cpPriv->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString());
467 cpPriv->service_id = saved_iap.value("service_id").toString();
468 cpPriv->service_type = saved_iap.value("service_type").toString();
469 if (iap_type.startsWith(QLatin1String("WLAN"))) {
470 QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray();
471 if (ssid.isEmpty()) {
472 qWarning() << "Cannot get ssid for" << iap_id;
473 }
474 cpPriv->network_id = ssid;
475 }
476 cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
477 if (m_onlineIapId == iap_id) {
478 cpPriv->state = QNetworkConfiguration::Active;
479 } else {
480 cpPriv->state = QNetworkConfiguration::Defined;
481 }
482
483 QNetworkConfigurationPrivatePointer ptr(cpPriv);
484 accessPointConfigurations.insert(iap_id, ptr);
485
486#ifdef BEARER_MANAGEMENT_DEBUG
487 qDebug("IAP: %s, name: %s, added to known list", iap_id.toAscii().data(), cpPriv->name.toAscii().data());
488#endif
489 locker.unlock();
490 emit configurationAdded(ptr);
491 locker.relock();
492 }
493 } else {
494 qWarning("IAP %s does not have \"type\" or \"name\" fields defined, skipping this IAP.", iap_id.toAscii().data());
495 }
496 } else {
497#ifdef BEARER_MANAGEMENT_DEBUG
498 qDebug() << "IAP" << iap_id << "already in db.";
499#endif
500
501 /* Check if the data in db changed and update configuration accordingly
502 */
503 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id);
504 if (ptr) {
505 Maemo::IAPConf changed_iap(iap_id);
506 QString iap_type = changed_iap.value("type").toString();
507 bool update_needed = false; /* if IAP type or ssid changed, we need to change the state */
508
509 QMutexLocker configLocker(&ptr->mutex);
510
511 toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString());
512 toIcdConfig(ptr)->service_id = changed_iap.value("service_id").toString();
513 toIcdConfig(ptr)->service_type = changed_iap.value("service_type").toString();
514
515 if (!iap_type.isEmpty()) {
516 ptr->name = changed_iap.value("name").toString();
517 if (ptr->name.isEmpty())
518 ptr->name = iap_id;
519 ptr->isValid = true;
520 if (toIcdConfig(ptr)->iap_type != iap_type) {
521 toIcdConfig(ptr)->iap_type = iap_type;
522 ptr->bearerType = bearerTypeFromIapType(iap_type);
523 update_needed = true;
524 }
525 if (iap_type.startsWith(QLatin1String("WLAN"))) {
526 QByteArray ssid = changed_iap.value("wlan_ssid").toByteArray();
527 if (ssid.isEmpty()) {
528 qWarning() << "Cannot get ssid for" << iap_id;
529 }
530 if (toIcdConfig(ptr)->network_id != ssid) {
531 toIcdConfig(ptr)->network_id = ssid;
532 update_needed = true;
533 }
534 }
535 }
536
537 if (update_needed) {
538 ptr->type = QNetworkConfiguration::InternetAccessPoint;
539 if (m_onlineIapId == iap_id) {
540 if (ptr->state < QNetworkConfiguration::Active) {
541 ptr->state = QNetworkConfiguration::Active;
542
543 configLocker.unlock();
544 locker.unlock();
545 emit configurationChanged(ptr);
546 locker.relock();
547 }
548 } else if (ptr->state < QNetworkConfiguration::Defined) {
549 ptr->state = QNetworkConfiguration::Defined;
550
551 configLocker.unlock();
552 locker.unlock();
553 emit configurationChanged(ptr);
554 locker.relock();
555 }
556 }
557 } else {
558 qWarning("Cannot find IAP %s from current configuration although it should be there.", iap_id.toAscii().data());
559 }
560 }
561}
562
563void QIcdEngine::doRequestUpdate(QList<Maemo::IcdScanResult> scanned)
564{
565 /* Contains all known iap_ids from storage */
566 QList<QString> knownConfigs = accessPointConfigurations.keys();
567
568 /* Contains all known WLAN network ids (like ssid) from storage */
569 QMultiHash<QByteArray, SSIDInfo* > notDiscoveredWLANConfigs;
570
571 QList<QString> all_iaps;
572 Maemo::IAPConf::getAll(all_iaps);
573
574 foreach (const QString &iap_id, all_iaps) {
575 QByteArray ssid;
576
577 Maemo::IAPConf saved_ap(iap_id);
578 bool is_temporary = saved_ap.value("temporary").toBool();
579 if (is_temporary) {
580#ifdef BEARER_MANAGEMENT_DEBUG
581 qDebug() << "IAP" << iap_id << "is temporary, skipping it.";
582#endif
583 continue;
584 }
585
586 QString iap_type = saved_ap.value("type").toString();
587 if (iap_type.startsWith(QLatin1String("WLAN"))) {
588 ssid = saved_ap.value("wlan_ssid").toByteArray();
589 if (ssid.isEmpty())
590 continue;
591
592 QString security_method = saved_ap.value("wlan_security").toString();
593 SSIDInfo *info = new SSIDInfo;
594 info->iap_id = iap_id;
595 info->wlan_security = security_method;
596 notDiscoveredWLANConfigs.insert(ssid, info);
597 } else if (iap_type.isEmpty()) {
598 continue;
599 } else {
600#ifdef BEARER_MANAGEMENT_DEBUG
601 qDebug() << "IAP" << iap_id << "network type is" << iap_type;
602#endif
603 ssid.clear();
604 }
605
606 if (!accessPointConfigurations.contains(iap_id)) {
607 IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate;
608
609 cpPriv->name = saved_ap.value("name").toString();
610 if (cpPriv->name.isEmpty()) {
611 if (!ssid.isEmpty() && ssid.size() > 0)
612 cpPriv->name = ssid.data();
613 else
614 cpPriv->name = iap_id;
615 }
616 cpPriv->isValid = true;
617 cpPriv->id = iap_id;
618 cpPriv->network_id = ssid;
619 cpPriv->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString());
620 cpPriv->iap_type = iap_type;
621 cpPriv->bearerType = bearerTypeFromIapType(iap_type);
622 cpPriv->service_id = saved_ap.value("service_id").toString();
623 cpPriv->service_type = saved_ap.value("service_type").toString();
624 cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
625 cpPriv->state = QNetworkConfiguration::Defined;
626
627 QNetworkConfigurationPrivatePointer ptr(cpPriv);
628 accessPointConfigurations.insert(iap_id, ptr);
629
630 mutex.unlock();
631 emit configurationAdded(ptr);
632 mutex.lock();
633
634#ifdef BEARER_MANAGEMENT_DEBUG
635 qDebug("IAP: %s, name: %s, ssid: %s, added to known list",
636 iap_id.toAscii().data(), ptr->name.toAscii().data(),
637 !ssid.isEmpty() ? ssid.data() : "-");
638#endif
639 } else {
640 knownConfigs.removeOne(iap_id);
641#ifdef BEARER_MANAGEMENT_DEBUG
642 qDebug("IAP: %s, ssid: %s, already exists in the known list",
643 iap_id.toAscii().data(), !ssid.isEmpty() ? ssid.data() : "-");
644#endif
645 }
646 }
647
648 /* This is skipped in the first update as scanned size is zero */
649 if (!scanned.isEmpty()) {
650 for (int i=0; i<scanned.size(); ++i) {
651 const Maemo::IcdScanResult ap = scanned.at(i);
652
653 if (ap.scan.network_attrs & ICD_NW_ATTR_IAPNAME) {
654 /* The network_id is IAP id, so the IAP is a known one */
655 QString iapid = ap.scan.network_id.data();
656 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid);
657 if (ptr) {
658 bool changed = false;
659
660 ptr->mutex.lock();
661
662 if (!ptr->isValid) {
663 ptr->isValid = true;
664 changed = true;
665 }
666
667 /* If this config is the current active one, we do not set it
668 * to discovered.
669 */
670 if ((ptr->state != QNetworkConfiguration::Discovered) &&
671 (ptr->state != QNetworkConfiguration::Active)) {
672 ptr->state = QNetworkConfiguration::Discovered;
673 changed = true;
674 }
675
676 toIcdConfig(ptr)->network_attrs = ap.scan.network_attrs;
677 toIcdConfig(ptr)->service_id = ap.scan.service_id;
678 toIcdConfig(ptr)->service_type = ap.scan.service_type;
679 toIcdConfig(ptr)->service_attrs = ap.scan.service_attrs;
680
681#ifdef BEARER_MANAGEMENT_DEBUG
682 qDebug("IAP: %s, ssid: %s, discovered",
683 iapid.toAscii().data(), toIcdConfig(ptr)->network_id.data());
684#endif
685
686 ptr->mutex.unlock();
687
688 if (changed) {
689 mutex.unlock();
690 emit configurationChanged(ptr);
691 mutex.lock();
692 }
693
694 if (!ap.scan.network_type.startsWith(QLatin1String("WLAN")))
695 continue; // not a wlan AP
696
697 /* Remove scanned AP from discovered WLAN configurations so that we can
698 * emit configurationRemoved signal later
699 */
700 ptr->mutex.lock();
701 QList<SSIDInfo* > known_iaps = notDiscoveredWLANConfigs.values(toIcdConfig(ptr)->network_id);
702rescan_list:
703 if (!known_iaps.isEmpty()) {
704 for (int k=0; k<known_iaps.size(); ++k) {
705 SSIDInfo *iap = known_iaps.at(k);
706
707 if (iap->wlan_security ==
708 network_attrs_to_security(ap.scan.network_attrs)) {
709 /* Remove IAP from the list */
710 notDiscoveredWLANConfigs.remove(toIcdConfig(ptr)->network_id, iap);
711#ifdef BEARER_MANAGEMENT_DEBUG
712 qDebug() << "Removed IAP" << iap->iap_id << "from unknown config";
713#endif
714 known_iaps.removeAt(k);
715 delete iap;
716 goto rescan_list;
717 }
718 }
719 }
720 ptr->mutex.unlock();
721 }
722 } else {
723 /* Non saved access point data */
724 QByteArray scanned_ssid = ap.scan.network_id;
725 if (!accessPointConfigurations.contains(scanned_ssid)) {
726 IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate;
727 QString hrs = scanned_ssid.data();
728
729 cpPriv->name = ap.network_name.isEmpty() ? hrs : ap.network_name;
730 cpPriv->isValid = true;
731 cpPriv->id = scanned_ssid.data(); // Note: id is now ssid, it should be set to IAP id if the IAP is saved
732 cpPriv->network_id = scanned_ssid;
733 cpPriv->iap_type = ap.scan.network_type;
734 cpPriv->bearerType = bearerTypeFromIapType(cpPriv->iap_type);
735 cpPriv->network_attrs = ap.scan.network_attrs;
736 cpPriv->service_id = ap.scan.service_id;
737 cpPriv->service_type = ap.scan.service_type;
738 cpPriv->service_attrs = ap.scan.service_attrs;
739
740 cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
741 cpPriv->state = QNetworkConfiguration::Undefined;
742
743#ifdef BEARER_MANAGEMENT_DEBUG
744 qDebug() << "IAP with network id" << cpPriv->id << "was found in the scan.";
745#endif
746
747 QNetworkConfigurationPrivatePointer ptr(cpPriv);
748 accessPointConfigurations.insert(ptr->id, ptr);
749
750 mutex.unlock();
751 emit configurationAdded(ptr);
752 mutex.lock();
753 } else {
754 knownConfigs.removeOne(scanned_ssid);
755 }
756 }
757 }
758 }
759
760 if (!firstUpdate) {
761 // Update Defined status to all defined WLAN IAPs which
762 // could not be found when access points were scanned
763 QHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs);
764 while (i.hasNext()) {
765 i.next();
766 SSIDInfo *iap = i.value();
767 QString iap_id = iap->iap_id;
768 //qDebug() << i.key() << ": " << iap_id;
769
770 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id);
771 if (ptr) {
772 QMutexLocker configLocker(&ptr->mutex);
773
774 // WLAN AccessPoint configuration could not be Discovered
775 // => Make sure that configuration state is Defined
776 if (ptr->state > QNetworkConfiguration::Defined) {
777 ptr->state = QNetworkConfiguration::Defined;
778
779 configLocker.unlock();
780 mutex.unlock();
781 emit configurationChanged(ptr);
782 mutex.lock();
783 }
784 }
785 }
786
787 /* Remove non existing iaps since last update */
788 foreach (const QString &oldIface, knownConfigs) {
789 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldIface);
790 if (ptr) {
791 mutex.unlock();
792 emit configurationRemoved(ptr);
793 mutex.lock();
794 //if we would have SNAP support we would have to remove the references
795 //from existing ServiceNetworks to the removed access point configuration
796 }
797 }
798 }
799
800 QMutableHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs);
801 while (i.hasNext()) {
802 i.next();
803 SSIDInfo *iap = i.value();
804 delete iap;
805 i.remove();
806 }
807
808 if (!firstUpdate) {
809 mutex.unlock();
810 emit updateCompleted();
811 mutex.lock();
812 }
813
814 if (firstUpdate)
815 firstUpdate = false;
816}
817
818QNetworkConfigurationPrivatePointer QIcdEngine::defaultConfiguration()
819{
820 QMutexLocker locker(&mutex);
821
822 if (!ensureDBusConnection())
823 return QNetworkConfigurationPrivatePointer();
824
825 // Here we just return [ANY] request to icd and let the icd decide which IAP to connect.
826 return userChoiceConfigurations.value(OSSO_IAP_ANY);
827}
828
829void QIcdEngine::startListeningStateSignalsForAllConnections()
830{
831 // Start listening ICD_DBUS_API_STATE_SIG signals
832 m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE,
833 ICD_DBUS_API_PATH,
834 ICD_DBUS_API_INTERFACE,
835 ICD_DBUS_API_STATE_SIG,
836 this, SLOT(connectionStateSignalsSlot(QDBusMessage)));
837}
838
839void QIcdEngine::getIcdInitialState()
840{
841 /* Instead of requesting ICD status asynchronously, we ask it synchronously.
842 * It ensures that we always get right icd status BEFORE initialize() ends.
843 * If not, initialize() might end before we got icd status and
844 * QNetworkConfigurationManager::updateConfigurations()
845 * call from user might also end before receiving icd status.
846 * In such case, we come up to a bug:
847 * QNetworkConfigurationManagerPrivate::isOnline() will be false even
848 * if we are connected.
849 */
850 Maemo::Icd icd;
851 QList<Maemo::IcdStateResult> state_results;
852 QNetworkConfigurationPrivatePointer ptr;
853
854 if (icd.state(state_results) && !state_results.isEmpty()) {
855
856 if (!(state_results.first().params.network_attrs == 0 &&
857 state_results.first().params.network_id.isEmpty())) {
858
859 switch (state_results.first().state) {
860 case ICD_STATE_CONNECTED:
861 m_onlineIapId = state_results.first().params.network_id;
862
863 ptr = accessPointConfigurations.value(m_onlineIapId);
864 if (ptr) {
865 QMutexLocker configLocker(&ptr->mutex);
866 ptr->state = QNetworkConfiguration::Active;
867 configLocker.unlock();
868
869 mutex.unlock();
870 emit configurationChanged(ptr);
871 mutex.lock();
872 }
873 break;
874 default:
875 break;
876 }
877 }
878 }
879}
880
881void QIcdEngine::connectionStateSignalsSlot(QDBusMessage msg)
882{
883 QMutexLocker locker(&mutex);
884
885 QList<QVariant> arguments = msg.arguments();
886 if (arguments[1].toUInt() != 0 || arguments.count() < 8) {
887 return;
888 }
889
890 QString iapid = arguments[5].toByteArray().data();
891 uint icd_connection_state = arguments[7].toUInt();
892
893 switch (icd_connection_state) {
894 case ICD_STATE_CONNECTED:
895 {
896 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid);
897 if (ptr) {
898 QMutexLocker configLocker(&ptr->mutex);
899
900 ptr->type = QNetworkConfiguration::InternetAccessPoint;
901 if (ptr->state != QNetworkConfiguration::Active) {
902 ptr->state = QNetworkConfiguration::Active;
903
904 configLocker.unlock();
905 locker.unlock();
906 emit configurationChanged(ptr);
907 locker.relock();
908
909 m_onlineIapId = iapid;
910 }
911 } else {
912 // This gets called when new WLAN IAP is created using Connection dialog
913 // At this point Undefined WLAN configuration has SSID as iap id
914 // => Because of that configuration can not be found from
915 // accessPointConfigurations using correct iap id
916 m_onlineIapId = iapid;
917 }
918 break;
919 }
920 case ICD_STATE_DISCONNECTED:
921 {
922 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid);
923 if (ptr) {
924 QMutexLocker configLocker(&ptr->mutex);
925
926 ptr->type = QNetworkConfiguration::InternetAccessPoint;
927 if (ptr->state == QNetworkConfiguration::Active) {
928 ptr->state = QNetworkConfiguration::Discovered;
929
930 configLocker.unlock();
931 locker.unlock();
932 emit configurationChanged(ptr);
933 locker.relock();
934
935 // Note: If ICD switches used IAP from one to another:
936 // 1) new IAP is reported to be online first
937 // 2) old IAP is reported to be offline then
938 // => Device can be reported to be offline only
939 // if last known online IAP is reported to be disconnected
940 if (iapid == m_onlineIapId) {
941 // It's known that there is only one global ICD connection
942 // => Because ICD state was reported to be DISCONNECTED, Device is offline
943 m_onlineIapId.clear();
944 }
945 }
946 } else {
947 // Disconnected IAP was not found from accessPointConfigurations
948 // => Reason: Online IAP was removed which resulted ICD to disconnect
949 if (iapid == m_onlineIapId) {
950 // It's known that there is only one global ICD connection
951 // => Because ICD state was reported to be DISCONNECTED, Device is offline
952 m_onlineIapId.clear();
953 }
954 }
955 break;
956 }
957 default:
958 break;
959 }
960
961 locker.unlock();
962 emit iapStateChanged(iapid, icd_connection_state);
963 locker.relock();
964}
965
966void QIcdEngine::icdServiceOwnerChanged(const QString &serviceName, const QString &oldOwner,
967 const QString &newOwner)
968{
969 Q_UNUSED(serviceName);
970 Q_UNUSED(oldOwner);
971
972 QMutexLocker locker(&mutex);
973
974 if (newOwner.isEmpty()) {
975 // Disconnected from ICD, remove all configurations
976 cleanup();
977 delete iapMonitor;
978 iapMonitor = 0;
979 delete m_dbusInterface;
980 m_dbusInterface = 0;
981
982 QMutableHashIterator<QString, QNetworkConfigurationPrivatePointer> i(accessPointConfigurations);
983 while (i.hasNext()) {
984 i.next();
985
986 QNetworkConfigurationPrivatePointer ptr = i.value();
987 i.remove();
988
989 locker.unlock();
990 emit configurationRemoved(ptr);
991 locker.relock();
992 }
993
994 userChoiceConfigurations.clear();
995 } else {
996 // Connected to ICD ensure connection.
997 ensureDBusConnection();
998 }
999}
1000
1001void QIcdEngine::requestUpdate()
1002{
1003 QMutexLocker locker(&mutex);
1004
1005 if (!ensureDBusConnection()) {
1006 locker.unlock();
1007 emit updateCompleted();
1008 locker.relock();
1009 return;
1010 }
1011
1012 if (m_scanGoingOn)
1013 return;
1014
1015 m_scanGoingOn = true;
1016
1017 m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE,
1018 ICD_DBUS_API_PATH,
1019 ICD_DBUS_API_INTERFACE,
1020 ICD_DBUS_API_SCAN_SIG,
1021 this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage)));
1022
1023 QDBusMessage msg = m_dbusInterface->call(ICD_DBUS_API_SCAN_REQ,
1024 (uint)ICD_SCAN_REQUEST_ACTIVE);
1025 m_typesToBeScanned = msg.arguments()[0].value<QStringList>();
1026 m_scanTimer.start(ICD_SHORT_SCAN_TIMEOUT);
1027}
1028
1029void QIcdEngine::cancelAsyncConfigurationUpdate()
1030{
1031 if (!ensureDBusConnection())
1032 return;
1033
1034 if (!m_scanGoingOn)
1035 return;
1036
1037 m_scanGoingOn = false;
1038
1039 if (m_scanTimer.isActive())
1040 m_scanTimer.stop();
1041
1042 m_dbusInterface->connection().disconnect(ICD_DBUS_API_INTERFACE,
1043 ICD_DBUS_API_PATH,
1044 ICD_DBUS_API_INTERFACE,
1045 ICD_DBUS_API_SCAN_SIG,
1046 this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage)));
1047
1048 // Stop scanning rounds by calling ICD_DBUS_API_SCAN_CANCEL
1049 // <=> If ICD_DBUS_API_SCAN_CANCEL is not called, new scanning round will
1050 // be started after the module scan timeout.
1051 m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL);
1052}
1053
1054void QIcdEngine::finishAsyncConfigurationUpdate()
1055{
1056 QMutexLocker locker(&mutex);
1057
1058 cancelAsyncConfigurationUpdate();
1059 doRequestUpdate(m_scanResult);
1060 m_scanResult.clear();
1061}
1062
1063void QIcdEngine::asyncUpdateConfigurationsSlot(QDBusMessage msg)
1064{
1065 QMutexLocker locker(&mutex);
1066
1067 QList<QVariant> arguments = msg.arguments();
1068 uint icd_scan_status = arguments.takeFirst().toUInt();
1069 if (icd_scan_status == ICD_SCAN_COMPLETE) {
1070 m_typesToBeScanned.removeOne(arguments[6].toString());
1071 if (!m_typesToBeScanned.count()) {
1072 locker.unlock();
1073 finishAsyncConfigurationUpdate();
1074 locker.relock();
1075 }
1076 } else {
1077 Maemo::IcdScanResult scanResult;
1078 scanResult.status = icd_scan_status;
1079 scanResult.timestamp = arguments.takeFirst().toUInt();
1080 scanResult.scan.service_type = arguments.takeFirst().toString();
1081 scanResult.service_name = arguments.takeFirst().toString();
1082 scanResult.scan.service_attrs = arguments.takeFirst().toUInt();
1083 scanResult.scan.service_id = arguments.takeFirst().toString();
1084 scanResult.service_priority = arguments.takeFirst().toInt();
1085 scanResult.scan.network_type = arguments.takeFirst().toString();
1086 scanResult.network_name = arguments.takeFirst().toString();
1087 scanResult.scan.network_attrs = arguments.takeFirst().toUInt();
1088 scanResult.scan.network_id = arguments.takeFirst().toByteArray();
1089 scanResult.network_priority = arguments.takeFirst().toInt();
1090 scanResult.signal_strength = arguments.takeFirst().toInt();
1091 scanResult.station_id = arguments.takeFirst().toString();
1092 scanResult.signal_dB = arguments.takeFirst().toInt();
1093
1094 m_scanResult.append(scanResult);
1095 }
1096}
1097
1098void QIcdEngine::cleanup()
1099{
1100 if (m_scanGoingOn) {
1101 m_scanTimer.stop();
1102 m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL);
1103 }
1104 if (iapMonitor)
1105 iapMonitor->cleanup();
1106}
1107
1108bool QIcdEngine::hasIdentifier(const QString &id)
1109{
1110 QMutexLocker locker(&mutex);
1111
1112 return accessPointConfigurations.contains(id) ||
1113 snapConfigurations.contains(id) ||
1114 userChoiceConfigurations.contains(id);
1115}
1116
1117QNetworkSessionPrivate *QIcdEngine::createSessionBackend()
1118{
1119 return new QNetworkSessionPrivateImpl(this);
1120}
1121
1122#include "qicdengine.moc"
1123
1124QT_END_NAMESPACE
1125
1126#endif // QT_NO_BEARERMANAGEMENT
Note: See TracBrowser for help on using the repository browser.