1 /**************************************************************************** 2 ** ui.h extension file, included from the uic-generated form implementation. 3 ** 4 ** If you want to add, delete, or rename functions or slots, use 5 ** Qt Designer to update this file, preserving your code. 6 ** 7 ** You should not define a constructor or destructor in this file. 8 ** Instead, write your code in functions called init() and destroy(). 9 ** These will automatically be called by the form's constructor and 10 ** destructor. 11 *****************************************************************************/ 12 13 14 #ifdef __MINGW32__ 15 /* Need to get getopt() */ 16 #include <unistd.h> 17 #endif 18 19 #include <stdlib.h> 20 21 void WpaGui::init() 22 { 23 eh = NULL; 24 scanres = NULL; 25 udr = NULL; 26 ctrl_iface = NULL; 27 ctrl_conn = NULL; 28 monitor_conn = NULL; 29 msgNotifier = NULL; 30 ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); 31 32 parse_argv(); 33 34 textStatus->setText("connecting to wpa_supplicant"); 35 timer = new QTimer(this); 36 connect(timer, SIGNAL(timeout()), SLOT(ping())); 37 timer->start(1000, FALSE); 38 39 if (openCtrlConnection(ctrl_iface) < 0) { 40 printf("Failed to open control connection to wpa_supplicant.\n"); 41 } 42 43 updateStatus(); 44 networkMayHaveChanged = true; 45 updateNetworks(); 46 } 47 48 49 void WpaGui::destroy() 50 { 51 delete msgNotifier; 52 53 if (monitor_conn) { 54 wpa_ctrl_detach(monitor_conn); 55 wpa_ctrl_close(monitor_conn); 56 monitor_conn = NULL; 57 } 58 if (ctrl_conn) { 59 wpa_ctrl_close(ctrl_conn); 60 ctrl_conn = NULL; 61 } 62 63 if (eh) { 64 eh->close(); 65 delete eh; 66 eh = NULL; 67 } 68 69 if (scanres) { 70 scanres->close(); 71 delete scanres; 72 scanres = NULL; 73 } 74 75 if (udr) { 76 udr->close(); 77 delete udr; 78 udr = NULL; 79 } 80 81 free(ctrl_iface); 82 ctrl_iface = NULL; 83 84 free(ctrl_iface_dir); 85 ctrl_iface_dir = NULL; 86 } 87 88 89 void WpaGui::parse_argv() 90 { 91 int c; 92 for (;;) { 93 c = getopt(qApp->argc(), qApp->argv(), "i:p:"); 94 if (c < 0) 95 break; 96 switch (c) { 97 case 'i': 98 free(ctrl_iface); 99 ctrl_iface = strdup(optarg); 100 break; 101 case 'p': 102 free(ctrl_iface_dir); 103 ctrl_iface_dir = strdup(optarg); 104 break; 105 } 106 } 107 } 108 109 110 int WpaGui::openCtrlConnection(const char *ifname) 111 { 112 char *cfile; 113 int flen; 114 char buf[2048], *pos, *pos2; 115 size_t len; 116 117 if (ifname) { 118 if (ifname != ctrl_iface) { 119 free(ctrl_iface); 120 ctrl_iface = strdup(ifname); 121 } 122 } else { 123 #ifdef CONFIG_CTRL_IFACE_UDP 124 free(ctrl_iface); 125 ctrl_iface = strdup("udp"); 126 #endif /* CONFIG_CTRL_IFACE_UDP */ 127 #ifdef CONFIG_CTRL_IFACE_UNIX 128 struct dirent *dent; 129 DIR *dir = opendir(ctrl_iface_dir); 130 free(ctrl_iface); 131 ctrl_iface = NULL; 132 if (dir) { 133 while ((dent = readdir(dir))) { 134 #ifdef _DIRENT_HAVE_D_TYPE 135 /* Skip the file if it is not a socket. 136 * Also accept DT_UNKNOWN (0) in case 137 * the C library or underlying file 138 * system does not support d_type. */ 139 if (dent->d_type != DT_SOCK && 140 dent->d_type != DT_UNKNOWN) 141 continue; 142 #endif /* _DIRENT_HAVE_D_TYPE */ 143 144 if (strcmp(dent->d_name, ".") == 0 || 145 strcmp(dent->d_name, "..") == 0) 146 continue; 147 printf("Selected interface '%s'\n", dent->d_name); 148 ctrl_iface = strdup(dent->d_name); 149 break; 150 } 151 closedir(dir); 152 } 153 #endif /* CONFIG_CTRL_IFACE_UNIX */ 154 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 155 struct wpa_ctrl *ctrl; 156 int ret; 157 158 free(ctrl_iface); 159 ctrl_iface = NULL; 160 161 ctrl = wpa_ctrl_open(NULL); 162 if (ctrl) { 163 len = sizeof(buf) - 1; 164 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); 165 if (ret >= 0) { 166 buf[len] = '\0'; 167 pos = strchr(buf, '\n'); 168 if (pos) 169 *pos = '\0'; 170 ctrl_iface = strdup(buf); 171 } 172 wpa_ctrl_close(ctrl); 173 } 174 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 175 } 176 177 if (ctrl_iface == NULL) 178 return -1; 179 180 #ifdef CONFIG_CTRL_IFACE_UNIX 181 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; 182 cfile = (char *) malloc(flen); 183 if (cfile == NULL) 184 return -1; 185 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); 186 #else /* CONFIG_CTRL_IFACE_UNIX */ 187 flen = strlen(ctrl_iface) + 1; 188 cfile = (char *) malloc(flen); 189 if (cfile == NULL) 190 return -1; 191 snprintf(cfile, flen, "%s", ctrl_iface); 192 #endif /* CONFIG_CTRL_IFACE_UNIX */ 193 194 if (ctrl_conn) { 195 wpa_ctrl_close(ctrl_conn); 196 ctrl_conn = NULL; 197 } 198 199 if (monitor_conn) { 200 delete msgNotifier; 201 msgNotifier = NULL; 202 wpa_ctrl_detach(monitor_conn); 203 wpa_ctrl_close(monitor_conn); 204 monitor_conn = NULL; 205 } 206 207 printf("Trying to connect to '%s'\n", cfile); 208 ctrl_conn = wpa_ctrl_open(cfile); 209 if (ctrl_conn == NULL) { 210 free(cfile); 211 return -1; 212 } 213 monitor_conn = wpa_ctrl_open(cfile); 214 free(cfile); 215 if (monitor_conn == NULL) { 216 wpa_ctrl_close(ctrl_conn); 217 return -1; 218 } 219 if (wpa_ctrl_attach(monitor_conn)) { 220 printf("Failed to attach to wpa_supplicant\n"); 221 wpa_ctrl_close(monitor_conn); 222 monitor_conn = NULL; 223 wpa_ctrl_close(ctrl_conn); 224 ctrl_conn = NULL; 225 return -1; 226 } 227 228 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 229 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), 230 QSocketNotifier::Read, this); 231 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); 232 #endif 233 234 adapterSelect->clear(); 235 adapterSelect->insertItem(ctrl_iface); 236 adapterSelect->setCurrentItem(0); 237 238 len = sizeof(buf) - 1; 239 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) { 240 buf[len] = '\0'; 241 pos = buf; 242 while (*pos) { 243 pos2 = strchr(pos, '\n'); 244 if (pos2) 245 *pos2 = '\0'; 246 if (strcmp(pos, ctrl_iface) != 0) 247 adapterSelect->insertItem(pos); 248 if (pos2) 249 pos = pos2 + 1; 250 else 251 break; 252 } 253 } 254 255 return 0; 256 } 257 258 259 static void wpa_gui_msg_cb(char *msg, size_t) 260 { 261 /* This should not happen anymore since two control connections are used. */ 262 printf("missed message: %s\n", msg); 263 } 264 265 266 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) 267 { 268 int ret; 269 270 if (ctrl_conn == NULL) 271 return -3; 272 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, 273 wpa_gui_msg_cb); 274 if (ret == -2) { 275 printf("'%s' command timed out.\n", cmd); 276 } else if (ret < 0) { 277 printf("'%s' command failed.\n", cmd); 278 } 279 280 return ret; 281 } 282 283 284 void WpaGui::updateStatus() 285 { 286 char buf[2048], *start, *end, *pos; 287 size_t len; 288 289 pingsToStatusUpdate = 10; 290 291 len = sizeof(buf) - 1; 292 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { 293 textStatus->setText("Could not get status from wpa_supplicant"); 294 textAuthentication->clear(); 295 textEncryption->clear(); 296 textSsid->clear(); 297 textBssid->clear(); 298 textIpAddress->clear(); 299 return; 300 } 301 302 buf[len] = '\0'; 303 304 bool auth_updated = false, ssid_updated = false; 305 bool bssid_updated = false, ipaddr_updated = false; 306 bool status_updated = false; 307 char *pairwise_cipher = NULL, *group_cipher = NULL; 308 309 start = buf; 310 while (*start) { 311 bool last = false; 312 end = strchr(start, '\n'); 313 if (end == NULL) { 314 last = true; 315 end = start; 316 while (end[0] && end[1]) 317 end++; 318 } 319 *end = '\0'; 320 321 pos = strchr(start, '='); 322 if (pos) { 323 *pos++ = '\0'; 324 if (strcmp(start, "bssid") == 0) { 325 bssid_updated = true; 326 textBssid->setText(pos); 327 } else if (strcmp(start, "ssid") == 0) { 328 ssid_updated = true; 329 textSsid->setText(pos); 330 } else if (strcmp(start, "ip_address") == 0) { 331 ipaddr_updated = true; 332 textIpAddress->setText(pos); 333 } else if (strcmp(start, "wpa_state") == 0) { 334 status_updated = true; 335 textStatus->setText(pos); 336 } else if (strcmp(start, "key_mgmt") == 0) { 337 auth_updated = true; 338 textAuthentication->setText(pos); 339 /* TODO: could add EAP status to this */ 340 } else if (strcmp(start, "pairwise_cipher") == 0) { 341 pairwise_cipher = pos; 342 } else if (strcmp(start, "group_cipher") == 0) { 343 group_cipher = pos; 344 } 345 } 346 347 if (last) 348 break; 349 start = end + 1; 350 } 351 352 if (pairwise_cipher || group_cipher) { 353 QString encr; 354 if (pairwise_cipher && group_cipher && 355 strcmp(pairwise_cipher, group_cipher) != 0) { 356 encr.append(pairwise_cipher); 357 encr.append(" + "); 358 encr.append(group_cipher); 359 } else if (pairwise_cipher) { 360 encr.append(pairwise_cipher); 361 } else { 362 encr.append(group_cipher); 363 encr.append(" [group key only]"); 364 } 365 textEncryption->setText(encr); 366 } else 367 textEncryption->clear(); 368 369 if (!status_updated) 370 textStatus->clear(); 371 if (!auth_updated) 372 textAuthentication->clear(); 373 if (!ssid_updated) 374 textSsid->clear(); 375 if (!bssid_updated) 376 textBssid->clear(); 377 if (!ipaddr_updated) 378 textIpAddress->clear(); 379 } 380 381 382 void WpaGui::updateNetworks() 383 { 384 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; 385 size_t len; 386 int first_active = -1; 387 bool selected = false; 388 389 if (!networkMayHaveChanged) 390 return; 391 392 networkSelect->clear(); 393 394 if (ctrl_conn == NULL) 395 return; 396 397 len = sizeof(buf) - 1; 398 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 399 return; 400 401 buf[len] = '\0'; 402 start = strchr(buf, '\n'); 403 if (start == NULL) 404 return; 405 start++; 406 407 while (*start) { 408 bool last = false; 409 end = strchr(start, '\n'); 410 if (end == NULL) { 411 last = true; 412 end = start; 413 while (end[0] && end[1]) 414 end++; 415 } 416 *end = '\0'; 417 418 id = start; 419 ssid = strchr(id, '\t'); 420 if (ssid == NULL) 421 break; 422 *ssid++ = '\0'; 423 bssid = strchr(ssid, '\t'); 424 if (bssid == NULL) 425 break; 426 *bssid++ = '\0'; 427 flags = strchr(bssid, '\t'); 428 if (flags == NULL) 429 break; 430 *flags++ = '\0'; 431 432 QString network(id); 433 network.append(": "); 434 network.append(ssid); 435 networkSelect->insertItem(network); 436 437 if (strstr(flags, "[CURRENT]")) { 438 networkSelect->setCurrentItem(networkSelect->count() - 1); 439 selected = true; 440 } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL) 441 first_active = networkSelect->count() - 1; 442 443 if (last) 444 break; 445 start = end + 1; 446 } 447 448 if (!selected && first_active >= 0) 449 networkSelect->setCurrentItem(first_active); 450 451 networkMayHaveChanged = false; 452 } 453 454 455 void WpaGui::helpIndex() 456 { 457 printf("helpIndex\n"); 458 } 459 460 461 void WpaGui::helpContents() 462 { 463 printf("helpContents\n"); 464 } 465 466 467 void WpaGui::helpAbout() 468 { 469 QMessageBox::about(this, "wpa_gui for wpa_supplicant", 470 "Copyright (c) 2003-2008,\n" 471 "Jouni Malinen <j (at) w1.fi>\n" 472 "and contributors.\n" 473 "\n" 474 "This program is free software. You can\n" 475 "distribute it and/or modify it under the terms of\n" 476 "the GNU General Public License version 2.\n" 477 "\n" 478 "Alternatively, this software may be distributed\n" 479 "under the terms of the BSD license.\n" 480 "\n" 481 "This product includes software developed\n" 482 "by the OpenSSL Project for use in the\n" 483 "OpenSSL Toolkit (http://www.openssl.org/)\n"); 484 } 485 486 487 void WpaGui::disconnect() 488 { 489 char reply[10]; 490 size_t reply_len = sizeof(reply); 491 ctrlRequest("DISCONNECT", reply, &reply_len); 492 } 493 494 495 void WpaGui::scan() 496 { 497 if (scanres) { 498 scanres->close(); 499 delete scanres; 500 } 501 502 scanres = new ScanResults(); 503 if (scanres == NULL) 504 return; 505 scanres->setWpaGui(this); 506 scanres->show(); 507 scanres->exec(); 508 } 509 510 511 void WpaGui::eventHistory() 512 { 513 if (eh) { 514 eh->close(); 515 delete eh; 516 } 517 518 eh = new EventHistory(); 519 if (eh == NULL) 520 return; 521 eh->addEvents(msgs); 522 eh->show(); 523 eh->exec(); 524 } 525 526 527 void WpaGui::ping() 528 { 529 char buf[10]; 530 size_t len; 531 532 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 533 /* 534 * QSocketNotifier cannot be used with Windows named pipes, so use a timer 535 * to check for received messages for now. This could be optimized be doing 536 * something specific to named pipes or Windows events, but it is not clear 537 * what would be the best way of doing that in Qt. 538 */ 539 receiveMsgs(); 540 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 541 542 if (scanres && !scanres->isVisible()) { 543 delete scanres; 544 scanres = NULL; 545 } 546 547 if (eh && !eh->isVisible()) { 548 delete eh; 549 eh = NULL; 550 } 551 552 if (udr && !udr->isVisible()) { 553 delete udr; 554 udr = NULL; 555 } 556 557 len = sizeof(buf) - 1; 558 if (ctrlRequest("PING", buf, &len) < 0) { 559 printf("PING failed - trying to reconnect\n"); 560 if (openCtrlConnection(ctrl_iface) >= 0) { 561 printf("Reconnected successfully\n"); 562 pingsToStatusUpdate = 0; 563 } 564 } 565 566 pingsToStatusUpdate--; 567 if (pingsToStatusUpdate <= 0) { 568 updateStatus(); 569 updateNetworks(); 570 } 571 } 572 573 574 static int str_match(const char *a, const char *b) 575 { 576 return strncmp(a, b, strlen(b)) == 0; 577 } 578 579 580 void WpaGui::processMsg(char *msg) 581 { 582 char *pos = msg, *pos2; 583 int priority = 2; 584 585 if (*pos == '<') { 586 /* skip priority */ 587 pos++; 588 priority = atoi(pos); 589 pos = strchr(pos, '>'); 590 if (pos) 591 pos++; 592 else 593 pos = msg; 594 } 595 596 WpaMsg wm(pos, priority); 597 if (eh) 598 eh->addEvent(wm); 599 msgs.append(wm); 600 while (msgs.count() > 100) 601 msgs.pop_front(); 602 603 /* Update last message with truncated version of the event */ 604 if (strncmp(pos, "CTRL-", 5) == 0) { 605 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); 606 if (pos2) 607 pos2++; 608 else 609 pos2 = pos; 610 } else 611 pos2 = pos; 612 QString lastmsg = pos2; 613 lastmsg.truncate(40); 614 textLastMessage->setText(lastmsg); 615 616 pingsToStatusUpdate = 0; 617 networkMayHaveChanged = true; 618 619 if (str_match(pos, WPA_CTRL_REQ)) 620 processCtrlReq(pos + strlen(WPA_CTRL_REQ)); 621 } 622 623 624 void WpaGui::processCtrlReq(const char *req) 625 { 626 if (udr) { 627 udr->close(); 628 delete udr; 629 } 630 udr = new UserDataRequest(); 631 if (udr == NULL) 632 return; 633 if (udr->setParams(this, req) < 0) { 634 delete udr; 635 udr = NULL; 636 return; 637 } 638 udr->show(); 639 udr->exec(); 640 } 641 642 643 void WpaGui::receiveMsgs() 644 { 645 char buf[256]; 646 size_t len; 647 648 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { 649 len = sizeof(buf) - 1; 650 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { 651 buf[len] = '\0'; 652 processMsg(buf); 653 } 654 } 655 } 656 657 658 void WpaGui::connectB() 659 { 660 char reply[10]; 661 size_t reply_len = sizeof(reply); 662 ctrlRequest("REASSOCIATE", reply, &reply_len); 663 } 664 665 666 void WpaGui::selectNetwork( const QString &sel ) 667 { 668 QString cmd(sel); 669 char reply[10]; 670 size_t reply_len = sizeof(reply); 671 672 int pos = cmd.find(':'); 673 if (pos < 0) { 674 printf("Invalid selectNetwork '%s'\n", cmd.ascii()); 675 return; 676 } 677 cmd.truncate(pos); 678 cmd.prepend("SELECT_NETWORK "); 679 ctrlRequest(cmd.ascii(), reply, &reply_len); 680 } 681 682 683 void WpaGui::editNetwork() 684 { 685 QString sel(networkSelect->currentText()); 686 int pos = sel.find(':'); 687 if (pos < 0) { 688 printf("Invalid selectNetwork '%s'\n", sel.ascii()); 689 return; 690 } 691 sel.truncate(pos); 692 693 NetworkConfig *nc = new NetworkConfig(); 694 if (nc == NULL) 695 return; 696 nc->setWpaGui(this); 697 698 nc->paramsFromConfig(sel.toInt()); 699 nc->show(); 700 nc->exec(); 701 } 702 703 704 void WpaGui::triggerUpdate() 705 { 706 updateStatus(); 707 networkMayHaveChanged = true; 708 updateNetworks(); 709 } 710 711 712 void WpaGui::addNetwork() 713 { 714 NetworkConfig *nc = new NetworkConfig(); 715 if (nc == NULL) 716 return; 717 nc->setWpaGui(this); 718 nc->newNetwork(); 719 nc->show(); 720 nc->exec(); 721 } 722 723 724 void WpaGui::selectAdapter( const QString & sel ) 725 { 726 if (openCtrlConnection(sel.ascii()) < 0) 727 printf("Failed to open control connection to wpa_supplicant.\n"); 728 updateStatus(); 729 updateNetworks(); 730 } 731