1 /* 2 * wpa_gui - WpaGui class 3 * Copyright (c) 2005-2011, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #ifdef CONFIG_NATIVE_WINDOWS 10 #include <windows.h> 11 #endif /* CONFIG_NATIVE_WINDOWS */ 12 13 #include <cstdio> 14 #include <unistd.h> 15 #include <QMessageBox> 16 #include <QCloseEvent> 17 #include <QImageReader> 18 #include <QSettings> 19 20 #include "wpagui.h" 21 #include "dirent.h" 22 #include "common/wpa_ctrl.h" 23 #include "userdatarequest.h" 24 #include "networkconfig.h" 25 26 #if 1 27 /* Silence stdout */ 28 #define printf wpagui_printf 29 static int wpagui_printf(const char *, ...) 30 { 31 return 0; 32 } 33 #endif 34 35 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) 36 : QMainWindow(parent), app(_app) 37 { 38 setupUi(this); 39 40 #ifdef CONFIG_NATIVE_WINDOWS 41 fileStopServiceAction = new QAction(this); 42 fileStopServiceAction->setObjectName("Stop Service"); 43 fileStopServiceAction->setIconText(tr("Stop Service")); 44 fileMenu->insertAction(actionWPS, fileStopServiceAction); 45 46 fileStartServiceAction = new QAction(this); 47 fileStartServiceAction->setObjectName("Start Service"); 48 fileStartServiceAction->setIconText(tr("Start Service")); 49 fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); 50 51 connect(fileStartServiceAction, SIGNAL(triggered()), this, 52 SLOT(startService())); 53 connect(fileStopServiceAction, SIGNAL(triggered()), this, 54 SLOT(stopService())); 55 56 addInterfaceAction = new QAction(this); 57 addInterfaceAction->setIconText(tr("Add Interface")); 58 fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); 59 60 connect(addInterfaceAction, SIGNAL(triggered()), this, 61 SLOT(addInterface())); 62 #endif /* CONFIG_NATIVE_WINDOWS */ 63 64 (void) statusBar(); 65 66 /* 67 * Disable WPS tab by default; it will be enabled if wpa_supplicant is 68 * built with WPS support. 69 */ 70 wpsTab->setEnabled(false); 71 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); 72 73 connect(fileEventHistoryAction, SIGNAL(triggered()), this, 74 SLOT(eventHistory())); 75 connect(fileSaveConfigAction, SIGNAL(triggered()), this, 76 SLOT(saveConfig())); 77 connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); 78 connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog())); 79 connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); 80 connect(networkAddAction, SIGNAL(triggered()), this, 81 SLOT(addNetwork())); 82 connect(networkEditAction, SIGNAL(triggered()), this, 83 SLOT(editSelectedNetwork())); 84 connect(networkRemoveAction, SIGNAL(triggered()), this, 85 SLOT(removeSelectedNetwork())); 86 connect(networkEnableAllAction, SIGNAL(triggered()), this, 87 SLOT(enableAllNetworks())); 88 connect(networkDisableAllAction, SIGNAL(triggered()), this, 89 SLOT(disableAllNetworks())); 90 connect(networkRemoveAllAction, SIGNAL(triggered()), this, 91 SLOT(removeAllNetworks())); 92 connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); 93 connect(helpContentsAction, SIGNAL(triggered()), this, 94 SLOT(helpContents())); 95 connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); 96 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); 97 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); 98 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); 99 connect(adapterSelect, SIGNAL(activated(const QString&)), this, 100 SLOT(selectAdapter(const QString&))); 101 connect(networkSelect, SIGNAL(activated(const QString&)), this, 102 SLOT(selectNetwork(const QString&))); 103 connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); 104 connect(editNetworkButton, SIGNAL(clicked()), this, 105 SLOT(editListedNetwork())); 106 connect(removeNetworkButton, SIGNAL(clicked()), this, 107 SLOT(removeListedNetwork())); 108 connect(networkList, SIGNAL(itemSelectionChanged()), this, 109 SLOT(updateNetworkDisabledStatus())); 110 connect(enableRadioButton, SIGNAL(toggled(bool)), this, 111 SLOT(enableListedNetwork(bool))); 112 connect(disableRadioButton, SIGNAL(toggled(bool)), this, 113 SLOT(disableListedNetwork(bool))); 114 connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); 115 connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), 116 this, SLOT(editListedNetwork())); 117 connect(wpaguiTab, SIGNAL(currentChanged(int)), this, 118 SLOT(tabChanged(int))); 119 connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); 120 connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); 121 connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, 122 SLOT(wpsApPinChanged(const QString &))); 123 connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); 124 125 eh = NULL; 126 scanres = NULL; 127 peers = NULL; 128 add_iface = NULL; 129 udr = NULL; 130 tray_icon = NULL; 131 startInTray = false; 132 ctrl_iface = NULL; 133 ctrl_conn = NULL; 134 monitor_conn = NULL; 135 msgNotifier = NULL; 136 ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); 137 138 parse_argv(); 139 140 #ifndef QT_NO_SESSIONMANAGER 141 if (app->isSessionRestored()) { 142 QSettings settings("wpa_supplicant", "wpa_gui"); 143 settings.beginGroup("state"); 144 if (app->sessionId().compare(settings.value("session_id"). 145 toString()) == 0) 146 startInTray = settings.value("in_tray").toBool(); 147 settings.endGroup(); 148 } 149 #endif 150 151 if (QSystemTrayIcon::isSystemTrayAvailable()) 152 createTrayIcon(startInTray); 153 else 154 show(); 155 156 connectedToService = false; 157 textStatus->setText(tr("connecting to wpa_supplicant")); 158 timer = new QTimer(this); 159 connect(timer, SIGNAL(timeout()), SLOT(ping())); 160 timer->setSingleShot(FALSE); 161 timer->start(1000); 162 163 if (openCtrlConnection(ctrl_iface) < 0) { 164 printf("Failed to open control connection to " 165 "wpa_supplicant.\n"); 166 } 167 168 updateStatus(); 169 networkMayHaveChanged = true; 170 updateNetworks(); 171 } 172 173 174 WpaGui::~WpaGui() 175 { 176 delete msgNotifier; 177 178 if (monitor_conn) { 179 wpa_ctrl_detach(monitor_conn); 180 wpa_ctrl_close(monitor_conn); 181 monitor_conn = NULL; 182 } 183 if (ctrl_conn) { 184 wpa_ctrl_close(ctrl_conn); 185 ctrl_conn = NULL; 186 } 187 188 if (eh) { 189 eh->close(); 190 delete eh; 191 eh = NULL; 192 } 193 194 if (scanres) { 195 scanres->close(); 196 delete scanres; 197 scanres = NULL; 198 } 199 200 if (peers) { 201 peers->close(); 202 delete peers; 203 peers = NULL; 204 } 205 206 if (add_iface) { 207 add_iface->close(); 208 delete add_iface; 209 add_iface = NULL; 210 } 211 212 if (udr) { 213 udr->close(); 214 delete udr; 215 udr = NULL; 216 } 217 218 free(ctrl_iface); 219 ctrl_iface = NULL; 220 221 free(ctrl_iface_dir); 222 ctrl_iface_dir = NULL; 223 } 224 225 226 void WpaGui::languageChange() 227 { 228 retranslateUi(this); 229 } 230 231 232 void WpaGui::parse_argv() 233 { 234 int c; 235 for (;;) { 236 c = getopt(qApp->argc(), qApp->argv(), "i:p:t"); 237 if (c < 0) 238 break; 239 switch (c) { 240 case 'i': 241 free(ctrl_iface); 242 ctrl_iface = strdup(optarg); 243 break; 244 case 'p': 245 free(ctrl_iface_dir); 246 ctrl_iface_dir = strdup(optarg); 247 break; 248 case 't': 249 startInTray = true; 250 break; 251 } 252 } 253 } 254 255 256 int WpaGui::openCtrlConnection(const char *ifname) 257 { 258 char *cfile; 259 int flen; 260 char buf[2048], *pos, *pos2; 261 size_t len; 262 263 if (ifname) { 264 if (ifname != ctrl_iface) { 265 free(ctrl_iface); 266 ctrl_iface = strdup(ifname); 267 } 268 } else { 269 #ifdef CONFIG_CTRL_IFACE_UDP 270 free(ctrl_iface); 271 ctrl_iface = strdup("udp"); 272 #endif /* CONFIG_CTRL_IFACE_UDP */ 273 #ifdef CONFIG_CTRL_IFACE_UNIX 274 struct dirent *dent; 275 DIR *dir = opendir(ctrl_iface_dir); 276 free(ctrl_iface); 277 ctrl_iface = NULL; 278 if (dir) { 279 while ((dent = readdir(dir))) { 280 #ifdef _DIRENT_HAVE_D_TYPE 281 /* Skip the file if it is not a socket. 282 * Also accept DT_UNKNOWN (0) in case 283 * the C library or underlying file 284 * system does not support d_type. */ 285 if (dent->d_type != DT_SOCK && 286 dent->d_type != DT_UNKNOWN) 287 continue; 288 #endif /* _DIRENT_HAVE_D_TYPE */ 289 290 if (strcmp(dent->d_name, ".") == 0 || 291 strcmp(dent->d_name, "..") == 0) 292 continue; 293 printf("Selected interface '%s'\n", 294 dent->d_name); 295 ctrl_iface = strdup(dent->d_name); 296 break; 297 } 298 closedir(dir); 299 } 300 #endif /* CONFIG_CTRL_IFACE_UNIX */ 301 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 302 struct wpa_ctrl *ctrl; 303 int ret; 304 305 free(ctrl_iface); 306 ctrl_iface = NULL; 307 308 ctrl = wpa_ctrl_open(NULL); 309 if (ctrl) { 310 len = sizeof(buf) - 1; 311 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, 312 &len, NULL); 313 if (ret >= 0) { 314 connectedToService = true; 315 buf[len] = '\0'; 316 pos = strchr(buf, '\n'); 317 if (pos) 318 *pos = '\0'; 319 ctrl_iface = strdup(buf); 320 } 321 wpa_ctrl_close(ctrl); 322 } 323 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 324 } 325 326 if (ctrl_iface == NULL) { 327 #ifdef CONFIG_NATIVE_WINDOWS 328 static bool first = true; 329 if (first && !serviceRunning()) { 330 first = false; 331 if (QMessageBox::warning( 332 this, qAppName(), 333 tr("wpa_supplicant service is not " 334 "running.\n" 335 "Do you want to start it?"), 336 QMessageBox::Yes | QMessageBox::No) == 337 QMessageBox::Yes) 338 startService(); 339 } 340 #endif /* CONFIG_NATIVE_WINDOWS */ 341 return -1; 342 } 343 344 #ifdef CONFIG_CTRL_IFACE_UNIX 345 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; 346 cfile = (char *) malloc(flen); 347 if (cfile == NULL) 348 return -1; 349 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); 350 #else /* CONFIG_CTRL_IFACE_UNIX */ 351 flen = strlen(ctrl_iface) + 1; 352 cfile = (char *) malloc(flen); 353 if (cfile == NULL) 354 return -1; 355 snprintf(cfile, flen, "%s", ctrl_iface); 356 #endif /* CONFIG_CTRL_IFACE_UNIX */ 357 358 if (ctrl_conn) { 359 wpa_ctrl_close(ctrl_conn); 360 ctrl_conn = NULL; 361 } 362 363 if (monitor_conn) { 364 delete msgNotifier; 365 msgNotifier = NULL; 366 wpa_ctrl_detach(monitor_conn); 367 wpa_ctrl_close(monitor_conn); 368 monitor_conn = NULL; 369 } 370 371 printf("Trying to connect to '%s'\n", cfile); 372 ctrl_conn = wpa_ctrl_open(cfile); 373 if (ctrl_conn == NULL) { 374 free(cfile); 375 return -1; 376 } 377 monitor_conn = wpa_ctrl_open(cfile); 378 free(cfile); 379 if (monitor_conn == NULL) { 380 wpa_ctrl_close(ctrl_conn); 381 return -1; 382 } 383 if (wpa_ctrl_attach(monitor_conn)) { 384 printf("Failed to attach to wpa_supplicant\n"); 385 wpa_ctrl_close(monitor_conn); 386 monitor_conn = NULL; 387 wpa_ctrl_close(ctrl_conn); 388 ctrl_conn = NULL; 389 return -1; 390 } 391 392 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 393 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), 394 QSocketNotifier::Read, this); 395 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); 396 #endif 397 398 adapterSelect->clear(); 399 adapterSelect->addItem(ctrl_iface); 400 adapterSelect->setCurrentIndex(0); 401 402 len = sizeof(buf) - 1; 403 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 404 0) { 405 buf[len] = '\0'; 406 pos = buf; 407 while (*pos) { 408 pos2 = strchr(pos, '\n'); 409 if (pos2) 410 *pos2 = '\0'; 411 if (strcmp(pos, ctrl_iface) != 0) 412 adapterSelect->addItem(pos); 413 if (pos2) 414 pos = pos2 + 1; 415 else 416 break; 417 } 418 } 419 420 len = sizeof(buf) - 1; 421 if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, 422 NULL) >= 0) { 423 buf[len] = '\0'; 424 425 QString res(buf); 426 QStringList types = res.split(QChar(' ')); 427 bool wps = types.contains("WSC"); 428 actionWPS->setEnabled(wps); 429 wpsTab->setEnabled(wps); 430 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); 431 } 432 433 return 0; 434 } 435 436 437 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) 438 { 439 int ret; 440 441 if (ctrl_conn == NULL) 442 return -3; 443 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); 444 if (ret == -2) 445 printf("'%s' command timed out.\n", cmd); 446 else if (ret < 0) 447 printf("'%s' command failed.\n", cmd); 448 449 return ret; 450 } 451 452 453 QString WpaGui::wpaStateTranslate(char *state) 454 { 455 if (!strcmp(state, "DISCONNECTED")) 456 return tr("Disconnected"); 457 else if (!strcmp(state, "INACTIVE")) 458 return tr("Inactive"); 459 else if (!strcmp(state, "SCANNING")) 460 return tr("Scanning"); 461 else if (!strcmp(state, "AUTHENTICATING")) 462 return tr("Authenticating"); 463 else if (!strcmp(state, "ASSOCIATING")) 464 return tr("Associating"); 465 else if (!strcmp(state, "ASSOCIATED")) 466 return tr("Associated"); 467 else if (!strcmp(state, "4WAY_HANDSHAKE")) 468 return tr("4-Way Handshake"); 469 else if (!strcmp(state, "GROUP_HANDSHAKE")) 470 return tr("Group Handshake"); 471 else if (!strcmp(state, "COMPLETED")) 472 return tr("Completed"); 473 else 474 return tr("Unknown"); 475 } 476 477 478 void WpaGui::updateStatus() 479 { 480 char buf[2048], *start, *end, *pos; 481 size_t len; 482 483 pingsToStatusUpdate = 10; 484 485 len = sizeof(buf) - 1; 486 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { 487 textStatus->setText(tr("Could not get status from " 488 "wpa_supplicant")); 489 textAuthentication->clear(); 490 textEncryption->clear(); 491 textSsid->clear(); 492 textBssid->clear(); 493 textIpAddress->clear(); 494 495 #ifdef CONFIG_NATIVE_WINDOWS 496 static bool first = true; 497 if (first && connectedToService && 498 (ctrl_iface == NULL || *ctrl_iface == '\0')) { 499 first = false; 500 if (QMessageBox::information( 501 this, qAppName(), 502 tr("No network interfaces in use.\n" 503 "Would you like to add one?"), 504 QMessageBox::Yes | QMessageBox::No) == 505 QMessageBox::Yes) 506 addInterface(); 507 } 508 #endif /* CONFIG_NATIVE_WINDOWS */ 509 return; 510 } 511 512 buf[len] = '\0'; 513 514 bool auth_updated = false, ssid_updated = false; 515 bool bssid_updated = false, ipaddr_updated = false; 516 bool status_updated = false; 517 char *pairwise_cipher = NULL, *group_cipher = NULL; 518 char *mode = NULL; 519 520 start = buf; 521 while (*start) { 522 bool last = false; 523 end = strchr(start, '\n'); 524 if (end == NULL) { 525 last = true; 526 end = start; 527 while (end[0] && end[1]) 528 end++; 529 } 530 *end = '\0'; 531 532 pos = strchr(start, '='); 533 if (pos) { 534 *pos++ = '\0'; 535 if (strcmp(start, "bssid") == 0) { 536 bssid_updated = true; 537 textBssid->setText(pos); 538 } else if (strcmp(start, "ssid") == 0) { 539 ssid_updated = true; 540 textSsid->setText(pos); 541 } else if (strcmp(start, "ip_address") == 0) { 542 ipaddr_updated = true; 543 textIpAddress->setText(pos); 544 } else if (strcmp(start, "wpa_state") == 0) { 545 status_updated = true; 546 textStatus->setText(wpaStateTranslate(pos)); 547 } else if (strcmp(start, "key_mgmt") == 0) { 548 auth_updated = true; 549 textAuthentication->setText(pos); 550 /* TODO: could add EAP status to this */ 551 } else if (strcmp(start, "pairwise_cipher") == 0) { 552 pairwise_cipher = pos; 553 } else if (strcmp(start, "group_cipher") == 0) { 554 group_cipher = pos; 555 } else if (strcmp(start, "mode") == 0) { 556 mode = pos; 557 } 558 } 559 560 if (last) 561 break; 562 start = end + 1; 563 } 564 if (status_updated && mode) 565 textStatus->setText(textStatus->text() + " (" + mode + ")"); 566 567 if (pairwise_cipher || group_cipher) { 568 QString encr; 569 if (pairwise_cipher && group_cipher && 570 strcmp(pairwise_cipher, group_cipher) != 0) { 571 encr.append(pairwise_cipher); 572 encr.append(" + "); 573 encr.append(group_cipher); 574 } else if (pairwise_cipher) { 575 encr.append(pairwise_cipher); 576 } else { 577 encr.append(group_cipher); 578 encr.append(" [group key only]"); 579 } 580 textEncryption->setText(encr); 581 } else 582 textEncryption->clear(); 583 584 if (!status_updated) 585 textStatus->clear(); 586 if (!auth_updated) 587 textAuthentication->clear(); 588 if (!ssid_updated) 589 textSsid->clear(); 590 if (!bssid_updated) 591 textBssid->clear(); 592 if (!ipaddr_updated) 593 textIpAddress->clear(); 594 } 595 596 597 void WpaGui::updateNetworks() 598 { 599 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; 600 size_t len; 601 int first_active = -1; 602 int was_selected = -1; 603 bool current = false; 604 605 if (!networkMayHaveChanged) 606 return; 607 608 if (networkList->currentRow() >= 0) 609 was_selected = networkList->currentRow(); 610 611 networkSelect->clear(); 612 networkList->clear(); 613 614 if (ctrl_conn == NULL) 615 return; 616 617 len = sizeof(buf) - 1; 618 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 619 return; 620 621 buf[len] = '\0'; 622 start = strchr(buf, '\n'); 623 if (start == NULL) 624 return; 625 start++; 626 627 while (*start) { 628 bool last = false; 629 end = strchr(start, '\n'); 630 if (end == NULL) { 631 last = true; 632 end = start; 633 while (end[0] && end[1]) 634 end++; 635 } 636 *end = '\0'; 637 638 id = start; 639 ssid = strchr(id, '\t'); 640 if (ssid == NULL) 641 break; 642 *ssid++ = '\0'; 643 bssid = strchr(ssid, '\t'); 644 if (bssid == NULL) 645 break; 646 *bssid++ = '\0'; 647 flags = strchr(bssid, '\t'); 648 if (flags == NULL) 649 break; 650 *flags++ = '\0'; 651 652 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) { 653 if (last) 654 break; 655 start = end + 1; 656 continue; 657 } 658 659 QString network(id); 660 network.append(": "); 661 network.append(ssid); 662 networkSelect->addItem(network); 663 networkList->addItem(network); 664 665 if (strstr(flags, "[CURRENT]")) { 666 networkSelect->setCurrentIndex(networkSelect->count() - 667 1); 668 current = true; 669 } else if (first_active < 0 && 670 strstr(flags, "[DISABLED]") == NULL) 671 first_active = networkSelect->count() - 1; 672 673 if (last) 674 break; 675 start = end + 1; 676 } 677 678 if (networkSelect->count() > 1) 679 networkSelect->addItem(tr("Select any network")); 680 681 if (!current && first_active >= 0) 682 networkSelect->setCurrentIndex(first_active); 683 684 if (was_selected >= 0 && networkList->count() > 0) { 685 if (was_selected < networkList->count()) 686 networkList->setCurrentRow(was_selected); 687 else 688 networkList->setCurrentRow(networkList->count() - 1); 689 } 690 else 691 networkList->setCurrentRow(networkSelect->currentIndex()); 692 693 networkMayHaveChanged = false; 694 } 695 696 697 void WpaGui::helpIndex() 698 { 699 printf("helpIndex\n"); 700 } 701 702 703 void WpaGui::helpContents() 704 { 705 printf("helpContents\n"); 706 } 707 708 709 void WpaGui::helpAbout() 710 { 711 QMessageBox::about(this, "wpa_gui for wpa_supplicant", 712 "Copyright (c) 2003-2013,\n" 713 "Jouni Malinen <j (at) w1.fi>\n" 714 "and contributors.\n" 715 "\n" 716 "This software may be distributed under\n" 717 "the terms of the BSD license.\n" 718 "See README for more details.\n" 719 "\n" 720 "This product includes software developed\n" 721 "by the OpenSSL Project for use in the\n" 722 "OpenSSL Toolkit (http://www.openssl.org/)\n"); 723 } 724 725 726 void WpaGui::disconnect() 727 { 728 char reply[10]; 729 size_t reply_len = sizeof(reply); 730 ctrlRequest("DISCONNECT", reply, &reply_len); 731 stopWpsRun(false); 732 } 733 734 735 void WpaGui::scan() 736 { 737 if (scanres) { 738 scanres->close(); 739 delete scanres; 740 } 741 742 scanres = new ScanResults(); 743 if (scanres == NULL) 744 return; 745 scanres->setWpaGui(this); 746 scanres->show(); 747 scanres->exec(); 748 } 749 750 751 void WpaGui::eventHistory() 752 { 753 if (eh) { 754 eh->close(); 755 delete eh; 756 } 757 758 eh = new EventHistory(); 759 if (eh == NULL) 760 return; 761 eh->addEvents(msgs); 762 eh->show(); 763 eh->exec(); 764 } 765 766 767 void WpaGui::ping() 768 { 769 char buf[10]; 770 size_t len; 771 772 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 773 /* 774 * QSocketNotifier cannot be used with Windows named pipes, so use a 775 * timer to check for received messages for now. This could be 776 * optimized be doing something specific to named pipes or Windows 777 * events, but it is not clear what would be the best way of doing that 778 * in Qt. 779 */ 780 receiveMsgs(); 781 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 782 783 if (scanres && !scanres->isVisible()) { 784 delete scanres; 785 scanres = NULL; 786 } 787 788 if (eh && !eh->isVisible()) { 789 delete eh; 790 eh = NULL; 791 } 792 793 if (udr && !udr->isVisible()) { 794 delete udr; 795 udr = NULL; 796 } 797 798 len = sizeof(buf) - 1; 799 if (ctrlRequest("PING", buf, &len) < 0) { 800 printf("PING failed - trying to reconnect\n"); 801 if (openCtrlConnection(ctrl_iface) >= 0) { 802 printf("Reconnected successfully\n"); 803 pingsToStatusUpdate = 0; 804 } 805 } 806 807 pingsToStatusUpdate--; 808 if (pingsToStatusUpdate <= 0) { 809 updateStatus(); 810 updateNetworks(); 811 } 812 813 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE 814 /* Use less frequent pings and status updates when the main window is 815 * hidden (running in taskbar). */ 816 int interval = isHidden() ? 5000 : 1000; 817 if (timer->interval() != interval) 818 timer->setInterval(interval); 819 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 820 } 821 822 823 static int str_match(const char *a, const char *b) 824 { 825 return strncmp(a, b, strlen(b)) == 0; 826 } 827 828 829 void WpaGui::processMsg(char *msg) 830 { 831 char *pos = msg, *pos2; 832 int priority = 2; 833 834 if (*pos == '<') { 835 /* skip priority */ 836 pos++; 837 priority = atoi(pos); 838 pos = strchr(pos, '>'); 839 if (pos) 840 pos++; 841 else 842 pos = msg; 843 } 844 845 WpaMsg wm(pos, priority); 846 if (eh) 847 eh->addEvent(wm); 848 if (peers) 849 peers->event_notify(wm); 850 msgs.append(wm); 851 while (msgs.count() > 100) 852 msgs.pop_front(); 853 854 /* Update last message with truncated version of the event */ 855 if (strncmp(pos, "CTRL-", 5) == 0) { 856 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); 857 if (pos2) 858 pos2++; 859 else 860 pos2 = pos; 861 } else 862 pos2 = pos; 863 QString lastmsg = pos2; 864 lastmsg.truncate(40); 865 textLastMessage->setText(lastmsg); 866 867 pingsToStatusUpdate = 0; 868 networkMayHaveChanged = true; 869 870 if (str_match(pos, WPA_CTRL_REQ)) 871 processCtrlReq(pos + strlen(WPA_CTRL_REQ)); 872 else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) 873 scanres->updateResults(); 874 else if (str_match(pos, WPA_EVENT_DISCONNECTED)) 875 showTrayMessage(QSystemTrayIcon::Information, 3, 876 tr("Disconnected from network.")); 877 else if (str_match(pos, WPA_EVENT_CONNECTED)) { 878 showTrayMessage(QSystemTrayIcon::Information, 3, 879 tr("Connection to network established.")); 880 QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); 881 stopWpsRun(true); 882 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { 883 wpsStatusText->setText(tr("WPS AP in active PBC mode found")); 884 if (textStatus->text() == "INACTIVE" || 885 textStatus->text() == "DISCONNECTED") 886 wpaguiTab->setCurrentWidget(wpsTab); 887 wpsInstructions->setText(tr("Press the PBC button on the " 888 "screen to start registration")); 889 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { 890 wpsStatusText->setText(tr("WPS AP with recently selected " 891 "registrar")); 892 if (textStatus->text() == "INACTIVE" || 893 textStatus->text() == "DISCONNECTED") 894 wpaguiTab->setCurrentWidget(wpsTab); 895 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) { 896 showTrayMessage(QSystemTrayIcon::Information, 3, 897 "Wi-Fi Protected Setup (WPS) AP\n" 898 "indicating this client is authorized."); 899 wpsStatusText->setText("WPS AP indicating this client is " 900 "authorized"); 901 if (textStatus->text() == "INACTIVE" || 902 textStatus->text() == "DISCONNECTED") 903 wpaguiTab->setCurrentWidget(wpsTab); 904 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { 905 wpsStatusText->setText(tr("WPS AP detected")); 906 } else if (str_match(pos, WPS_EVENT_OVERLAP)) { 907 wpsStatusText->setText(tr("PBC mode overlap detected")); 908 wpsInstructions->setText(tr("More than one AP is currently in " 909 "active WPS PBC mode. Wait couple " 910 "of minutes and try again")); 911 wpaguiTab->setCurrentWidget(wpsTab); 912 } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { 913 wpsStatusText->setText(tr("Network configuration received")); 914 wpaguiTab->setCurrentWidget(wpsTab); 915 } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { 916 if (strstr(pos, "(WSC)")) 917 wpsStatusText->setText(tr("Registration started")); 918 } else if (str_match(pos, WPS_EVENT_M2D)) { 919 wpsStatusText->setText(tr("Registrar does not yet know PIN")); 920 } else if (str_match(pos, WPS_EVENT_FAIL)) { 921 wpsStatusText->setText(tr("Registration failed")); 922 } else if (str_match(pos, WPS_EVENT_SUCCESS)) { 923 wpsStatusText->setText(tr("Registration succeeded")); 924 } 925 } 926 927 928 void WpaGui::processCtrlReq(const char *req) 929 { 930 if (udr) { 931 udr->close(); 932 delete udr; 933 } 934 udr = new UserDataRequest(); 935 if (udr == NULL) 936 return; 937 if (udr->setParams(this, req) < 0) { 938 delete udr; 939 udr = NULL; 940 return; 941 } 942 udr->show(); 943 udr->exec(); 944 } 945 946 947 void WpaGui::receiveMsgs() 948 { 949 char buf[256]; 950 size_t len; 951 952 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { 953 len = sizeof(buf) - 1; 954 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { 955 buf[len] = '\0'; 956 processMsg(buf); 957 } 958 } 959 } 960 961 962 void WpaGui::connectB() 963 { 964 char reply[10]; 965 size_t reply_len = sizeof(reply); 966 ctrlRequest("REASSOCIATE", reply, &reply_len); 967 } 968 969 970 void WpaGui::selectNetwork( const QString &sel ) 971 { 972 QString cmd(sel); 973 char reply[10]; 974 size_t reply_len = sizeof(reply); 975 976 if (cmd.contains(QRegExp("^\\d+:"))) 977 cmd.truncate(cmd.indexOf(':')); 978 else 979 cmd = "any"; 980 cmd.prepend("SELECT_NETWORK "); 981 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); 982 triggerUpdate(); 983 stopWpsRun(false); 984 } 985 986 987 void WpaGui::enableNetwork(const QString &sel) 988 { 989 QString cmd(sel); 990 char reply[10]; 991 size_t reply_len = sizeof(reply); 992 993 if (cmd.contains(QRegExp("^\\d+:"))) 994 cmd.truncate(cmd.indexOf(':')); 995 else if (!cmd.startsWith("all")) { 996 printf("Invalid editNetwork '%s'\n", 997 cmd.toAscii().constData()); 998 return; 999 } 1000 cmd.prepend("ENABLE_NETWORK "); 1001 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); 1002 triggerUpdate(); 1003 } 1004 1005 1006 void WpaGui::disableNetwork(const QString &sel) 1007 { 1008 QString cmd(sel); 1009 char reply[10]; 1010 size_t reply_len = sizeof(reply); 1011 1012 if (cmd.contains(QRegExp("^\\d+:"))) 1013 cmd.truncate(cmd.indexOf(':')); 1014 else if (!cmd.startsWith("all")) { 1015 printf("Invalid editNetwork '%s'\n", 1016 cmd.toAscii().constData()); 1017 return; 1018 } 1019 cmd.prepend("DISABLE_NETWORK "); 1020 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); 1021 triggerUpdate(); 1022 } 1023 1024 1025 void WpaGui::editNetwork(const QString &sel) 1026 { 1027 QString cmd(sel); 1028 int id = -1; 1029 1030 if (cmd.contains(QRegExp("^\\d+:"))) { 1031 cmd.truncate(cmd.indexOf(':')); 1032 id = cmd.toInt(); 1033 } 1034 1035 NetworkConfig *nc = new NetworkConfig(); 1036 if (nc == NULL) 1037 return; 1038 nc->setWpaGui(this); 1039 1040 if (id >= 0) 1041 nc->paramsFromConfig(id); 1042 else 1043 nc->newNetwork(); 1044 1045 nc->show(); 1046 nc->exec(); 1047 } 1048 1049 1050 void WpaGui::editSelectedNetwork() 1051 { 1052 if (networkSelect->count() < 1) { 1053 QMessageBox::information( 1054 this, tr("No Networks"), 1055 tr("There are no networks to edit.\n")); 1056 return; 1057 } 1058 QString sel(networkSelect->currentText()); 1059 editNetwork(sel); 1060 } 1061 1062 1063 void WpaGui::editListedNetwork() 1064 { 1065 if (networkList->currentRow() < 0) { 1066 QMessageBox::information(this, tr("Select A Network"), 1067 tr("Select a network from the list to" 1068 " edit it.\n")); 1069 return; 1070 } 1071 QString sel(networkList->currentItem()->text()); 1072 editNetwork(sel); 1073 } 1074 1075 1076 void WpaGui::triggerUpdate() 1077 { 1078 updateStatus(); 1079 networkMayHaveChanged = true; 1080 updateNetworks(); 1081 } 1082 1083 1084 void WpaGui::addNetwork() 1085 { 1086 NetworkConfig *nc = new NetworkConfig(); 1087 if (nc == NULL) 1088 return; 1089 nc->setWpaGui(this); 1090 nc->newNetwork(); 1091 nc->show(); 1092 nc->exec(); 1093 } 1094 1095 1096 void WpaGui::removeNetwork(const QString &sel) 1097 { 1098 QString cmd(sel); 1099 char reply[10]; 1100 size_t reply_len = sizeof(reply); 1101 1102 if (cmd.contains(QRegExp("^\\d+:"))) 1103 cmd.truncate(cmd.indexOf(':')); 1104 else if (!cmd.startsWith("all")) { 1105 printf("Invalid editNetwork '%s'\n", 1106 cmd.toAscii().constData()); 1107 return; 1108 } 1109 cmd.prepend("REMOVE_NETWORK "); 1110 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); 1111 triggerUpdate(); 1112 } 1113 1114 1115 void WpaGui::removeSelectedNetwork() 1116 { 1117 if (networkSelect->count() < 1) { 1118 QMessageBox::information(this, tr("No Networks"), 1119 tr("There are no networks to remove." 1120 "\n")); 1121 return; 1122 } 1123 QString sel(networkSelect->currentText()); 1124 removeNetwork(sel); 1125 } 1126 1127 1128 void WpaGui::removeListedNetwork() 1129 { 1130 if (networkList->currentRow() < 0) { 1131 QMessageBox::information(this, tr("Select A Network"), 1132 tr("Select a network from the list " 1133 "to remove it.\n")); 1134 return; 1135 } 1136 QString sel(networkList->currentItem()->text()); 1137 removeNetwork(sel); 1138 } 1139 1140 1141 void WpaGui::enableAllNetworks() 1142 { 1143 QString sel("all"); 1144 enableNetwork(sel); 1145 } 1146 1147 1148 void WpaGui::disableAllNetworks() 1149 { 1150 QString sel("all"); 1151 disableNetwork(sel); 1152 } 1153 1154 1155 void WpaGui::removeAllNetworks() 1156 { 1157 QString sel("all"); 1158 removeNetwork(sel); 1159 } 1160 1161 1162 int WpaGui::getNetworkDisabled(const QString &sel) 1163 { 1164 QString cmd(sel); 1165 char reply[10]; 1166 size_t reply_len = sizeof(reply) - 1; 1167 int pos = cmd.indexOf(':'); 1168 if (pos < 0) { 1169 printf("Invalid getNetworkDisabled '%s'\n", 1170 cmd.toAscii().constData()); 1171 return -1; 1172 } 1173 cmd.truncate(pos); 1174 cmd.prepend("GET_NETWORK "); 1175 cmd.append(" disabled"); 1176 1177 if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0 1178 && reply_len >= 1) { 1179 reply[reply_len] = '\0'; 1180 if (!str_match(reply, "FAIL")) 1181 return atoi(reply); 1182 } 1183 1184 return -1; 1185 } 1186 1187 1188 void WpaGui::updateNetworkDisabledStatus() 1189 { 1190 if (networkList->currentRow() < 0) 1191 return; 1192 1193 QString sel(networkList->currentItem()->text()); 1194 1195 switch (getNetworkDisabled(sel)) { 1196 case 0: 1197 if (!enableRadioButton->isChecked()) 1198 enableRadioButton->setChecked(true); 1199 return; 1200 case 1: 1201 if (!disableRadioButton->isChecked()) 1202 disableRadioButton->setChecked(true); 1203 return; 1204 } 1205 } 1206 1207 1208 void WpaGui::enableListedNetwork(bool enabled) 1209 { 1210 if (networkList->currentRow() < 0 || !enabled) 1211 return; 1212 1213 QString sel(networkList->currentItem()->text()); 1214 1215 if (getNetworkDisabled(sel) == 1) 1216 enableNetwork(sel); 1217 } 1218 1219 1220 void WpaGui::disableListedNetwork(bool disabled) 1221 { 1222 if (networkList->currentRow() < 0 || !disabled) 1223 return; 1224 1225 QString sel(networkList->currentItem()->text()); 1226 1227 if (getNetworkDisabled(sel) == 0) 1228 disableNetwork(sel); 1229 } 1230 1231 1232 void WpaGui::saveConfig() 1233 { 1234 char buf[10]; 1235 size_t len; 1236 1237 len = sizeof(buf) - 1; 1238 ctrlRequest("SAVE_CONFIG", buf, &len); 1239 1240 buf[len] = '\0'; 1241 1242 if (str_match(buf, "FAIL")) 1243 QMessageBox::warning( 1244 this, tr("Failed to save configuration"), 1245 tr("The configuration could not be saved.\n" 1246 "\n" 1247 "The update_config=1 configuration option\n" 1248 "must be used for configuration saving to\n" 1249 "be permitted.\n")); 1250 else 1251 QMessageBox::information( 1252 this, tr("Saved configuration"), 1253 tr("The current configuration was saved." 1254 "\n")); 1255 } 1256 1257 1258 void WpaGui::selectAdapter( const QString & sel ) 1259 { 1260 if (openCtrlConnection(sel.toAscii().constData()) < 0) 1261 printf("Failed to open control connection to " 1262 "wpa_supplicant.\n"); 1263 updateStatus(); 1264 updateNetworks(); 1265 } 1266 1267 1268 void WpaGui::createTrayIcon(bool trayOnly) 1269 { 1270 QApplication::setQuitOnLastWindowClosed(false); 1271 1272 tray_icon = new QSystemTrayIcon(this); 1273 tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface")); 1274 if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) 1275 tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg")); 1276 else 1277 tray_icon->setIcon(QIcon(":/icons/wpa_gui.png")); 1278 1279 connect(tray_icon, 1280 SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 1281 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); 1282 1283 ackTrayIcon = false; 1284 1285 tray_menu = new QMenu(this); 1286 1287 disconnectAction = new QAction(tr("&Disconnect"), this); 1288 reconnectAction = new QAction(tr("Re&connect"), this); 1289 connect(disconnectAction, SIGNAL(triggered()), this, 1290 SLOT(disconnect())); 1291 connect(reconnectAction, SIGNAL(triggered()), this, 1292 SLOT(connectB())); 1293 tray_menu->addAction(disconnectAction); 1294 tray_menu->addAction(reconnectAction); 1295 tray_menu->addSeparator(); 1296 1297 eventAction = new QAction(tr("&Event History"), this); 1298 scanAction = new QAction(tr("Scan &Results"), this); 1299 statAction = new QAction(tr("S&tatus"), this); 1300 connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); 1301 connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); 1302 connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); 1303 tray_menu->addAction(eventAction); 1304 tray_menu->addAction(scanAction); 1305 tray_menu->addAction(statAction); 1306 tray_menu->addSeparator(); 1307 1308 showAction = new QAction(tr("&Show Window"), this); 1309 hideAction = new QAction(tr("&Hide Window"), this); 1310 quitAction = new QAction(tr("&Quit"), this); 1311 connect(showAction, SIGNAL(triggered()), this, SLOT(show())); 1312 connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); 1313 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); 1314 tray_menu->addAction(showAction); 1315 tray_menu->addAction(hideAction); 1316 tray_menu->addSeparator(); 1317 tray_menu->addAction(quitAction); 1318 1319 tray_icon->setContextMenu(tray_menu); 1320 1321 tray_icon->show(); 1322 1323 if (!trayOnly) 1324 show(); 1325 inTray = trayOnly; 1326 } 1327 1328 1329 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, 1330 const QString & msg) 1331 { 1332 if (!QSystemTrayIcon::supportsMessages()) 1333 return; 1334 1335 if (isVisible() || !tray_icon || !tray_icon->isVisible()) 1336 return; 1337 1338 tray_icon->showMessage(qAppName(), msg, type, sec * 1000); 1339 } 1340 1341 1342 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) 1343 { 1344 switch (how) { 1345 /* use close() here instead of hide() and allow the 1346 * custom closeEvent handler take care of children */ 1347 case QSystemTrayIcon::Trigger: 1348 ackTrayIcon = true; 1349 if (isVisible()) { 1350 close(); 1351 inTray = true; 1352 } else { 1353 show(); 1354 inTray = false; 1355 } 1356 break; 1357 case QSystemTrayIcon::MiddleClick: 1358 showTrayStatus(); 1359 break; 1360 default: 1361 break; 1362 } 1363 } 1364 1365 1366 void WpaGui::showTrayStatus() 1367 { 1368 char buf[2048]; 1369 size_t len; 1370 1371 len = sizeof(buf) - 1; 1372 if (ctrlRequest("STATUS", buf, &len) < 0) 1373 return; 1374 buf[len] = '\0'; 1375 1376 QString msg, status(buf); 1377 1378 QStringList lines = status.split(QRegExp("\\n")); 1379 for (QStringList::Iterator it = lines.begin(); 1380 it != lines.end(); it++) { 1381 int pos = (*it).indexOf('=') + 1; 1382 if (pos < 1) 1383 continue; 1384 1385 if ((*it).startsWith("bssid=")) 1386 msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); 1387 else if ((*it).startsWith("ssid=")) 1388 msg.append("SSID: \t" + (*it).mid(pos) + "\n"); 1389 else if ((*it).startsWith("pairwise_cipher=")) 1390 msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); 1391 else if ((*it).startsWith("group_cipher=")) 1392 msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); 1393 else if ((*it).startsWith("key_mgmt=")) 1394 msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); 1395 else if ((*it).startsWith("wpa_state=")) 1396 msg.append("STATE:\t" + (*it).mid(pos) + "\n"); 1397 else if ((*it).startsWith("ip_address=")) 1398 msg.append("IP: \t" + (*it).mid(pos) + "\n"); 1399 else if ((*it).startsWith("Supplicant PAE state=")) 1400 msg.append("PAE: \t" + (*it).mid(pos) + "\n"); 1401 else if ((*it).startsWith("EAP state=")) 1402 msg.append("EAP: \t" + (*it).mid(pos) + "\n"); 1403 } 1404 1405 if (!msg.isEmpty()) 1406 showTrayMessage(QSystemTrayIcon::Information, 10, msg); 1407 } 1408 1409 1410 void WpaGui::closeEvent(QCloseEvent *event) 1411 { 1412 if (eh) { 1413 eh->close(); 1414 delete eh; 1415 eh = NULL; 1416 } 1417 1418 if (scanres) { 1419 scanres->close(); 1420 delete scanres; 1421 scanres = NULL; 1422 } 1423 1424 if (peers) { 1425 peers->close(); 1426 delete peers; 1427 peers = NULL; 1428 } 1429 1430 if (udr) { 1431 udr->close(); 1432 delete udr; 1433 udr = NULL; 1434 } 1435 1436 if (tray_icon && !ackTrayIcon) { 1437 /* give user a visual hint that the tray icon exists */ 1438 if (QSystemTrayIcon::supportsMessages()) { 1439 hide(); 1440 showTrayMessage(QSystemTrayIcon::Information, 3, 1441 qAppName() + 1442 tr(" will keep running in " 1443 "the system tray.")); 1444 } else { 1445 QMessageBox::information(this, qAppName() + 1446 tr(" systray"), 1447 tr("The program will keep " 1448 "running in the system " 1449 "tray.")); 1450 } 1451 ackTrayIcon = true; 1452 } 1453 1454 event->accept(); 1455 } 1456 1457 1458 void WpaGui::wpsDialog() 1459 { 1460 wpaguiTab->setCurrentWidget(wpsTab); 1461 } 1462 1463 1464 void WpaGui::peersDialog() 1465 { 1466 if (peers) { 1467 peers->close(); 1468 delete peers; 1469 } 1470 1471 peers = new Peers(); 1472 if (peers == NULL) 1473 return; 1474 peers->setWpaGui(this); 1475 peers->show(); 1476 peers->exec(); 1477 } 1478 1479 1480 void WpaGui::tabChanged(int index) 1481 { 1482 if (index != 2) 1483 return; 1484 1485 if (wpsRunning) 1486 return; 1487 1488 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); 1489 if (bssFromScan.isEmpty()) 1490 wpsApPinButton->setEnabled(false); 1491 } 1492 1493 1494 void WpaGui::wpsPbc() 1495 { 1496 char reply[20]; 1497 size_t reply_len = sizeof(reply); 1498 1499 if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) 1500 return; 1501 1502 wpsPinEdit->setEnabled(false); 1503 if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) { 1504 wpsInstructions->setText(tr("Press the push button on the AP to " 1505 "start the PBC mode.")); 1506 } else { 1507 wpsInstructions->setText(tr("If you have not yet done so, press " 1508 "the push button on the AP to start " 1509 "the PBC mode.")); 1510 } 1511 wpsStatusText->setText(tr("Waiting for Registrar")); 1512 wpsRunning = true; 1513 } 1514 1515 1516 void WpaGui::wpsGeneratePin() 1517 { 1518 char reply[20]; 1519 size_t reply_len = sizeof(reply) - 1; 1520 1521 if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) 1522 return; 1523 1524 reply[reply_len] = '\0'; 1525 1526 wpsPinEdit->setText(reply); 1527 wpsPinEdit->setEnabled(true); 1528 wpsInstructions->setText(tr("Enter the generated PIN into the Registrar " 1529 "(either the internal one in the AP or an " 1530 "external one).")); 1531 wpsStatusText->setText(tr("Waiting for Registrar")); 1532 wpsRunning = true; 1533 } 1534 1535 1536 void WpaGui::setBssFromScan(const QString &bssid) 1537 { 1538 bssFromScan = bssid; 1539 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); 1540 wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); 1541 wpsStatusText->setText(tr("WPS AP selected from scan results")); 1542 wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., " 1543 "from a label in the device, enter the eight " 1544 "digit AP PIN and click Use AP PIN button.")); 1545 } 1546 1547 1548 void WpaGui::wpsApPinChanged(const QString &text) 1549 { 1550 wpsApPinButton->setEnabled(text.length() == 8); 1551 } 1552 1553 1554 void WpaGui::wpsApPin() 1555 { 1556 char reply[20]; 1557 size_t reply_len = sizeof(reply); 1558 1559 QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); 1560 if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0) 1561 return; 1562 1563 wpsStatusText->setText(tr("Waiting for AP/Enrollee")); 1564 wpsRunning = true; 1565 } 1566 1567 1568 void WpaGui::stopWpsRun(bool success) 1569 { 1570 if (wpsRunning) 1571 wpsStatusText->setText(success ? tr("Connected to the network") : 1572 tr("Stopped")); 1573 else 1574 wpsStatusText->setText(""); 1575 wpsPinEdit->setEnabled(false); 1576 wpsInstructions->setText(""); 1577 wpsRunning = false; 1578 bssFromScan = ""; 1579 wpsApPinEdit->setEnabled(false); 1580 wpsApPinButton->setEnabled(false); 1581 } 1582 1583 1584 #ifdef CONFIG_NATIVE_WINDOWS 1585 1586 #ifndef WPASVC_NAME 1587 #define WPASVC_NAME TEXT("wpasvc") 1588 #endif 1589 1590 class ErrorMsg : public QMessageBox { 1591 public: 1592 ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); 1593 void showMsg(QString msg); 1594 private: 1595 DWORD err; 1596 }; 1597 1598 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : 1599 QMessageBox(parent), err(last_err) 1600 { 1601 setWindowTitle(tr("wpa_gui error")); 1602 setIcon(QMessageBox::Warning); 1603 } 1604 1605 void ErrorMsg::showMsg(QString msg) 1606 { 1607 LPTSTR buf; 1608 1609 setText(msg); 1610 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1611 FORMAT_MESSAGE_FROM_SYSTEM, 1612 NULL, err, 0, (LPTSTR) (void *) &buf, 1613 0, NULL) > 0) { 1614 QString msg = QString::fromWCharArray(buf); 1615 setInformativeText(QString("[%1] %2").arg(err).arg(msg)); 1616 LocalFree(buf); 1617 } else { 1618 setInformativeText(QString("[%1]").arg(err)); 1619 } 1620 1621 exec(); 1622 } 1623 1624 1625 void WpaGui::startService() 1626 { 1627 SC_HANDLE svc, scm; 1628 1629 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1630 if (!scm) { 1631 ErrorMsg(this).showMsg(tr("OpenSCManager failed")); 1632 return; 1633 } 1634 1635 svc = OpenService(scm, WPASVC_NAME, SERVICE_START); 1636 if (!svc) { 1637 ErrorMsg(this).showMsg(tr("OpenService failed")); 1638 CloseServiceHandle(scm); 1639 return; 1640 } 1641 1642 if (!StartService(svc, 0, NULL)) { 1643 ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant " 1644 "service")); 1645 } 1646 1647 CloseServiceHandle(svc); 1648 CloseServiceHandle(scm); 1649 } 1650 1651 1652 void WpaGui::stopService() 1653 { 1654 SC_HANDLE svc, scm; 1655 SERVICE_STATUS status; 1656 1657 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1658 if (!scm) { 1659 ErrorMsg(this).showMsg(tr("OpenSCManager failed")); 1660 return; 1661 } 1662 1663 svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); 1664 if (!svc) { 1665 ErrorMsg(this).showMsg(tr("OpenService failed")); 1666 CloseServiceHandle(scm); 1667 return; 1668 } 1669 1670 if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { 1671 ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant " 1672 "service")); 1673 } 1674 1675 CloseServiceHandle(svc); 1676 CloseServiceHandle(scm); 1677 } 1678 1679 1680 bool WpaGui::serviceRunning() 1681 { 1682 SC_HANDLE svc, scm; 1683 SERVICE_STATUS status; 1684 bool running = false; 1685 1686 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1687 if (!scm) { 1688 printf("OpenSCManager failed: %d\n", (int) GetLastError()); 1689 return false; 1690 } 1691 1692 svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); 1693 if (!svc) { 1694 printf("OpenService failed: %d\n\n", (int) GetLastError()); 1695 CloseServiceHandle(scm); 1696 return false; 1697 } 1698 1699 if (QueryServiceStatus(svc, &status)) { 1700 if (status.dwCurrentState != SERVICE_STOPPED) 1701 running = true; 1702 } 1703 1704 CloseServiceHandle(svc); 1705 CloseServiceHandle(scm); 1706 1707 return running; 1708 } 1709 1710 #endif /* CONFIG_NATIVE_WINDOWS */ 1711 1712 1713 void WpaGui::addInterface() 1714 { 1715 if (add_iface) { 1716 add_iface->close(); 1717 delete add_iface; 1718 } 1719 add_iface = new AddInterface(this, this); 1720 add_iface->show(); 1721 add_iface->exec(); 1722 } 1723 1724 1725 #ifndef QT_NO_SESSIONMANAGER 1726 void WpaGui::saveState() 1727 { 1728 QSettings settings("wpa_supplicant", "wpa_gui"); 1729 settings.beginGroup("state"); 1730 settings.setValue("session_id", app->sessionId()); 1731 settings.setValue("in_tray", inTray); 1732 settings.endGroup(); 1733 } 1734 #endif 1735