1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 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 Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qcorewlanengine_mac_p.h" |
|
43 #include "qnetworkconfiguration_p.h" |
|
44 |
|
45 #include <QtCore/qthread.h> |
|
46 #include <QThread> |
|
47 #include <QtCore/qmutex.h> |
|
48 #include <QtCore/qcoreapplication.h> |
|
49 #include <QtCore/qstringlist.h> |
|
50 |
|
51 #include <QtCore/qdebug.h> |
|
52 |
|
53 #include <QDir> |
|
54 #if defined(MAC_SDK_10_6) //not much functionality without this |
|
55 #include <CoreWLAN/CoreWLAN.h> |
|
56 #include <CoreWLAN/CWInterface.h> |
|
57 #include <CoreWLAN/CWNetwork.h> |
|
58 #include <CoreWLAN/CWNetwork.h> |
|
59 #include <CoreWLAN/CW8021XProfile.h> |
|
60 |
|
61 #endif |
|
62 |
|
63 #include <Foundation/NSEnumerator.h> |
|
64 #include <Foundation/NSKeyValueObserving.h> |
|
65 #include <Foundation/NSAutoreleasePool.h> |
|
66 |
|
67 #include <SystemConfiguration/SCNetworkConfiguration.h> |
|
68 QMap <QString, QString> networkInterfaces; |
|
69 |
|
70 #ifdef MAC_SDK_10_6 |
|
71 @interface QNSListener : NSObject |
|
72 { |
|
73 NSNotificationCenter *center; |
|
74 CWInterface * currentInterface; |
|
75 } |
|
76 - (void)notificationHandler;//:(NSNotification *)notification; |
|
77 - (void)remove; |
|
78 @end |
|
79 |
|
80 @implementation QNSListener |
|
81 - (id) init |
|
82 { |
|
83 [super init]; |
|
84 center = [NSNotificationCenter defaultCenter]; |
|
85 currentInterface = [CWInterface interfaceWithName:nil]; |
|
86 [center addObserver:self selector:@selector(notificationHandler:) name:kCWLinkDidChangeNotification object:nil]; |
|
87 [center addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; |
|
88 |
|
89 return self; |
|
90 } |
|
91 |
|
92 -(void)dealloc |
|
93 { |
|
94 [center release]; |
|
95 [currentInterface release]; |
|
96 [super dealloc]; |
|
97 } |
|
98 |
|
99 -(void)remove |
|
100 { |
|
101 [center removeObserver:self]; |
|
102 } |
|
103 |
|
104 - (void)notificationHandler;//:(NSNotification *)notification |
|
105 { |
|
106 QTM_NAMESPACE::QCoreWlanEngine::instance()->requestUpdate(); |
|
107 } |
|
108 @end |
|
109 |
|
110 QNSListener *listener = 0; |
|
111 #endif |
|
112 |
|
113 QTM_BEGIN_NAMESPACE |
|
114 |
|
115 Q_GLOBAL_STATIC(QCoreWlanEngine, coreWlanEngine) |
|
116 |
|
117 inline QString cfstringRefToQstring(CFStringRef cfStringRef) { |
|
118 QString retVal; |
|
119 CFIndex maxLength = 2 * CFStringGetLength(cfStringRef) + 1/*zero term*/; // max UTF8 |
|
120 char *cstring = new char[maxLength]; |
|
121 if (CFStringGetCString(CFStringRef(cfStringRef), cstring, maxLength, kCFStringEncodingUTF8)) { |
|
122 retVal = QString::fromUtf8(cstring); |
|
123 } |
|
124 delete[] cstring; |
|
125 return retVal; |
|
126 } |
|
127 |
|
128 inline CFStringRef qstringToCFStringRef(const QString &string) |
|
129 { |
|
130 return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()), |
|
131 string.length()); |
|
132 } |
|
133 |
|
134 inline NSString *qstringToNSString(const QString &qstr) |
|
135 { return [reinterpret_cast<const NSString *>(qstringToCFStringRef(qstr)) autorelease]; } |
|
136 |
|
137 inline QString nsstringToQString(const NSString *nsstr) |
|
138 { return cfstringRefToQstring(reinterpret_cast<const CFStringRef>(nsstr)); } |
|
139 |
|
140 inline QStringList nsarrayToQStringList(void *nsarray) |
|
141 { |
|
142 QStringList result; |
|
143 NSArray *array = static_cast<NSArray *>(nsarray); |
|
144 for (NSUInteger i=0; i<[array count]; ++i) |
|
145 result << nsstringToQString([array objectAtIndex:i]); |
|
146 return result; |
|
147 } |
|
148 |
|
149 void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) |
|
150 { |
|
151 for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { |
|
152 |
|
153 CFStringRef changed = (CFStringRef)CFArrayGetValueAtIndex(changedKeys, i); |
|
154 if( cfstringRefToQstring(changed).contains("/Network/Global/IPv4")) { |
|
155 QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info); |
|
156 wlanEngine->requestUpdate(); |
|
157 } |
|
158 } |
|
159 return; |
|
160 } |
|
161 |
|
162 QScanThread::QScanThread(QObject *parent) |
|
163 :QThread(parent) |
|
164 { |
|
165 } |
|
166 |
|
167 QScanThread::~QScanThread() |
|
168 { |
|
169 } |
|
170 |
|
171 void QScanThread::quit() |
|
172 { |
|
173 wait(); |
|
174 } |
|
175 |
|
176 void QScanThread::run() |
|
177 { |
|
178 #if defined(MAC_SDK_10_6) |
|
179 getUserProfiles(); |
|
180 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
181 QStringList found; |
|
182 mutex.lock(); |
|
183 CWInterface *currentInterface; |
|
184 if(interfaceName.isEmpty()) { |
|
185 currentInterface = [CWInterface interfaceWithName:nil]; |
|
186 interfaceName = nsstringToQString([currentInterface name]); |
|
187 } else { |
|
188 currentInterface = [CWInterface interfaceWithName:qstringToNSString(interfaceName)]; |
|
189 } |
|
190 mutex.unlock(); |
|
191 |
|
192 if([currentInterface power]) { |
|
193 NSError *err = nil; |
|
194 NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: |
|
195 [NSNumber numberWithBool:YES], kCWScanKeyMerge, |
|
196 [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; |
|
197 |
|
198 NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; |
|
199 CWNetwork *apNetwork; |
|
200 |
|
201 if (!err) { |
|
202 for(uint row=0; row < [apArray count]; row++ ) { |
|
203 apNetwork = [apArray objectAtIndex:row]; |
|
204 |
|
205 const QString networkSsid = nsstringToQString([apNetwork ssid]); |
|
206 found.append(networkSsid); |
|
207 |
|
208 QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; |
|
209 |
|
210 bool known = isKnownSsid(networkSsid); |
|
211 if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { |
|
212 if( networkSsid == nsstringToQString( [currentInterface ssid])) { |
|
213 state = QNetworkConfiguration::Active; |
|
214 } |
|
215 } |
|
216 if(state == QNetworkConfiguration::Undefined) { |
|
217 if(known) { |
|
218 state = QNetworkConfiguration::Discovered; |
|
219 } else { |
|
220 state = QNetworkConfiguration::Undefined; |
|
221 } |
|
222 } |
|
223 |
|
224 QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; |
|
225 if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { |
|
226 purpose = QNetworkConfiguration::PublicPurpose; |
|
227 } else { |
|
228 purpose = QNetworkConfiguration::PrivatePurpose; |
|
229 } |
|
230 |
|
231 found.append(foundNetwork(networkSsid, networkSsid, state, interfaceName, purpose)); |
|
232 |
|
233 } //end row |
|
234 }//end error |
|
235 }// endwifi power |
|
236 |
|
237 // add known configurations that are not around. |
|
238 QMapIterator<QString, QMap<QString,QString> > i(userProfiles); |
|
239 while (i.hasNext()) { |
|
240 i.next(); |
|
241 |
|
242 QString networkName = i.key(); |
|
243 const QString id = networkName; |
|
244 |
|
245 if(!found.contains(id)) { |
|
246 QString networkSsid = getSsidFromNetworkName(networkName); |
|
247 const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); |
|
248 QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; |
|
249 QString interfaceName; |
|
250 QMapIterator<QString, QString> ij(i.value()); |
|
251 while (ij.hasNext()) { |
|
252 ij.next(); |
|
253 interfaceName = ij.value(); |
|
254 } |
|
255 |
|
256 if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { |
|
257 if( networkSsid == nsstringToQString([currentInterface ssid])) { |
|
258 state = QNetworkConfiguration::Active; |
|
259 } |
|
260 } |
|
261 if(state == QNetworkConfiguration::Undefined) { |
|
262 if( userProfiles.contains(networkName) |
|
263 && found.contains(ssidId)) { |
|
264 state = QNetworkConfiguration::Discovered; |
|
265 } |
|
266 } |
|
267 |
|
268 if(state == QNetworkConfiguration::Undefined) { |
|
269 state = QNetworkConfiguration::Defined; |
|
270 } |
|
271 |
|
272 found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); |
|
273 } |
|
274 } |
|
275 emit networksChanged(); |
|
276 [pool release]; |
|
277 #endif |
|
278 } |
|
279 |
|
280 QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) |
|
281 { |
|
282 QStringList found; |
|
283 QMutexLocker locker(&mutex); |
|
284 QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; |
|
285 |
|
286 ptr->name = name; |
|
287 ptr->isValid = true; |
|
288 ptr->id = id; |
|
289 ptr->state = state; |
|
290 ptr->type = QNetworkConfiguration::InternetAccessPoint; |
|
291 ptr->bearer = QLatin1String("WLAN"); |
|
292 ptr->purpose = purpose; |
|
293 ptr->internet = true; |
|
294 ptr->serviceInterface = QNetworkInterface::interfaceFromName(interfaceName); |
|
295 |
|
296 fetchedConfigurations.append( ptr); |
|
297 configurationInterface[name] = interfaceName; |
|
298 |
|
299 locker.unlock(); |
|
300 locker.relock(); |
|
301 found.append(id); |
|
302 return found; |
|
303 } |
|
304 |
|
305 QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations() |
|
306 { |
|
307 QMutexLocker locker(&mutex); |
|
308 |
|
309 QList<QNetworkConfigurationPrivate *> foundConfigurations; |
|
310 |
|
311 for (int i = 0; i < fetchedConfigurations.count(); ++i) { |
|
312 QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate; |
|
313 config->name = fetchedConfigurations.at(i)->name; |
|
314 config->isValid = fetchedConfigurations.at(i)->isValid; |
|
315 config->id = fetchedConfigurations.at(i)->id; |
|
316 config->state = fetchedConfigurations.at(i)->state; |
|
317 config->bearer = fetchedConfigurations.at(i)->bearer; |
|
318 config->type = fetchedConfigurations.at(i)->type; |
|
319 config->roamingSupported = fetchedConfigurations.at(i)->roamingSupported; |
|
320 config->purpose = fetchedConfigurations.at(i)->purpose; |
|
321 config->internet = fetchedConfigurations.at(i)->internet; |
|
322 foundConfigurations.append(config); |
|
323 } |
|
324 |
|
325 return foundConfigurations; |
|
326 } |
|
327 |
|
328 void QScanThread::getUserProfiles() |
|
329 { |
|
330 #if defined(MAC_SDK_10_6) |
|
331 QMutexLocker locker(&mutex); |
|
332 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
333 userProfiles.clear(); |
|
334 |
|
335 NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; |
|
336 for(uint row=0; row < [wifiInterfaces count]; row++ ) { |
|
337 |
|
338 CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; |
|
339 if (![wifiInterface power]) |
|
340 continue; |
|
341 |
|
342 NSString *nsInterfaceName = [wifiInterface name]; |
|
343 // add user configured system networks |
|
344 SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); |
|
345 NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); |
|
346 CFRelease(dynRef); |
|
347 |
|
348 NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; |
|
349 |
|
350 NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; |
|
351 NSEnumerator *ssidEnumerator = [thisSsidarray objectEnumerator]; |
|
352 NSString *ssidkey; |
|
353 while ((ssidkey = [ssidEnumerator nextObject])) { |
|
354 QString thisSsid = nsstringToQString(ssidkey); |
|
355 if(!userProfiles.contains(thisSsid)) { |
|
356 QMap <QString,QString> map; |
|
357 map.insert(thisSsid, nsstringToQString(nsInterfaceName)); |
|
358 userProfiles.insert(thisSsid, map); |
|
359 } |
|
360 } |
|
361 CFRelease(airportPlist); |
|
362 |
|
363 // 802.1X user profiles |
|
364 QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; |
|
365 NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qstringToNSString(userProfilePath)] autorelease]; |
|
366 NSString *profileStr= @"Profiles"; |
|
367 NSString *nameStr = @"UserDefinedName"; |
|
368 NSString *networkSsidStr = @"Wireless Network"; |
|
369 |
|
370 id profileKey; |
|
371 NSEnumerator *dictEnumerator = [eapDict objectEnumerator]; |
|
372 while ((profileKey = [dictEnumerator nextObject])) { |
|
373 |
|
374 if ([profileStr isEqualToString:profileKey]) { |
|
375 NSDictionary *itemDict = [eapDict objectForKey:profileKey]; |
|
376 id itemKey; |
|
377 NSEnumerator *dictEnumerator = [thisSsidarray objectEnumerator]; |
|
378 while ((itemKey = [dictEnumerator nextObject])) { |
|
379 |
|
380 NSInteger dictSize = [itemKey count]; |
|
381 id objects[dictSize]; |
|
382 id keys[dictSize]; |
|
383 |
|
384 [itemKey getObjects:objects andKeys:keys]; |
|
385 QString networkName; |
|
386 QString ssid; |
|
387 for(int i = 0; i < dictSize; i++) { |
|
388 if([nameStr isEqualToString:keys[i]]) { |
|
389 networkName = nsstringToQString(objects[i]); |
|
390 } |
|
391 if([networkSsidStr isEqualToString:keys[i]]) { |
|
392 ssid = nsstringToQString(objects[i]); |
|
393 } |
|
394 if(!userProfiles.contains(networkName) |
|
395 && !ssid.isEmpty()) { |
|
396 QMap<QString,QString> map; |
|
397 map.insert(ssid, nsstringToQString(nsInterfaceName)); |
|
398 userProfiles.insert(networkName, map); |
|
399 } |
|
400 } |
|
401 } |
|
402 } |
|
403 } |
|
404 } |
|
405 |
|
406 [pool release]; |
|
407 #endif |
|
408 } |
|
409 |
|
410 QString QScanThread::getSsidFromNetworkName(const QString &name) |
|
411 { |
|
412 QMutexLocker locker(&mutex); |
|
413 QMapIterator<QString, QMap<QString,QString> > i(userProfiles); |
|
414 while (i.hasNext()) { |
|
415 i.next(); |
|
416 QMap<QString,QString> map = i.value(); |
|
417 QMapIterator<QString, QString> ij(i.value()); |
|
418 while (ij.hasNext()) { |
|
419 ij.next(); |
|
420 const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); |
|
421 if(name == i.key() || name == networkNameHash) { |
|
422 return ij.key(); |
|
423 } |
|
424 } |
|
425 } |
|
426 return QString(); |
|
427 } |
|
428 |
|
429 QString QScanThread::getNetworkNameFromSsid(const QString &ssid) |
|
430 { |
|
431 QMutexLocker locker(&mutex); |
|
432 QMapIterator<QString, QMap<QString,QString> > i(userProfiles); |
|
433 while (i.hasNext()) { |
|
434 i.next(); |
|
435 QMap<QString,QString> map = i.value(); |
|
436 QMapIterator<QString, QString> ij(i.value()); |
|
437 while (ij.hasNext()) { |
|
438 ij.next(); |
|
439 if(ij.key() == ssid) { |
|
440 return i.key(); |
|
441 } |
|
442 } |
|
443 } |
|
444 return QString(); |
|
445 } |
|
446 |
|
447 bool QScanThread::isKnownSsid(const QString &ssid) |
|
448 { |
|
449 QMutexLocker locker(&mutex); |
|
450 |
|
451 QMapIterator<QString, QMap<QString,QString> > i(userProfiles); |
|
452 while (i.hasNext()) { |
|
453 i.next(); |
|
454 QMap<QString,QString> map = i.value(); |
|
455 if(map.keys().contains(ssid)) { |
|
456 return true; |
|
457 } |
|
458 } |
|
459 return false; |
|
460 } |
|
461 |
|
462 |
|
463 QCoreWlanEngine::QCoreWlanEngine(QObject *parent) |
|
464 : QNetworkSessionEngine(parent) |
|
465 { |
|
466 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
467 getAllScInterfaces(); |
|
468 scanThread = new QScanThread(this); |
|
469 connect(scanThread, SIGNAL(networksChanged()), |
|
470 this, SIGNAL(configurationsChanged())); |
|
471 |
|
472 QTimer::singleShot(0,this,SLOT(init())); |
|
473 [pool release]; |
|
474 } |
|
475 |
|
476 QCoreWlanEngine::~QCoreWlanEngine() |
|
477 { |
|
478 QNetworkConfigurationPrivate* cpPriv = 0; |
|
479 foundConfigurations.clear(); |
|
480 while(!foundConfigurations.isEmpty()) { |
|
481 cpPriv = foundConfigurations.takeFirst(); |
|
482 delete cpPriv; |
|
483 } |
|
484 } |
|
485 |
|
486 void QCoreWlanEngine::init() |
|
487 { |
|
488 #ifdef MAC_SDK_10_6 |
|
489 if([[CWInterface supportedInterfaces] count] > 0 && !listener) { |
|
490 listener = [[QNSListener alloc] init]; |
|
491 hasWifi = true; |
|
492 } else { |
|
493 hasWifi = false; |
|
494 } |
|
495 #endif |
|
496 storeSession = NULL; |
|
497 scanThread->start(); |
|
498 |
|
499 startNetworkChangeLoop(); |
|
500 } |
|
501 |
|
502 |
|
503 QList<QNetworkConfigurationPrivate *> QCoreWlanEngine::getConfigurations(bool *ok) |
|
504 { |
|
505 if (ok) |
|
506 *ok = true; |
|
507 foundConfigurations.clear(); |
|
508 |
|
509 QNetworkConfigurationPrivate* cpPriv = 0; |
|
510 QMutexLocker locker(&mutex); |
|
511 QList<QNetworkConfigurationPrivate *> fetchedConfigurations = scanThread->getConfigurations(); |
|
512 locker.unlock(); |
|
513 |
|
514 for (int i = 0; i < fetchedConfigurations.count(); ++i) { |
|
515 |
|
516 QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate(); |
|
517 cpPriv = fetchedConfigurations.at(i); |
|
518 config->name = cpPriv->name; |
|
519 config->isValid = cpPriv->isValid; |
|
520 config->id = cpPriv->id; |
|
521 config->state = cpPriv->state; |
|
522 config->type = cpPriv->type; |
|
523 config->roamingSupported = cpPriv->roamingSupported; |
|
524 config->purpose = cpPriv->purpose; |
|
525 config->internet = cpPriv->internet; |
|
526 config->serviceInterface = cpPriv->serviceInterface; |
|
527 config->bearer = cpPriv->bearer; |
|
528 |
|
529 foundConfigurations.append(config); |
|
530 delete cpPriv; |
|
531 } |
|
532 |
|
533 |
|
534 return foundConfigurations; |
|
535 } |
|
536 |
|
537 QString QCoreWlanEngine::getInterfaceFromId(const QString &id) |
|
538 { |
|
539 return scanThread->configurationInterface.value(id); |
|
540 } |
|
541 |
|
542 bool QCoreWlanEngine::hasIdentifier(const QString &id) |
|
543 { |
|
544 return scanThread->configurationInterface.contains(id); |
|
545 } |
|
546 |
|
547 void QCoreWlanEngine::connectToId(const QString &id) |
|
548 { |
|
549 QString interfaceString = getInterfaceFromId(id); |
|
550 |
|
551 if(networkInterfaces.value(interfaceString) == "WLAN") { |
|
552 #if defined(MAC_SDK_10_6) |
|
553 NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
|
554 CWInterface *wifiInterface = [CWInterface interfaceWithName: qstringToNSString(interfaceString)]; |
|
555 |
|
556 if([wifiInterface power]) { |
|
557 NSError *err = nil; |
|
558 NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; |
|
559 |
|
560 QString wantedSsid = 0; |
|
561 bool using8021X = false; |
|
562 |
|
563 if(scanThread->getNetworkNameFromSsid(id) != id) { |
|
564 NSArray *array = [CW8021XProfile allUser8021XProfiles]; |
|
565 for (NSUInteger i=0; i<[array count]; ++i) { |
|
566 |
|
567 if(id == nsstringToQString([[array objectAtIndex:i] userDefinedName]) |
|
568 || id == nsstringToQString([[array objectAtIndex:i] ssid]) ) { |
|
569 QString thisName = scanThread->getSsidFromNetworkName(id); |
|
570 if(thisName.isEmpty()) { |
|
571 wantedSsid = id; |
|
572 } else { |
|
573 wantedSsid = thisName; |
|
574 } |
|
575 [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; |
|
576 using8021X = true; |
|
577 break; |
|
578 } |
|
579 } |
|
580 } |
|
581 |
|
582 if(!using8021X) { |
|
583 QString wantedNetwork; |
|
584 QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); |
|
585 while (i.hasNext()) { |
|
586 i.next(); |
|
587 wantedNetwork = i.key(); |
|
588 if(id == wantedNetwork) { |
|
589 wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); |
|
590 break; |
|
591 } |
|
592 } |
|
593 } |
|
594 |
|
595 NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: |
|
596 [NSNumber numberWithBool:YES], kCWScanKeyMerge, |
|
597 [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, |
|
598 [NSNumber numberWithInteger:100], kCWScanKeyRestTime, |
|
599 qstringToNSString(wantedSsid), kCWScanKeySSID, |
|
600 nil]; |
|
601 |
|
602 NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:parametersDict error:&err]; |
|
603 if(!err) { |
|
604 for(uint row=0; row < [scanArray count]; row++ ) { |
|
605 CWNetwork *apNetwork = [scanArray objectAtIndex:row]; |
|
606 if(wantedSsid == nsstringToQString([apNetwork ssid])) { |
|
607 |
|
608 if(!using8021X) { |
|
609 SecKeychainAttribute attributes[3]; |
|
610 |
|
611 NSString *account = [apNetwork ssid]; |
|
612 NSString *keyKind = @"AirPort network password"; |
|
613 NSString *keyName = account; |
|
614 |
|
615 attributes[0].tag = kSecAccountItemAttr; |
|
616 attributes[0].data = (void *)[account UTF8String]; |
|
617 attributes[0].length = [account length]; |
|
618 |
|
619 attributes[1].tag = kSecDescriptionItemAttr; |
|
620 attributes[1].data = (void *)[keyKind UTF8String]; |
|
621 attributes[1].length = [keyKind length]; |
|
622 |
|
623 attributes[2].tag = kSecLabelItemAttr; |
|
624 attributes[2].data = (void *)[keyName UTF8String]; |
|
625 attributes[2].length = [keyName length]; |
|
626 |
|
627 SecKeychainAttributeList attributeList = {3,attributes}; |
|
628 |
|
629 SecKeychainSearchRef searchRef; |
|
630 OSErr result = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); |
|
631 Q_UNUSED(result); |
|
632 NSString *password = @""; |
|
633 SecKeychainItemRef searchItem; |
|
634 OSStatus resultStatus; |
|
635 resultStatus = SecKeychainSearchCopyNext(searchRef, &searchItem); |
|
636 |
|
637 if (resultStatus == errSecSuccess) { |
|
638 UInt32 realPasswordLength; |
|
639 SecKeychainAttribute attributesW[8]; |
|
640 attributesW[0].tag = kSecAccountItemAttr; |
|
641 SecKeychainAttributeList listW = {1,attributesW}; |
|
642 char *realPassword; |
|
643 OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); |
|
644 |
|
645 if (status == noErr) { |
|
646 if (realPassword != NULL) { |
|
647 |
|
648 QByteArray pBuf; |
|
649 pBuf.resize(realPasswordLength); |
|
650 pBuf.prepend(realPassword); |
|
651 pBuf.insert(realPasswordLength,'\0'); |
|
652 |
|
653 password = [NSString stringWithUTF8String:pBuf]; |
|
654 } |
|
655 } |
|
656 |
|
657 CFRelease(searchItem); |
|
658 SecKeychainItemFreeContent(&listW, realPassword); |
|
659 } else { |
|
660 qDebug() << "SecKeychainSearchCopyNext error" << cfstringRefToQstring(SecCopyErrorMessageString(resultStatus, NULL)); |
|
661 } |
|
662 [params setValue: password forKey: kCWAssocKeyPassphrase]; |
|
663 } // end using8021X |
|
664 |
|
665 bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; |
|
666 |
|
667 if(!result) { |
|
668 emit connectionError(id, ConnectError); |
|
669 } else { |
|
670 [autoreleasepool release]; |
|
671 return; |
|
672 } |
|
673 } |
|
674 } |
|
675 } else { |
|
676 qDebug() <<"ERROR"<< nsstringToQString([err localizedDescription ]); |
|
677 } |
|
678 |
|
679 emit connectionError(id, InterfaceLookupError); |
|
680 [autoreleasepool release]; |
|
681 |
|
682 } else { |
|
683 qDebug() << "wifi power off"; |
|
684 // not wifi |
|
685 } |
|
686 #endif |
|
687 } |
|
688 emit connectionError(id, OperationNotSupported); |
|
689 } |
|
690 |
|
691 void QCoreWlanEngine::disconnectFromId(const QString &id) |
|
692 { |
|
693 QString interfaceString = getInterfaceFromId(id); |
|
694 if(networkInterfaces.value(getInterfaceFromId(id)) == "WLAN") { //wifi only for now |
|
695 #if defined(MAC_SDK_10_6) |
|
696 NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
|
697 CWInterface *wifiInterface = [CWInterface interfaceWithName: qstringToNSString(interfaceString)]; |
|
698 [wifiInterface disassociate]; |
|
699 if([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { |
|
700 emit connectionError(id, DisconnectionError); |
|
701 } |
|
702 [autoreleasepool release]; |
|
703 return; |
|
704 #endif |
|
705 } else { |
|
706 |
|
707 } |
|
708 emit connectionError(id, OperationNotSupported); |
|
709 } |
|
710 |
|
711 void QCoreWlanEngine::requestUpdate() |
|
712 { |
|
713 getAllScInterfaces(); |
|
714 scanThread->getUserProfiles(); |
|
715 scanThread->start(); |
|
716 } |
|
717 |
|
718 QCoreWlanEngine *QCoreWlanEngine::instance() |
|
719 { |
|
720 return coreWlanEngine(); |
|
721 } |
|
722 |
|
723 bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) |
|
724 { |
|
725 #if defined(MAC_SDK_10_6) |
|
726 if([[CWInterface supportedInterfaces] count] > 0 ) { |
|
727 CWInterface *defaultInterface = [CWInterface interfaceWithName: qstringToNSString(wifiDeviceName)]; |
|
728 if([defaultInterface power]) |
|
729 return true; |
|
730 } |
|
731 #else |
|
732 Q_UNUSED(wifiDeviceName); |
|
733 #endif |
|
734 return false; |
|
735 } |
|
736 |
|
737 bool QCoreWlanEngine::getAllScInterfaces() |
|
738 { |
|
739 networkInterfaces.clear(); |
|
740 NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
|
741 |
|
742 CFArrayRef interfaces = SCNetworkInterfaceCopyAll(); |
|
743 if (interfaces != NULL) { |
|
744 CFIndex interfaceCount; |
|
745 CFIndex interfaceIndex; |
|
746 interfaceCount = CFArrayGetCount(interfaces); |
|
747 for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) { |
|
748 NSAutoreleasePool *looppool = [[NSAutoreleasePool alloc] init]; |
|
749 |
|
750 CFStringRef bsdName; |
|
751 CFTypeRef thisInterface = CFArrayGetValueAtIndex(interfaces, interfaceIndex); |
|
752 bsdName = SCNetworkInterfaceGetBSDName((SCNetworkInterfaceRef)thisInterface); |
|
753 QString interfaceName = cfstringRefToQstring(bsdName); |
|
754 QString typeStr; |
|
755 CFStringRef type = SCNetworkInterfaceGetInterfaceType((SCNetworkInterfaceRef)thisInterface); |
|
756 if ( CFEqual(type, kSCNetworkInterfaceTypeIEEE80211)) { |
|
757 typeStr = "WLAN"; |
|
758 // } else if (CFEqual(type, kSCNetworkInterfaceTypeBluetooth)) { |
|
759 // typeStr = "Bluetooth"; |
|
760 } else if(CFEqual(type, kSCNetworkInterfaceTypeEthernet)) { |
|
761 typeStr = "Ethernet"; |
|
762 } else if(CFEqual(type, kSCNetworkInterfaceTypeFireWire)) { |
|
763 typeStr = "Ethernet"; //ok a bit fudged |
|
764 } |
|
765 if(!networkInterfaces.contains(interfaceName) && !typeStr.isEmpty()) { |
|
766 networkInterfaces.insert(interfaceName,typeStr); |
|
767 } |
|
768 [looppool release]; |
|
769 } |
|
770 } |
|
771 CFRelease(interfaces); |
|
772 |
|
773 [autoreleasepool drain]; |
|
774 return true; |
|
775 } |
|
776 |
|
777 void QCoreWlanEngine::startNetworkChangeLoop() |
|
778 { |
|
779 storeSession = NULL; |
|
780 |
|
781 SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; |
|
782 storeSession = SCDynamicStoreCreate(NULL, |
|
783 CFSTR("networkChangeCallback"), |
|
784 networkChangeCallback, |
|
785 &dynStoreContext); |
|
786 if (!storeSession ) { |
|
787 qDebug() << "could not open dynamic store: error:" << SCErrorString(SCError()); |
|
788 return; |
|
789 } |
|
790 |
|
791 CFMutableArrayRef notificationKeys; |
|
792 notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
|
793 CFMutableArrayRef patternsArray; |
|
794 patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
|
795 |
|
796 CFStringRef storeKey; |
|
797 storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, |
|
798 kSCDynamicStoreDomainState, |
|
799 kSCEntNetIPv4); |
|
800 CFArrayAppendValue(notificationKeys, storeKey); |
|
801 CFRelease(storeKey); |
|
802 |
|
803 storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, |
|
804 kSCDynamicStoreDomainState, |
|
805 kSCCompAnyRegex, |
|
806 kSCEntNetIPv4); |
|
807 CFArrayAppendValue(patternsArray, storeKey); |
|
808 CFRelease(storeKey); |
|
809 |
|
810 if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { |
|
811 qDebug() << "register notification error:"<< SCErrorString(SCError()); |
|
812 CFRelease(storeSession ); |
|
813 CFRelease(notificationKeys); |
|
814 CFRelease(patternsArray); |
|
815 return; |
|
816 } |
|
817 CFRelease(notificationKeys); |
|
818 CFRelease(patternsArray); |
|
819 |
|
820 runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); |
|
821 if (!runloopSource) { |
|
822 qDebug() << "runloop source error:"<< SCErrorString(SCError()); |
|
823 CFRelease(storeSession ); |
|
824 return; |
|
825 } |
|
826 |
|
827 CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); |
|
828 return; |
|
829 } |
|
830 #include "moc_qcorewlanengine_mac_p.cpp" |
|
831 |
|
832 QTM_END_NAMESPACE |
|