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 if (group_cipher) { 362 encr.append(group_cipher); 363 encr.append(" [group key only]"); 364 } else { 365 encr.append("?"); 366 } 367 textEncryption->setText(encr); 368 } else 369 textEncryption->clear(); 370 371 if (!status_updated) 372 textStatus->clear(); 373 if (!auth_updated) 374 textAuthentication->clear(); 375 if (!ssid_updated) 376 textSsid->clear(); 377 if (!bssid_updated) 378 textBssid->clear(); 379 if (!ipaddr_updated) 380 textIpAddress->clear(); 381 } 382 383 384 void WpaGui::updateNetworks() 385 { 386 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; 387 size_t len; 388 int first_active = -1; 389 bool selected = false; 390 391 if (!networkMayHaveChanged) 392 return; 393 394 networkSelect->clear(); 395 396 if (ctrl_conn == NULL) 397 return; 398 399 len = sizeof(buf) - 1; 400 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 401 return; 402 403 buf[len] = '\0'; 404 start = strchr(buf, '\n'); 405 if (start == NULL) 406 return; 407 start++; 408 409 while (*start) { 410 bool last = false; 411 end = strchr(start, '\n'); 412 if (end == NULL) { 413 last = true; 414 end = start; 415 while (end[0] && end[1]) 416 end++; 417 } 418 *end = '\0'; 419 420 id = start; 421 ssid = strchr(id, '\t'); 422 if (ssid == NULL) 423 break; 424 *ssid++ = '\0'; 425 bssid = strchr(ssid, '\t'); 426 if (bssid == NULL) 427 break; 428 *bssid++ = '\0'; 429 flags = strchr(bssid, '\t'); 430 if (flags == NULL) 431 break; 432 *flags++ = '\0'; 433 434 QString network(id); 435 network.append(": "); 436 network.append(ssid); 437 networkSelect->insertItem(network); 438 439 if (strstr(flags, "[CURRENT]")) { 440 networkSelect->setCurrentItem(networkSelect->count() - 1); 441 selected = true; 442 } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL) 443 first_active = networkSelect->count() - 1; 444 445 if (last) 446 break; 447 start = end + 1; 448 } 449 450 if (!selected && first_active >= 0) 451 networkSelect->setCurrentItem(first_active); 452 453 networkMayHaveChanged = false; 454 } 455 456 457 void WpaGui::helpIndex() 458 { 459 printf("helpIndex\n"); 460 } 461 462 463 void WpaGui::helpContents() 464 { 465 printf("helpContents\n"); 466 } 467 468 469 void WpaGui::helpAbout() 470 { 471 QMessageBox::about(this, "wpa_gui for wpa_supplicant", 472 "Copyright (c) 2003-2008,\n" 473 "Jouni Malinen <j (at) w1.fi>\n" 474 "and contributors.\n" 475 "\n" 476 "This program is free software. You can\n" 477 "distribute it and/or modify it under the terms of\n" 478 "the GNU General Public License version 2.\n" 479 "\n" 480 "Alternatively, this software may be distributed\n" 481 "under the terms of the BSD license.\n" 482 "\n" 483 "This product includes software developed\n" 484 "by the OpenSSL Project for use in the\n" 485 "OpenSSL Toolkit (http://www.openssl.org/)\n"); 486 } 487 488 489 void WpaGui::disconnect() 490 { 491 char reply[10]; 492 size_t reply_len = sizeof(reply); 493 ctrlRequest("DISCONNECT", reply, &reply_len); 494 } 495 496 497 void WpaGui::scan() 498 { 499 if (scanres) { 500 scanres->close(); 501 delete scanres; 502 } 503 504 scanres = new ScanResults(); 505 if (scanres == NULL) 506 return; 507 scanres->setWpaGui(this); 508 scanres->show(); 509 scanres->exec(); 510 } 511 512 513 void WpaGui::eventHistory() 514 { 515 if (eh) { 516 eh->close(); 517 delete eh; 518 } 519 520 eh = new EventHistory(); 521 if (eh == NULL) 522 return; 523 eh->addEvents(msgs); 524 eh->show(); 525 eh->exec(); 526 } 527 528 529 void WpaGui::ping() 530 { 531 char buf[10]; 532 size_t len; 533 534 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 535 /* 536 * QSocketNotifier cannot be used with Windows named pipes, so use a timer 537 * to check for received messages for now. This could be optimized be doing 538 * something specific to named pipes or Windows events, but it is not clear 539 * what would be the best way of doing that in Qt. 540 */ 541 receiveMsgs(); 542 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 543 544 if (scanres && !scanres->isVisible()) { 545 delete scanres; 546 scanres = NULL; 547 } 548 549 if (eh && !eh->isVisible()) { 550 delete eh; 551 eh = NULL; 552 } 553 554 if (udr && !udr->isVisible()) { 555 delete udr; 556 udr = NULL; 557 } 558 559 len = sizeof(buf) - 1; 560 if (ctrlRequest("PING", buf, &len) < 0) { 561 printf("PING failed - trying to reconnect\n"); 562 if (openCtrlConnection(ctrl_iface) >= 0) { 563 printf("Reconnected successfully\n"); 564 pingsToStatusUpdate = 0; 565 } 566 } 567 568 pingsToStatusUpdate--; 569 if (pingsToStatusUpdate <= 0) { 570 updateStatus(); 571 updateNetworks(); 572 } 573 } 574 575 576 static int str_match(const char *a, const char *b) 577 { 578 return strncmp(a, b, strlen(b)) == 0; 579 } 580 581 582 void WpaGui::processMsg(char *msg) 583 { 584 char *pos = msg, *pos2; 585 int priority = 2; 586 587 if (*pos == '<') { 588 /* skip priority */ 589 pos++; 590 priority = atoi(pos); 591 pos = strchr(pos, '>'); 592 if (pos) 593 pos++; 594 else 595 pos = msg; 596 } 597 598 WpaMsg wm(pos, priority); 599 if (eh) 600 eh->addEvent(wm); 601 msgs.append(wm); 602 while (msgs.count() > 100) 603 msgs.pop_front(); 604 605 /* Update last message with truncated version of the event */ 606 if (strncmp(pos, "CTRL-", 5) == 0) { 607 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); 608 if (pos2) 609 pos2++; 610 else 611 pos2 = pos; 612 } else 613 pos2 = pos; 614 QString lastmsg = pos2; 615 lastmsg.truncate(40); 616 textLastMessage->setText(lastmsg); 617 618 pingsToStatusUpdate = 0; 619 networkMayHaveChanged = true; 620 621 if (str_match(pos, WPA_CTRL_REQ)) 622 processCtrlReq(pos + strlen(WPA_CTRL_REQ)); 623 } 624 625 626 void WpaGui::processCtrlReq(const char *req) 627 { 628 if (udr) { 629 udr->close(); 630 delete udr; 631 } 632 udr = new UserDataRequest(); 633 if (udr == NULL) 634 return; 635 if (udr->setParams(this, req) < 0) { 636 delete udr; 637 udr = NULL; 638 return; 639 } 640 udr->show(); 641 udr->exec(); 642 } 643 644 645 void WpaGui::receiveMsgs() 646 { 647 char buf[256]; 648 size_t len; 649 650 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { 651 len = sizeof(buf) - 1; 652 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { 653 buf[len] = '\0'; 654 processMsg(buf); 655 } 656 } 657 } 658 659 660 void WpaGui::connectB() 661 { 662 char reply[10]; 663 size_t reply_len = sizeof(reply); 664 ctrlRequest("REASSOCIATE", reply, &reply_len); 665 } 666 667 668 void WpaGui::selectNetwork( const QString &sel ) 669 { 670 QString cmd(sel); 671 char reply[10]; 672 size_t reply_len = sizeof(reply); 673 674 int pos = cmd.find(':'); 675 if (pos < 0) { 676 printf("Invalid selectNetwork '%s'\n", cmd.ascii()); 677 return; 678 } 679 cmd.truncate(pos); 680 cmd.prepend("SELECT_NETWORK "); 681 ctrlRequest(cmd.ascii(), reply, &reply_len); 682 } 683 684 685 void WpaGui::editNetwork() 686 { 687 QString sel(networkSelect->currentText()); 688 int pos = sel.find(':'); 689 if (pos < 0) { 690 printf("Invalid selectNetwork '%s'\n", sel.ascii()); 691 return; 692 } 693 sel.truncate(pos); 694 695 NetworkConfig *nc = new NetworkConfig(); 696 if (nc == NULL) 697 return; 698 nc->setWpaGui(this); 699 700 nc->paramsFromConfig(sel.toInt()); 701 nc->show(); 702 nc->exec(); 703 } 704 705 706 void WpaGui::triggerUpdate() 707 { 708 updateStatus(); 709 networkMayHaveChanged = true; 710 updateNetworks(); 711 } 712 713 714 void WpaGui::addNetwork() 715 { 716 NetworkConfig *nc = new NetworkConfig(); 717 if (nc == NULL) 718 return; 719 nc->setWpaGui(this); 720 nc->newNetwork(); 721 nc->show(); 722 nc->exec(); 723 } 724 725 726 void WpaGui::selectAdapter( const QString & sel ) 727 { 728 if (openCtrlConnection(sel.ascii()) < 0) 729 printf("Failed to open control connection to wpa_supplicant.\n"); 730 updateStatus(); 731 updateNetworks(); 732 } 733