[qnut] fixed main window show/hide on tray icon click event
[nut.git] / libnutwireless / base.cpp
blobc3d9fdad9199a53bf49966c97cd4c1b557fffaaf
1 #include "base.h"
2 #include <QDebug>
4 namespace libnutwireless {
6 //CWpa_supplicant
9 //Wpa_supplicant control commands:
10 QString CWpaSupplicantBase::wpaCtrlCommand(QString cmd = "PING") {
11 //int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
12 // char *reply, size_t *reply_len,
13 // void (*msg_cb)(char *msg, size_t len));
14 //
15 //Check if we have a control interface:
16 if (cmd_ctrl == NULL || event_ctrl == NULL) {
17 return QString();
19 if (!m_wpaConnected or m_inConnectionPhase) {
20 return QString();
22 //First Check if wpa_supplicant is running:
23 QByteArray command("PING");
24 char reply[4096];
25 size_t reply_len = sizeof(reply);
27 int status = wpa_ctrl_request(cmd_ctrl, command.constData(), command.size(), reply, &reply_len,NULL);
28 if ( (status != 0) or (QString::fromUtf8(reply, reply_len) != "PONG\n") ) {
29 qDebug() << QString("(status=%2)PING COMMAND RESPONSE: %1").arg(QString::fromUtf8(reply, reply_len),QString::number(status));
30 closeWpa("wpaCtrlCommand/nopong");
31 return QString();
33 if (cmd != "PING") {
34 size_t reply_len = sizeof(reply);
36 command = cmd.toAscii();
38 status = wpa_ctrl_request(cmd_ctrl, command.constData(), command.size(), reply, &reply_len,NULL);
39 if (0 == status) {
40 qDebug() << cmd + " : " + QString::fromUtf8(reply, reply_len) + " EOC";
41 if (reply_len > 0) {
42 return QString::fromUtf8(reply, reply_len);
44 else {
45 return QString();
48 else {
49 return QString();
52 else { //PING command requested
53 qDebug() << cmd << ":" << QString::fromUtf8(reply, reply_len) << "EOC";
54 return QString::fromUtf8(reply, reply_len);
63 // void CWpaSupplicantBase::printMessage(QString msg) {
64 // if (m_logEnabled) {
65 // emit(message(msg));
66 // }
67 // }
70 //Private slots:
71 //Reads messages from wpa_supplicant
72 void CWpaSupplicantBase::readFromWpa(int socket) {
73 if (socket == m_wpaFd) {
74 if (m_wpaConnected) {
75 //check if wpa_supplicant is still running (i.e. file exists)
76 if (! QFile::exists(m_wpaSupplicantPath)) {
77 closeWpa("readFromWpa/no wpa interface on event");
78 return;
80 //status: 1 = msg available; 0 = no messages, -1 = error
81 int status = wpa_ctrl_pending(event_ctrl);
82 if (1 == status) {
83 //Receive Messages
84 char reply[512];
85 size_t reply_len = sizeof(reply);
86 wpa_ctrl_recv(event_ctrl, reply, &reply_len);
87 eventDispatcher(QString::fromUtf8(reply, reply_len));
89 else if (-1 == status) {
90 qWarning() << tr("Error while trying to receive messages from wpa_supplicant");
98 //CTRL-RSP-<field name>-<network id>-<value>
101 CTRL-EVENT-DISCONNECTED
102 CTRL-EVENT-CONNECTED
104 void CWpaSupplicantBase::eventDispatcher(Request req) {
105 if (req.type != REQ_FAIL) {
106 emit(request(req));
109 void CWpaSupplicantBase::eventDispatcher(EventType event, QString str) {
110 if (event == EVENT_CONNECTED) {
111 emit(connectionStateChanged(true,parseEventNetworkId(str)));
112 emit(networkListUpdated());
114 else if (event == EVENT_DISCONNECTED) {
115 emit(connectionStateChanged(false,parseEventNetworkId(str)));
117 else if (event == EVENT_TERMINATING) {
118 closeWpa("event-dispatcher/wpa-TERMINATING");
120 else {
121 emit(eventMessage(event));
125 void CWpaSupplicantBase::eventDispatcher(QString event) {
126 QStringList str_list = event.split('\n',QString::KeepEmptyParts);
127 InteractiveType type;
128 foreach(QString str, str_list) {
129 type = parseInteract(str);
130 switch (type) {
131 case (INTERACT_REQ):
132 eventDispatcher(parseReq(str));
133 break;
134 case (INTERACT_EVENT):
135 eventDispatcher(parseEvent(str),str);
136 break;
137 default:
138 printMessage(str);
139 break;
144 //Public functions:
145 CWpaSupplicantBase::CWpaSupplicantBase(QObject * parent, QString m_ifname) : QObject(parent), cmd_ctrl(0), event_ctrl(0), m_wpaSupplicantPath("/var/run/wpa_supplicant/"+m_ifname), m_wpaFd(-1), m_wextFd(-1), m_eventSn(0), m_connectTimerId(-1), m_wextTimerId(-1), m_scanTimerId(-1), m_wextTimerRate(10000), m_ifname(m_ifname), m_scanTimeoutCount(0),m_wextPollTimeoutCount(0) {
146 m_wpaConnected = false;
147 m_timerCount = 0;
148 m_logEnabled = true;
150 //Workaround as constructor of subclass is not beeing called
151 m_apScanDefault = -1;
152 qDebug() << (QString("Constructor set ap_scan=%1").arg(QString::number(m_apScanDefault)));
153 m_lastWasAdHoc = false;
154 qDebug() << (QString("Constructor set m_lastWasAdHoc=%1").arg((m_lastWasAdHoc) ? "true" : "false"));
157 connect(QCoreApplication::instance(),SIGNAL(aboutToQuit ()),this,SLOT(detachWpa()));
159 CWpaSupplicantBase::~CWpaSupplicantBase() {
160 closeWpa("destructor");
162 void CWpaSupplicantBase::openWpa(bool) {
163 if (m_connectTimerId != -1) {
164 killTimer(m_connectTimerId);
165 m_connectTimerId = -1;
167 if (m_wextTimerId != -1) {
168 killTimer(m_wextTimerId);
169 m_wextTimerId = -1;
171 if (m_wpaConnected) return;
172 int status;
173 //Open wpa_supplicant control interface
174 if (!QFile::exists(m_wpaSupplicantPath)) {
175 qWarning() << tr("Could not open wpa_supplicant socket: %1").arg(QString::number(m_timerCount));
176 m_inConnectionPhase = true;
177 m_connectTimerId = startTimer(dynamicTimerTime(m_timerCount));
178 return;
180 cmd_ctrl = wpa_ctrl_open(m_wpaSupplicantPath.toAscii().constData());
181 event_ctrl = wpa_ctrl_open(m_wpaSupplicantPath.toAscii().constData());
182 if (cmd_ctrl == NULL and event_ctrl == NULL) {
183 qWarning() << tr("Could not open wpa_supplicant control interface");
184 m_inConnectionPhase = true;
185 m_connectTimerId = startTimer(dynamicTimerTime(m_timerCount));
186 return;
188 if (cmd_ctrl == NULL) {
189 wpa_ctrl_close(event_ctrl);
190 event_ctrl = NULL;
191 qWarning() << tr("Could not open wpa_supplicant control interface");
192 m_inConnectionPhase = true;
193 m_connectTimerId = startTimer(dynamicTimerTime(m_timerCount));
194 return;
196 if (event_ctrl == NULL) {
197 wpa_ctrl_close(cmd_ctrl);
198 cmd_ctrl = NULL;
199 qWarning() << tr("Could not open wpa_supplicant control interface");
200 m_inConnectionPhase = true;
201 m_connectTimerId = startTimer(dynamicTimerTime(m_timerCount));
202 return;
205 //Atach event monitor
206 status = wpa_ctrl_attach(event_ctrl);
207 //Status : 0 = succ; -1 = fail, -2 = timeout
208 if (status != 0) {
209 wpa_ctrl_close(event_ctrl);
210 wpa_ctrl_close(cmd_ctrl);
211 event_ctrl = NULL;
212 cmd_ctrl = NULL;
213 qWarning() << tr("Could not attach to wpa_supplicant");
214 m_inConnectionPhase = true;
215 m_connectTimerId = startTimer(dynamicTimerTime(m_timerCount));
216 return;
218 m_inConnectionPhase = false;
219 m_timerCount = 0;
220 //Set socket notifier
221 m_wpaFd = wpa_ctrl_get_fd(event_ctrl);
222 m_eventSn = new QSocketNotifier(m_wpaFd, QSocketNotifier::Read,NULL);
223 connect(m_eventSn,SIGNAL(activated(int)),this,SLOT(readFromWpa(int)));
224 m_eventSn->setEnabled(true);
225 m_wpaConnected = true;
227 //NEW FEATURE: Signal level retrieving:
229 //Get file Descriptor to NET kernel
230 if ( (m_wextFd = iw_sockets_open()) < 0) {
231 m_wextFd = -1;
232 qWarning() << tr("ERROR: Could not open socket to net kernel");
234 else { //Socket is set up, now set SocketNotifier
235 qDebug() << QString("File Descriptor for Wext is: %1").arg(QString::number(m_wextFd));
238 //Start timer for reading wireless info (like in /proc/net/wireless)
239 m_wextTimerId = startTimer(m_wextTimerRate);
241 //Set ap_scan default
242 setApScanDefault();
244 //Continue of old features:
245 emit(stateChanged(true));
246 printMessage(tr("wpa_supplicant connection established"));
247 return;
250 bool CWpaSupplicantBase::closeWpa(QString call_func, bool internal) {
251 if (m_connectTimerId != -1) {
252 killTimer(m_connectTimerId);
253 m_connectTimerId = -1;
254 m_inConnectionPhase = false;
255 m_timerCount = 0;
257 if (m_wextTimerId != -1) {
258 killTimer(m_wextTimerId);
259 m_wextTimerId = -1;
261 if (m_wpaConnected) {
262 if (m_eventSn != NULL) {
263 disconnect(m_eventSn,SIGNAL(activated(int)),this,SLOT(readFromWpa(int)));
264 delete m_eventSn;
265 m_eventSn = NULL;
267 if (-1 != m_wextFd) {
268 iw_sockets_close(m_wextFd);
269 m_wextFd = -1;
271 //Detaching takes place if program is about to quit
272 //Close control connections
273 wpa_ctrl_close(event_ctrl);
274 wpa_ctrl_close(cmd_ctrl);
275 event_ctrl = NULL;
276 cmd_ctrl = NULL;
277 m_wpaConnected = false;
278 emit(stateChanged(false));
280 printMessage(tr("(%1)[%2] wpa_supplicant disconnected").arg(((internal) ? "internal" : "external"),call_func));
281 return true;
283 int CWpaSupplicantBase::dynamicTimerTime(int m_timerCount) {
284 if (m_timerCount > 0) {
285 if (m_timerCount <= 5) {
286 return 1000;
288 if (m_timerCount <= 10) {
289 return 3000;
291 if (m_timerCount <= 15) {
292 return 10000;
294 return 30000;
296 else {
297 return 0;
302 //Slot is executed when aplication is about to quit;
303 void CWpaSupplicantBase::detachWpa() {
304 if (event_ctrl != NULL) {
305 wpa_ctrl_detach(event_ctrl);
309 void CWpaSupplicantBase::setScanResults(QList<WextRawScan> wextScanResults) {
310 QString response = wpaCtrlCmd_SCAN_RESULTS();
311 if (response.isEmpty()) {
312 m_wpaScanResults = QList<ScanResult>();
313 return;
315 else {
316 //Set scan results from wpa_supplicant:
317 m_wpaScanResults = parseScanResult(sliceMessage(response));
318 //This may not be possible as qHash references an namespace that is unknown to qt TODO:CHECK!
319 QHash<QString,WextScan> wextScanHash; //Namespace problem
320 WextScan wextScan;
321 foreach(WextRawScan i, wextScanResults) {
322 wextScan.ssid = i.ssid;
323 wextScan.bssid = i.bssid;
324 wextScan.signal = convertValues(i);
325 wextScan.hasRange = i.hasRange;
326 wextScan.we_version_compiled = i.we_version_compiled;
327 wextScan.freq = i.freq;
328 wextScan.group = i.group;
329 wextScan.pairwise = i.pairwise;
330 wextScan.keyManagement = i.keyManagement;
331 wextScan.protocols = i.protocols;
332 wextScan.opmode = i.opmode;
333 wextScan.bitrates = i.bitrates;
334 wextScanHash.insert(i.bssid.toString(), wextScan);
336 WextScan dummy;
337 int count = 0;
338 QHash<QString,WextScan>::iterator wextScanHashIter;
339 //Set the signal quality and so on
340 for (QList<ScanResult>::Iterator i = m_wpaScanResults.begin(); i != m_wpaScanResults.end(); ++i ) {
341 if (wextScanHash.contains(i->bssid.toString())) { //We do have this network in our wext list
342 wextScanHashIter = wextScanHash.find(i->bssid.toString());
343 //Workaround for some cards that send wrong information via wext.
344 //If ssid is hidden (empty), then we do not set the information from the wext.
345 i->bssid = wextScanHashIter.value().bssid;
346 if (!wextScanHashIter.value().ssid.isEmpty() && i->ssid.isEmpty()) {
347 i->ssid = "<hidden>";
349 else if (!wextScanHashIter.value().ssid.isEmpty()) {
350 i->ssid = wextScanHashIter.value().ssid;
352 if (-1 != frequencyToChannel(wextScanHashIter.value().freq)) {
353 i->freq = wextScanHashIter.value().freq;
355 i->signal = wextScanHashIter.value().signal;
356 i->group = wextScanHashIter.value().group;
357 i->pairwise = wextScanHashIter.value().pairwise;
358 i->keyManagement = wextScanHashIter.value().keyManagement;
359 i->protocols = wextScanHashIter.value().protocols;
360 i->opmode = wextScanHashIter.value().opmode;
361 i->bitrates = wextScanHashIter.value().bitrates;
362 wextScanHash.erase(wextScanHashIter);
363 count++;
365 else { //Network is unknown to wext, add level type information
366 if (m_signalQuality.type != WSR_UNKNOWN) {
367 i->signal.type = m_signalQuality.type;
371 ScanResult scanresult;
372 //Now add all remaining networks:
373 for(QHash<QString,WextScan>::iterator i = wextScanHash.begin(); i != wextScanHash.end(); ++i) {
374 scanresult.bssid = i.value().bssid;
375 scanresult.ssid = i.value().ssid;
376 scanresult.freq = i.value().freq;
377 scanresult.signal = i.value().signal;
378 scanresult.group = i.value().group;
379 scanresult.pairwise = i.value().pairwise;
380 scanresult.keyManagement = i.value().keyManagement;
381 scanresult.protocols = i.value().protocols;
382 scanresult.opmode = i.value().opmode;
383 scanresult.bitrates = i.value().bitrates;
384 m_wpaScanResults.append(scanresult);
387 qDebug() << "Found " << count << "BSSIDs; " << wextScanHash.size() << " in Hash; " << m_wpaScanResults.size() << " in wpa_supplicant list";
388 //The complete list is done;
389 emit(scanCompleted());
395 void CWpaSupplicantBase::timerEvent(QTimerEvent *event) {
396 if (event->timerId() == m_wextTimerId) {
397 if ( (m_wextFd != -1) && m_wpaConnected) {
398 readWirelessInfo();
401 else if (event->timerId() == m_connectTimerId) {
402 if (!m_wpaConnected) {
403 m_timerCount++;
404 openWpa(true);
405 } else {
406 killTimer(m_connectTimerId);
407 m_connectTimerId = -1;
408 m_timerCount = 0;
411 else if (event->timerId() == m_scanTimerId) {
412 if ( (m_wextFd != -1) && m_wpaConnected) {
413 tryScanResults();
418 bool CWpaSupplicantBase::connected() {
419 if (wpaCtrlCmd_PING() == "PONG\n") {
420 return true;
422 else {
423 return false;
427 //Public slots
430 void CWpaSupplicantBase::setSignalQualityPollRate(int msec) {
431 m_wextPollTimeoutCount = 0;
432 if (m_wextTimerId != -1) {
433 qDebug() << "Setting signal quality polling (restarting timer)";
434 killTimer(m_wextTimerId);
435 m_wextTimerRate = msec;
436 m_wextTimerId = startTimer(m_wextTimerRate);
438 else {
439 qDebug() << "Setting signal quality polling (starting timer)";
440 m_wextTimerRate = msec;
441 m_wextTimerId = startTimer(m_wextTimerRate);
444 int CWpaSupplicantBase::getSignalQualityPollRate() {
445 return m_wextTimerRate;
447 WextSignal CWpaSupplicantBase::getSignalQuality() {
448 return m_signalQuality;
451 void CWpaSupplicantBase::setLog(bool enabled) {
452 m_logEnabled = enabled;
456 void CWpaSupplicantBase::scan() {
457 if (0 == wpaCtrlCmd_SCAN().indexOf("OK")) {
458 //Check if we're already scanning:
459 if (m_scanTimerId != -1) {
460 killTimer(m_scanTimerId);
461 m_scanTimerId = -1;
462 printMessage("We're already scanning!");
464 //Return scanresults from wpa_supplicant immediately
465 setScanResults(QList<WextRawScan>());
466 m_scanTimeoutCount = 0;
467 m_scanTimerId = startTimer(CWPA_SCAN_TIMER_TIME);
472 //noise levels, returned by this functions, are invalid, don't use them
473 void CWpaSupplicantBase::tryScanResults() {
474 if (m_wextFd == -1 || !m_wpaConnected) {
475 return;
477 //Kill Timer:
478 if (m_scanTimerId != -1) {
479 killTimer(m_scanTimerId);
480 m_scanTimerId = -1;
482 else { //This is not a timer call; this should not happen
483 qWarning() << tr("Warning, no timer present while trying to get scan results");
484 return;
486 struct iwreq wrq;
487 memset(&wrq,0,sizeof(struct iwreq));
488 unsigned char * buffer = NULL; /* Results */
489 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
490 struct iw_range range;
491 memset(&range,0,sizeof(struct iw_range));
492 int has_range;
493 QList<WextRawScan> res = QList<WextRawScan>();
494 WextRawScan singleres;
495 singleres.bssid = libnutcommon::MacAddress();
496 singleres.group = GCI_UNDEFINED;
497 singleres.pairwise = PCI_UNDEFINED;
498 singleres.protocols = PROTO_UNDEFINED;
499 singleres.keyManagement = KM_UNDEFINED;
501 /* workaround */
502 struct wireless_config wifiConfig;
503 memset(&wifiConfig,0,sizeof(struct wireless_config));
505 /* Get basic information */
506 if(iw_get_basic_config(m_wextFd, m_ifname.toAscii().constData(), &wifiConfig) < 0) {
507 /* If no wireless name : no wireless extensions */
508 /* But let's check if the interface exists at all */
509 struct ifreq ifr;
510 memset(&ifr,0,sizeof(struct ifreq));
512 strncpy(ifr.ifr_name, m_ifname.toAscii().data(), IFNAMSIZ);
513 if(ioctl(m_wextFd, SIOCGIFFLAGS, &ifr) < 0)
514 qWarning() << tr("(Wireless Extension) No device present");
515 else
516 qWarning() << tr("(Wireless Extension) Device not supported");
517 return;
519 qDebug() << "Fetched basic config.";
521 /* Get AP address */
522 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWAP, &wrq) >= 0) {
523 qDebug() << "Got AP";
526 /* Get bit rate */
527 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWRATE, &wrq) >= 0) {
528 qDebug() << "Got bit rate";
531 /* Get Power Management settings */
532 wrq.u.power.flags = 0;
533 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWPOWER, &wrq) >= 0) {
534 qDebug() << "Got power";
536 /* workaround */
538 /* Get range stuff */
539 /* Get range stuff */
540 qDebug() << QString("Getting range stuff for %1").arg(m_ifname.toAscii().data());
541 if (iw_get_range_info(m_wextFd, m_ifname.toAscii().data(), &range) >= 0) {
542 has_range = 1;
543 qDebug() << "Success readWirelessInfo getrange" << strerror(errno);
545 else { //This is VERY strange: we always get the "operation not permitted" error, although iw_get_range() worked
546 qDebug() << QString("Error \"hasRange == 0\" (%1)").arg(strerror(errno));
548 singleres.hasRange = has_range;
550 //If we get a timeout for more than 5 times, stop polling.
551 if (errno == EAGAIN) {
552 qDebug() << "Scan results not available yet";
553 m_scanTimeoutCount++;
554 if (m_scanTimeoutCount == 5) {
555 return;
557 m_scanTimerId = startTimer(CWPA_SCAN_RETRY_TIMER_TIME);
558 return;
561 qDebug() << "Got range stuff";
563 if (has_range) {
564 singleres.maxquality.level = (quint8) range.max_qual.level;
565 singleres.maxquality.qual = (quint8) range.max_qual.qual;
566 singleres.maxquality.noise = (quint8) range.max_qual.noise;
567 singleres.maxquality.updated = (quint8) range.max_qual.updated;
568 qDebug() << "RANGE (scanresults): " << singleres.maxquality.level << singleres.maxquality.qual << singleres.maxquality.noise << singleres.maxquality.updated;
570 else {
571 singleres.maxquality.level = 0;
572 singleres.maxquality.qual = 0;
573 singleres.maxquality.noise = 0;
574 singleres.maxquality.updated = 0;
575 qWarning() << tr("Range information are not available");
578 unsigned char * newbuf;
579 for (int i=0; i <= 16; i++) { //realloc (don't do this forever)
580 //Allocate newbuffer
581 newbuf = (uchar*) realloc(buffer, buflen);
582 if(newbuf == NULL) {
583 if (buffer) {
584 free(buffer);
585 buffer = NULL;
587 qDebug() << "Allocating buffer for Wext failed";
588 return;
590 buffer = newbuf;
592 //Set Request variables:
593 wrq.u.data.pointer = buffer;
594 wrq.u.data.flags = 0;
595 wrq.u.data.length = buflen;
597 //Get the data:
598 if (iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWSCAN, &wrq) < 0) {
599 //Buffer is too small
600 if((errno == E2BIG) && (range.we_version_compiled > 16)) {
602 //check if driver gives any hints about scan length:
603 if (wrq.u.data.length > buflen) {
604 buflen = wrq.u.data.length;
606 else { //If not, double the length
607 buflen *= 2;
609 //Start from the beginning:
610 qDebug() << "Buffer was too small";
611 continue;
613 //No range error occured or kernel has wireless extension < 16
614 if (errno == EAGAIN) {
615 qDebug() << "Scan results not available yet";
616 m_scanTimerId = startTimer(CWPA_SCAN_RETRY_TIMER_TIME);
617 return;
620 //Bad error occured
621 if (buffer) {
622 free(buffer);
623 buffer = NULL;
625 qWarning() << tr("(%1) Failed to read scan data : %2").arg(m_ifname, QString(strerror(errno)));
627 else { //Results are there
628 break;
632 //Now read the data:
633 if (wrq.u.data.length) {
635 struct iw_event iwe;
636 memset(&iwe,0,sizeof(struct iw_event));
637 struct stream_descr stream;
638 memset(&stream,0,sizeof(struct stream_descr));
639 int ret;
641 //Init event stream
642 QByteArray test;
643 char buffer2[128];
644 libnutcommon::MacAddress tmpMac;
645 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
646 do {
647 /* Extract an event and parse it*/
648 memset(&iwe,0,sizeof(struct iw_event)); //valgrind complains about it?
649 ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
650 if(ret > 0) {
651 //Now parse our scan event:
652 switch(iwe.cmd) {
653 case SIOCGIWAP:
654 //ap_addr has type socketaddr
655 //Workaround for macaddress
656 iw_saether_ntop(&(iwe.u.ap_addr), buffer2);
657 tmpMac = libnutcommon::MacAddress(QString::fromAscii(buffer2,128));
659 if (singleres.bssid.zero()) { //First bssid
660 singleres.bssid = tmpMac;
661 qDebug() << "Start parsing one network" << singleres.bssid.toString();
663 // if our last bssid is different from the actual one, then we have to append it to our scanlist
664 if ( (singleres.bssid != tmpMac) ) {
665 res.append(singleres);
666 qDebug() << "End parsing one network" << singleres.bssid.toString();
667 //reset singleres
668 singleres.ssid = QString();
669 singleres.bssid.clear();
670 singleres.quality = WextRawSignal();
671 singleres.freq = -1;
672 singleres.group = GCI_UNDEFINED;
673 singleres.pairwise = PCI_UNDEFINED;
674 singleres.keyManagement = KM_UNDEFINED;
675 singleres.protocols = PROTO_UNDEFINED;
676 singleres.opmode = OPM_AUTO;
677 singleres.bssid = tmpMac;
678 qDebug() << "Start parsing one network" << singleres.bssid.toString();
680 qDebug() << "BSSID" << singleres.bssid.toString();
681 break;
682 case IWEVQUAL: //Quality event:
683 qDebug() << "Quality" << singleres.bssid.toString();
684 singleres.quality.qual = (quint8) iwe.u.qual.qual;
685 singleres.quality.level = (quint8) iwe.u.qual.level;
686 singleres.quality.noise = (quint8) iwe.u.qual.noise;
687 singleres.quality.updated = (quint8) iwe.u.qual.updated;
688 qDebug() << "STATS (scanresults): " << singleres.quality.level << singleres.quality.qual << singleres.quality.noise << singleres.quality.updated;
689 break;
690 case SIOCGIWFREQ:
691 qDebug() << "Frequency" << singleres.bssid.toString();
693 double freq;
694 freq = iw_freq2float(&(iwe.u.freq)); //Hopefully in hz
695 if ( ( (freq/1e9) < 10.0 ) && ( (freq/1e9) > 0.0 ) ) {
696 singleres.freq = (int) (freq/1e6);
697 qDebug() << "Channel for" << singleres.ssid << "is " << freq << singleres.freq;
699 else {
700 singleres.freq = -1;
703 break;
705 case SIOCGIWMODE:
706 qDebug() << "Mode:" << singleres.bssid.toString();
707 if(iwe.u.mode >= IW_NUM_OPER_MODE) {
708 iwe.u.mode = IW_NUM_OPER_MODE;
710 singleres.opmode = (OPMODE) iwe.u.mode;
711 break;
712 case SIOCGIWESSID:
713 qDebug() << "ESSID:" << singleres.bssid.toString();
714 if (iwe.u.essid.flags) {
715 /* Does it have an ESSID index ? */
716 if ( iwe.u.essid.pointer && iwe.u.essid.length ) {
717 if ( (iwe.u.essid.flags & IW_ENCODE_INDEX) > 1) {
718 singleres.ssid = QString("%1 [%2]").arg(QString::fromAscii((char*) iwe.u.essid.pointer,iwe.u.essid.length), QString::number(iwe.u.essid.flags & IW_ENCODE_INDEX));
720 else {
721 singleres.ssid = QString("%1").arg(QString::fromAscii((char*) iwe.u.essid.pointer,iwe.u.essid.length));
724 else {
725 singleres.ssid = QString("N/A");
728 else { //Hidden essid or broken driver
729 singleres.ssid = QString();
731 break;
733 case SIOCGIWENCODE: //Get encrytion stuff: (just the key)
734 qDebug() << "Encode" << singleres.bssid.toString();
735 if (! iwe.u.data.pointer) {
736 iwe.u.data.flags |= IW_ENCODE_NOKEY;
738 if(iwe.u.data.flags & IW_ENCODE_DISABLED) { //Encryption is disabled
739 singleres.keyManagement = KM_OFF;
740 qDebug() << "PARING ENCODE-Information: NO KEY";
742 else {
743 //Extract key information: (See iwlib.c line 1500)
745 //keyflags: iwe.u.data.flags
746 //keysize = iwe.u.data.length
748 //Do we have a key
749 if (iwe.u.data.flags & IW_ENCODE_NOKEY) { //no key
750 if (iwe.u.data.length <= 0) {
751 //Encryption is on, but group is unknown
752 singleres.keyManagement = KM_NONE;
753 qDebug() << "PARSING ENCODE-INFORMATION: WEP KEY";
755 } //else: we have a, key but check type later
757 break;
759 case SIOCGIWRATE:
760 singleres.bitrates.append((qint32) iwe.u.bitrate.value);
761 qDebug() << "Adding Bitrate: " << (qint32) iwe.u.bitrate.value;
762 break;
764 case IWEVGENIE: //group/pairwsie ciphers etc.
765 //buffer = iwe.u.data.pointer
766 //bufflen = iwe.u.data.length
767 qDebug() << "IE_START" << singleres.bssid.toString();
769 int offset = 0;
770 /* Loop on each IE, each IE is minimum 2 bytes */
771 while(offset <= (iwe.u.data.length - 2)) {
772 /* Check IE type */
773 if (0xdd == ((uchar *) iwe.u.data.pointer)[offset] || (0x30 == ((uchar *) iwe.u.data.pointer)[offset]) ) { // WPA1/2
774 parseWextIeWpa(((uchar *) iwe.u.data.pointer) + offset, iwe.u.data.length, &singleres);
776 qDebug() << "Parsed IE-Information of " << singleres.ssid << singleres.bssid.toString();
777 qDebug() << toString(singleres.group) << toString(singleres.pairwise) << toString(singleres.keyManagement);
779 /* Skip over this IE to the next one in the list. */
780 offset += buffer[offset+1] + 2;
783 qDebug() << "IE_END" << singleres.bssid.toString();
784 break;
786 default: //Ignore all other event types. Maybe we need them later?
787 break;
790 else { //Append last scan:
791 if (!singleres.bssid.zero()) {
792 res.append(singleres);
793 qDebug() << "End parsing one network" << singleres.bssid.toString();
797 } while(ret > 0);
799 //Delete buffer
800 if (buffer) {
801 free(buffer);
802 buffer = NULL;
804 //We have the data, now construct complete ScanResult
805 setScanResults(res);
807 else {
808 qWarning() << tr("No Scanresults available");
810 if (buffer) {
811 free(buffer);
812 buffer = NULL;
816 void CWpaSupplicantBase::readWirelessInfo() {
817 qDebug() << "Executing readWirelessInfo() with TimerRate of" << m_wextTimerRate;
818 if ( (m_wextFd == -1) || !m_wpaConnected) {
819 return;
821 struct iw_range range;
822 memset(&range,0,sizeof(struct iw_range));
823 int hasRange = 0;
824 iwstats stats;
825 memset(&stats,0,sizeof(iwstats));
826 WextRawScan res;
827 /* workaround */
828 struct wireless_config wifiConfig;
829 memset(&wifiConfig,0,sizeof(struct wireless_config));
830 /* Get basic information */
831 if(iw_get_basic_config(m_wextFd, m_ifname.toAscii().constData(), &wifiConfig) < 0) {
832 /* If no wireless name : no wireless extensions */
833 /* But let's check if the interface exists at all */
834 struct ifreq ifr;
835 memset(&ifr,0,sizeof(struct ifreq));
837 strncpy(ifr.ifr_name, m_ifname.toAscii().data(), IFNAMSIZ);
838 if(ioctl(m_wextFd, SIOCGIFFLAGS, &ifr) < 0)
839 qWarning() << tr("(Wireless Extension) No device present");
840 else
841 qWarning() << tr("(Wireless Extension) device not supported");
842 return;
844 qDebug() << "Fetched basic config.";
846 //We encode frequency in mhz;
847 //kernel encodes as double; (hopefully always in hz)
848 //But better test this:
849 res.freq = -1;
850 if (wifiConfig.has_freq) {
851 if ( ( (wifiConfig.freq/1e9) < 10.0 ) && ( (wifiConfig.freq/1e9) > 0.0 ) ) {
852 res.freq = (int) (wifiConfig.freq/1e6);
856 struct iwreq wrq;
857 memset(&wrq,0,sizeof(struct iwreq));
859 /* Get AP address */
860 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWAP, &wrq) >= 0) {
861 //Add mac address of current ap;
862 char buffer[128];
863 iw_saether_ntop(&(wrq.u.ap_addr), buffer);
864 res.bssid = libnutcommon::MacAddress(QString::fromAscii(buffer,128));
865 qDebug() << "Got AP: " << res.bssid.toString();
868 /* Get ssid */
869 quint8 * buffer = new quint8[IW_ESSID_MAX_SIZE];
870 memset(buffer, '\0', IW_ESSID_MAX_SIZE);
871 wrq.u.essid.pointer = (void *)buffer;
872 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
873 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWESSID, &wrq) >= 0) {
874 if (wrq.u.essid.length > IW_ESSID_MAX_SIZE)
875 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
876 if (wrq.u.essid.flags) {
877 /* Does it have an ESSID index ? */
878 if ( wrq.u.essid.pointer && wrq.u.essid.length ) {
879 if ( (wrq.u.essid.flags & IW_ENCODE_INDEX) > 1) {
880 res.ssid = QString("%1 [%2]").arg(QString::fromAscii((char*) wrq.u.essid.pointer, wrq.u.essid.length), QString::number(wrq.u.essid.flags & IW_ENCODE_INDEX));
882 else {
883 res.ssid = QString::fromAscii((char*) wrq.u.essid.pointer, wrq.u.essid.length);
886 else {
887 res.ssid = "N/A";
890 qDebug() << "Got ssid: " << res.ssid;
892 delete[] buffer;
894 /* Get bit rate */
895 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWRATE, &wrq) >= 0) {
896 res.bitrates.append((qint32) wrq.u.bitrate.value);
897 qDebug() << "Got bit rate: " << res.bitrates[0];
900 /* Get Power Management settings */
901 wrq.u.power.flags = 0;
902 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWPOWER, &wrq) >= 0) {
903 qDebug() << "Got power";
905 /* workaround */
908 /* Get range stuff */
909 qDebug() << QString("Getting range stuff for %1").arg(m_ifname.toAscii().data());
910 if (iw_get_range_info(m_wextFd, m_ifname.toAscii().data(), &range) >= 0) {
911 hasRange = 1;
912 qDebug() << "Success readWirelessInfo getrange" << strerror(errno);
914 else { //This is VERY strange: we always get the "operation not permitted" error, although iw_get_range() worked
915 qDebug() << QString("Error \"hasRange == 0\" (%1)").arg(strerror(errno));
917 res.hasRange = hasRange;
918 if (errno == EAGAIN) {
919 m_wextPollTimeoutCount++;
920 qDebug() << QString("Getting range stuff failed (%1)").arg(strerror(errno));
921 if ( (m_wextPollTimeoutCount > 10) && m_wextTimerRate < 1000) {
922 setSignalQualityPollRate(10000);
924 else if (m_wextPollTimeoutCount > 10) { //Fast polling disabled, but still EAGAIN errors
925 //Seems the kernel does not care about our calls
926 killTimer(m_wextTimerId);
927 m_wextTimerId = -1;
929 return;
932 qDebug() << "Got range stuff";
935 //Set supported Frequencies if the list is not empty;
936 if (m_supportedFrequencies.isEmpty() && hasRange) {
937 qDebug() << range.num_frequency;
938 qDebug() << "Printing Frequency information";
939 quint32 m;
940 quint16 e;
941 quint32 freqinmhz;
942 for (int i=0; i < range.num_channels; i++) {
943 m = (quint32) range.freq[i].m;
944 e = (quint16) range.freq[i].e;
945 freqinmhz = m;
946 for (int j=0; j < 9-e-3; j++) {
947 freqinmhz = freqinmhz/10;
949 if (!m_supportedFrequencies.contains(freqinmhz)) { //Only add frequency that are not in our list
950 m_supportedFrequencies.append(freqinmhz);
952 qDebug() << m << e << freqinmhz << frequencyToChannel(freqinmhz);
954 qDebug() << "Done printing";
956 else {
957 qDebug() << "m_supportedFrequencies not set";
960 if (hasRange) {
961 res.maxquality.level = (quint8) range.max_qual.level;
962 res.maxquality.qual = (quint8) range.max_qual.qual;
963 res.maxquality.noise = (quint8) range.max_qual.noise;
964 res.maxquality.updated = (quint8) range.max_qual.updated;
965 qDebug() << "RANGE: " << res.maxquality.level << res.maxquality.qual << res.maxquality.noise << res.maxquality.updated;
967 else {
968 res.maxquality.level = 0;
969 res.maxquality.qual = 0;
970 res.maxquality.noise = 0;
971 res.maxquality.updated = 0;
972 qDebug() << "Range information are not available";
974 if ( (hasRange) && (range.we_version_compiled > 11) ) {
975 struct iwreq wrq;
976 memset(&wrq,0,sizeof(struct iwreq));
977 wrq.u.data.pointer = (caddr_t) &stats;
978 wrq.u.data.length = sizeof(struct iw_statistics);
979 wrq.u.data.flags = 1; // Clear updated flag
980 strncpy(wrq.ifr_name, m_ifname.toAscii().data(), IFNAMSIZ);
982 qDebug() << "Getting wireless stats";
983 if(iw_get_ext(m_wextFd, m_ifname.toAscii().data(), SIOCGIWSTATS, &wrq) < 0) {
984 qWarning() << tr("Error occured while fetching wireless info: ") << strerror(errno);
986 else { //Stats fetched
987 qDebug() << "Stats fetched";
988 res.quality.level = (quint8) stats.qual.level;
989 res.quality.qual = (quint8) stats.qual.qual;
990 res.quality.noise = (quint8) stats.qual.noise;
991 res.quality.updated = (quint8) stats.qual.updated;
992 qDebug() << "STATS: " << res.quality.level << res.quality.qual << res.quality.noise << res.quality.updated;
993 m_signalQuality = convertValues(res);
994 qDebug() << "Emittig m_signalQualityUpdated()";
995 if (m_wextTimerRate < 1000) {
996 setSignalQualityPollRate(10000);
997 printMessage(tr("Auto-resetting timer to 10 seconds"));
999 emit signalQualityUpdated(m_signalQuality);
1002 else if (range.we_version_compiled <= 11) {
1003 printMessage(tr("Cannot fetch wireless information as your wireless extension is too old"));
1004 printMessage(tr("Think about updating your kernel (it's way too old)"));
1006 else {
1007 qDebug() << "Error while trying to fetch wireless information" << strerror(errno);
1008 qDebug() << "Wireless Extension socket file descriptor was: " << m_wextFd;
1013 QList<ScanResult> CWpaSupplicantBase::scanResults() {
1014 return m_wpaScanResults;