source: trunk/src/plugins/bearer/nativewifi/qnativewifiengine.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: 19.3 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 "qnativewifiengine.h"
43#include "platformdefs.h"
44#include "../qnetworksession_impl.h"
45
46#include <QtNetwork/private/qnetworkconfiguration_p.h>
47
48#include <QtCore/qstringlist.h>
49#include <QtCore/qcoreapplication.h>
50
51#include <QtCore/qdebug.h>
52
53#ifndef QT_NO_BEARERMANAGEMENT
54
55QT_BEGIN_NAMESPACE
56
57WlanOpenHandleProto local_WlanOpenHandle = 0;
58WlanRegisterNotificationProto local_WlanRegisterNotification = 0;
59WlanEnumInterfacesProto local_WlanEnumInterfaces = 0;
60WlanGetAvailableNetworkListProto local_WlanGetAvailableNetworkList = 0;
61WlanQueryInterfaceProto local_WlanQueryInterface = 0;
62WlanConnectProto local_WlanConnect = 0;
63WlanDisconnectProto local_WlanDisconnect = 0;
64WlanScanProto local_WlanScan = 0;
65WlanFreeMemoryProto local_WlanFreeMemory = 0;
66WlanCloseHandleProto local_WlanCloseHandle = 0;
67
68void qNotificationCallback(WLAN_NOTIFICATION_DATA *data, QNativeWifiEngine *d)
69{
70 Q_UNUSED(d);
71
72 switch (data->NotificationCode) {
73 case wlan_notification_acm_connection_complete:
74 case wlan_notification_acm_disconnected:
75 QMetaObject::invokeMethod(d, "scanComplete", Qt::QueuedConnection);
76 break;
77 default:
78 ;
79 }
80}
81
82QNativeWifiEngine::QNativeWifiEngine(QObject *parent)
83: QBearerEngineImpl(parent), handle(INVALID_HANDLE_VALUE)
84{
85 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(closeHandle()));
86}
87
88QNativeWifiEngine::~QNativeWifiEngine()
89{
90 closeHandle();
91}
92
93void QNativeWifiEngine::scanComplete()
94{
95 QMutexLocker locker(&mutex);
96
97 if (!available()) {
98 locker.unlock();
99 emit updateCompleted();
100 return;
101 }
102
103 // enumerate interfaces
104 WLAN_INTERFACE_INFO_LIST *interfaceList;
105 DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
106 if (result != ERROR_SUCCESS) {
107#ifdef BEARER_MANAGEMENT_DEBUG
108 qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
109#endif
110
111 locker.unlock();
112 emit updateCompleted();
113
114 return;
115 }
116
117 QStringList previous = accessPointConfigurations.keys();
118
119 for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
120 const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
121
122 WLAN_AVAILABLE_NETWORK_LIST *networkList;
123 result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
124 3, 0, &networkList);
125 if (result != ERROR_SUCCESS) {
126#ifdef BEARER_MANAGEMENT_DEBUG
127 qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
128 __FUNCTION__, result);
129#endif
130 continue;
131 }
132
133 QStringList seenNetworks;
134
135 for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
136 WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
137
138 QString networkName;
139
140 if (network.strProfileName[0] != 0) {
141 networkName = QString::fromWCharArray(network.strProfileName);
142 } else {
143 networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID),
144 network.dot11Ssid.uSSIDLength);
145 }
146
147 const QString id = QString::number(qHash(QLatin1String("WLAN:") + networkName));
148
149 previous.removeAll(id);
150
151 QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
152
153 if (!(network.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE))
154 state = QNetworkConfiguration::Undefined;
155
156 if (network.strProfileName[0] != 0) {
157 if (network.bNetworkConnectable) {
158 if (network.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
159 state = QNetworkConfiguration::Active;
160 else
161 state = QNetworkConfiguration::Discovered;
162 } else {
163 state = QNetworkConfiguration::Defined;
164 }
165 }
166
167 if (seenNetworks.contains(networkName))
168 continue;
169 else
170 seenNetworks.append(networkName);
171
172 if (accessPointConfigurations.contains(id)) {
173 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
174
175 bool changed = false;
176
177 ptr->mutex.lock();
178
179 if (!ptr->isValid) {
180 ptr->isValid = true;
181 changed = true;
182 }
183
184 if (ptr->name != networkName) {
185 ptr->name = networkName;
186 changed = true;
187 }
188
189 if (ptr->state != state) {
190 ptr->state = state;
191 changed = true;
192 }
193
194 ptr->mutex.unlock();
195
196 if (changed) {
197 locker.unlock();
198 emit configurationChanged(ptr);
199 locker.relock();
200 }
201 } else {
202 QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate);
203
204 ptr->name = networkName;
205 ptr->isValid = true;
206 ptr->id = id;
207 ptr->state = state;
208 ptr->type = QNetworkConfiguration::InternetAccessPoint;
209 ptr->bearerType = QNetworkConfiguration::BearerWLAN;
210
211 accessPointConfigurations.insert(id, ptr);
212
213 locker.unlock();
214 emit configurationAdded(ptr);
215 locker.relock();
216 }
217 }
218
219 local_WlanFreeMemory(networkList);
220 }
221
222 local_WlanFreeMemory(interfaceList);
223
224 while (!previous.isEmpty()) {
225 QNetworkConfigurationPrivatePointer ptr =
226 accessPointConfigurations.take(previous.takeFirst());
227
228 locker.unlock();
229 emit configurationRemoved(ptr);
230 locker.relock();
231 }
232
233 locker.unlock();
234 emit updateCompleted();
235}
236
237QString QNativeWifiEngine::getInterfaceFromId(const QString &id)
238{
239 QMutexLocker locker(&mutex);
240
241 if (!available())
242 return QString();
243
244 // enumerate interfaces
245 WLAN_INTERFACE_INFO_LIST *interfaceList;
246 DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
247 if (result != ERROR_SUCCESS) {
248#ifdef BEARER_MANAGEMENT_DEBUG
249 qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
250#endif
251 return QString();
252 }
253
254 for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
255 const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
256
257 DWORD dataSize;
258 WLAN_CONNECTION_ATTRIBUTES *connectionAttributes;
259 result = local_WlanQueryInterface(handle, &interface.InterfaceGuid,
260 wlan_intf_opcode_current_connection, 0, &dataSize,
261 reinterpret_cast<PVOID *>(&connectionAttributes), 0);
262 if (result != ERROR_SUCCESS) {
263#ifdef BEARER_MANAGEMENT_DEBUG
264 if (result != ERROR_INVALID_STATE)
265 qDebug("%s: WlanQueryInterface failed with error %ld\n", __FUNCTION__, result);
266#endif
267
268 continue;
269 }
270
271 if (qHash(QLatin1String("WLAN:") +
272 QString::fromWCharArray(connectionAttributes->strProfileName)) == id.toUInt()) {
273 QString guid("{%1-%2-%3-%4%5-%6%7%8%9%10%11}");
274
275 guid = guid.arg(interface.InterfaceGuid.Data1, 8, 16, QChar('0'));
276 guid = guid.arg(interface.InterfaceGuid.Data2, 4, 16, QChar('0'));
277 guid = guid.arg(interface.InterfaceGuid.Data3, 4, 16, QChar('0'));
278 for (int i = 0; i < 8; ++i)
279 guid = guid.arg(interface.InterfaceGuid.Data4[i], 2, 16, QChar('0'));
280
281 local_WlanFreeMemory(connectionAttributes);
282 local_WlanFreeMemory(interfaceList);
283
284 return guid.toUpper();
285 }
286
287 local_WlanFreeMemory(connectionAttributes);
288 }
289
290 local_WlanFreeMemory(interfaceList);
291
292 return QString();
293}
294
295bool QNativeWifiEngine::hasIdentifier(const QString &id)
296{
297 QMutexLocker locker(&mutex);
298
299 if (!available())
300 return false;
301
302 // enumerate interfaces
303 WLAN_INTERFACE_INFO_LIST *interfaceList;
304 DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
305 if (result != ERROR_SUCCESS) {
306#ifdef BEARER_MANAGEMENT_DEBUG
307 qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
308#endif
309 return false;
310 }
311
312 for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
313 const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
314
315 WLAN_AVAILABLE_NETWORK_LIST *networkList;
316 result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
317 3, 0, &networkList);
318 if (result != ERROR_SUCCESS) {
319#ifdef BEARER_MANAGEMENT_DEBUG
320 qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
321 __FUNCTION__, result);
322#endif
323 continue;
324 }
325
326 for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
327 WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
328
329 QString networkName;
330
331 if (network.strProfileName[0] != 0) {
332 networkName = QString::fromWCharArray(network.strProfileName);
333 } else {
334 networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID),
335 network.dot11Ssid.uSSIDLength);
336 }
337
338 if (qHash(QLatin1String("WLAN:") + networkName) == id.toUInt()) {
339 local_WlanFreeMemory(networkList);
340 local_WlanFreeMemory(interfaceList);
341 return true;
342 }
343 }
344
345 local_WlanFreeMemory(networkList);
346 }
347
348 local_WlanFreeMemory(interfaceList);
349
350 return false;
351}
352
353void QNativeWifiEngine::connectToId(const QString &id)
354{
355 QMutexLocker locker(&mutex);
356
357 if (!available()) {
358 locker.unlock();
359 emit connectionError(id, InterfaceLookupError);
360 return;
361 }
362
363 WLAN_INTERFACE_INFO_LIST *interfaceList;
364 DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
365 if (result != ERROR_SUCCESS) {
366#ifdef BEARER_MANAGEMENT_DEBUG
367 qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
368#endif
369 locker.unlock();
370 emit connectionError(id, InterfaceLookupError);
371 return;
372 }
373
374 QString profile;
375
376 for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
377 const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
378
379 WLAN_AVAILABLE_NETWORK_LIST *networkList;
380 result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
381 3, 0, &networkList);
382 if (result != ERROR_SUCCESS) {
383#ifdef BEARER_MANAGEMENT_DEBUG
384 qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
385 __FUNCTION__, result);
386#endif
387 continue;
388 }
389
390 for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
391 WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
392
393 profile = QString::fromWCharArray(network.strProfileName);
394
395 if (qHash(QLatin1String("WLAN:") + profile) == id.toUInt())
396 break;
397 else
398 profile.clear();
399 }
400
401 local_WlanFreeMemory(networkList);
402
403 if (!profile.isEmpty()) {
404 WLAN_CONNECTION_PARAMETERS parameters;
405 parameters.wlanConnectionMode = wlan_connection_mode_profile;
406 parameters.strProfile = reinterpret_cast<LPCWSTR>(profile.utf16());
407 parameters.pDot11Ssid = 0;
408 parameters.pDesiredBssidList = 0;
409 parameters.dot11BssType = dot11_BSS_type_any;
410 parameters.dwFlags = 0;
411
412 DWORD result = local_WlanConnect(handle, &interface.InterfaceGuid, &parameters, 0);
413 if (result != ERROR_SUCCESS) {
414#ifdef BEARER_MANAGEMENT_DEBUG
415 qDebug("%s: WlanConnect failed with error %ld\n", __FUNCTION__, result);
416#endif
417 locker.unlock();
418 emit connectionError(id, ConnectError);
419 locker.relock();
420 break;
421 }
422
423 break;
424 }
425 }
426
427 local_WlanFreeMemory(interfaceList);
428
429 if (profile.isEmpty()) {
430 locker.unlock();
431 emit connectionError(id, InterfaceLookupError);
432 }
433}
434
435void QNativeWifiEngine::disconnectFromId(const QString &id)
436{
437 QMutexLocker locker(&mutex);
438
439 if (!available()) {
440 locker.unlock();
441 emit connectionError(id, InterfaceLookupError);
442 return;
443 }
444
445 QString interface = getInterfaceFromId(id);
446
447 if (interface.isEmpty()) {
448 locker.unlock();
449 emit connectionError(id, InterfaceLookupError);
450 return;
451 }
452
453 QStringList split = interface.mid(1, interface.length() - 2).split('-');
454
455 GUID guid;
456 guid.Data1 = split.at(0).toUInt(0, 16);
457 guid.Data2 = split.at(1).toUShort(0, 16);
458 guid.Data3 = split.at(2).toUShort(0, 16);
459 guid.Data4[0] = split.at(3).left(2).toUShort(0, 16);
460 guid.Data4[1] = split.at(3).right(2).toUShort(0, 16);
461 for (int i = 0; i < 6; ++i)
462 guid.Data4[i + 2] = split.at(4).mid(i*2, 2).toUShort(0, 16);
463
464 DWORD result = local_WlanDisconnect(handle, &guid, 0);
465 if (result != ERROR_SUCCESS) {
466#ifdef BEARER_MANAGEMENT_DEBUG
467 qDebug("%s: WlanDisconnect failed with error %ld\n", __FUNCTION__, result);
468#endif
469 locker.unlock();
470 emit connectionError(id, DisconnectionError);
471 return;
472 }
473}
474
475void QNativeWifiEngine::initialize()
476{
477 scanComplete();
478}
479
480void QNativeWifiEngine::requestUpdate()
481{
482 QMutexLocker locker(&mutex);
483
484 if (!available()) {
485 locker.unlock();
486 emit updateCompleted();
487 return;
488 }
489
490 // enumerate interfaces
491 WLAN_INTERFACE_INFO_LIST *interfaceList;
492 DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
493 if (result != ERROR_SUCCESS) {
494#ifdef BEARER_MANAGEMENT_DEBUG
495 qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
496#endif
497
498 locker.unlock();
499 emit updateCompleted();
500
501 return;
502 }
503
504 bool requested = false;
505 for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
506 result = local_WlanScan(handle, &interfaceList->InterfaceInfo[i].InterfaceGuid, 0, 0, 0);
507 if (result != ERROR_SUCCESS) {
508#ifdef BEARER_MANAGEMENT_DEBUG
509 qDebug("%s: WlanScan failed with error %ld\n", __FUNCTION__, result);
510#endif
511 } else {
512 requested = true;
513 }
514 }
515
516 local_WlanFreeMemory(interfaceList);
517
518 if (!requested) {
519 locker.unlock();
520 emit updateCompleted();
521 }
522}
523
524QNetworkSession::State QNativeWifiEngine::sessionStateForId(const QString &id)
525{
526 QMutexLocker locker(&mutex);
527
528 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
529
530 if (!ptr)
531 return QNetworkSession::Invalid;
532
533 if (!ptr->isValid) {
534 return QNetworkSession::Invalid;
535 } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
536 return QNetworkSession::Connected;
537 } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
538 QNetworkConfiguration::Discovered) {
539 return QNetworkSession::Disconnected;
540 } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
541 return QNetworkSession::NotAvailable;
542 } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
543 QNetworkConfiguration::Undefined) {
544 return QNetworkSession::NotAvailable;
545 }
546
547 return QNetworkSession::Invalid;
548}
549
550QNetworkConfigurationManager::Capabilities QNativeWifiEngine::capabilities() const
551{
552 return QNetworkConfigurationManager::ForcedRoaming |
553 QNetworkConfigurationManager::CanStartAndStopInterfaces;
554}
555
556QNetworkSessionPrivate *QNativeWifiEngine::createSessionBackend()
557{
558 return new QNetworkSessionPrivateImpl;
559}
560
561QNetworkConfigurationPrivatePointer QNativeWifiEngine::defaultConfiguration()
562{
563 return QNetworkConfigurationPrivatePointer();
564}
565
566bool QNativeWifiEngine::available()
567{
568 if (handle != INVALID_HANDLE_VALUE)
569 return true;
570
571 DWORD clientVersion;
572
573 DWORD result = local_WlanOpenHandle(1, 0, &clientVersion, &handle);
574 if (result != ERROR_SUCCESS) {
575#ifdef BEARER_MANAGEMENT_DEBUG
576 if (result != ERROR_SERVICE_NOT_ACTIVE)
577 qDebug("%s: WlanOpenHandle failed with error %ld\n", __FUNCTION__, result);
578#endif
579
580 return false;
581 }
582
583 result = local_WlanRegisterNotification(handle, WLAN_NOTIFICATION_SOURCE_ALL, true,
584 WLAN_NOTIFICATION_CALLBACK(qNotificationCallback),
585 this, 0, 0);
586#ifdef BEARER_MANAGEMENT_DEBUG
587 if (result != ERROR_SUCCESS)
588 qDebug("%s: WlanRegisterNotification failed with error %ld\n", __FUNCTION__, result);
589#endif
590
591 return handle != INVALID_HANDLE_VALUE;
592}
593
594void QNativeWifiEngine::closeHandle()
595{
596 if (handle != INVALID_HANDLE_VALUE) {
597 local_WlanCloseHandle(handle, 0);
598 handle = INVALID_HANDLE_VALUE;
599 }
600}
601
602bool QNativeWifiEngine::requiresPolling() const
603{
604 // On Windows XP SP2 and SP3 only connection and disconnection notifications are available.
605 // We need to poll for changes in available wireless networks.
606 return true;
607}
608
609QT_END_NAMESPACE
610
611#endif // QT_NO_BEARERMANAGEMENT
Note: See TracBrowser for help on using the repository browser.