| /**************************************************************************** |
| ** ui.h extension file, included from the uic-generated form implementation. |
| ** |
| ** If you want to add, delete, or rename functions or slots, use |
| ** Qt Designer to update this file, preserving your code. |
| ** |
| ** You should not define a constructor or destructor in this file. |
| ** Instead, write your code in functions called init() and destroy(). |
| ** These will automatically be called by the form's constructor and |
| ** destructor. |
| *****************************************************************************/ |
| |
| |
| #ifdef __MINGW32__ |
| /* Need to get getopt() */ |
| #include <unistd.h> |
| #endif |
| |
| #include <stdlib.h> |
| |
| void WpaGui::init() |
| { |
| eh = NULL; |
| scanres = NULL; |
| udr = NULL; |
| ctrl_iface = NULL; |
| ctrl_conn = NULL; |
| monitor_conn = NULL; |
| msgNotifier = NULL; |
| ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); |
| |
| parse_argv(); |
| |
| textStatus->setText("connecting to wpa_supplicant"); |
| timer = new QTimer(this); |
| connect(timer, SIGNAL(timeout()), SLOT(ping())); |
| timer->start(1000, FALSE); |
| |
| if (openCtrlConnection(ctrl_iface) < 0) { |
| printf("Failed to open control connection to wpa_supplicant.\n"); |
| } |
| |
| updateStatus(); |
| networkMayHaveChanged = true; |
| updateNetworks(); |
| } |
| |
| |
| void WpaGui::destroy() |
| { |
| delete msgNotifier; |
| |
| if (monitor_conn) { |
| wpa_ctrl_detach(monitor_conn); |
| wpa_ctrl_close(monitor_conn); |
| monitor_conn = NULL; |
| } |
| if (ctrl_conn) { |
| wpa_ctrl_close(ctrl_conn); |
| ctrl_conn = NULL; |
| } |
| |
| if (eh) { |
| eh->close(); |
| delete eh; |
| eh = NULL; |
| } |
| |
| if (scanres) { |
| scanres->close(); |
| delete scanres; |
| scanres = NULL; |
| } |
| |
| if (udr) { |
| udr->close(); |
| delete udr; |
| udr = NULL; |
| } |
| |
| free(ctrl_iface); |
| ctrl_iface = NULL; |
| |
| free(ctrl_iface_dir); |
| ctrl_iface_dir = NULL; |
| } |
| |
| |
| void WpaGui::parse_argv() |
| { |
| int c; |
| for (;;) { |
| c = getopt(qApp->argc(), qApp->argv(), "i:p:"); |
| if (c < 0) |
| break; |
| switch (c) { |
| case 'i': |
| free(ctrl_iface); |
| ctrl_iface = strdup(optarg); |
| break; |
| case 'p': |
| free(ctrl_iface_dir); |
| ctrl_iface_dir = strdup(optarg); |
| break; |
| } |
| } |
| } |
| |
| |
| int WpaGui::openCtrlConnection(const char *ifname) |
| { |
| char *cfile; |
| int flen; |
| char buf[2048], *pos, *pos2; |
| size_t len; |
| |
| if (ifname) { |
| if (ifname != ctrl_iface) { |
| free(ctrl_iface); |
| ctrl_iface = strdup(ifname); |
| } |
| } else { |
| #ifdef CONFIG_CTRL_IFACE_UDP |
| free(ctrl_iface); |
| ctrl_iface = strdup("udp"); |
| #endif /* CONFIG_CTRL_IFACE_UDP */ |
| #ifdef CONFIG_CTRL_IFACE_UNIX |
| struct dirent *dent; |
| DIR *dir = opendir(ctrl_iface_dir); |
| free(ctrl_iface); |
| ctrl_iface = NULL; |
| if (dir) { |
| while ((dent = readdir(dir))) { |
| #ifdef _DIRENT_HAVE_D_TYPE |
| /* Skip the file if it is not a socket. |
| * Also accept DT_UNKNOWN (0) in case |
| * the C library or underlying file |
| * system does not support d_type. */ |
| if (dent->d_type != DT_SOCK && |
| dent->d_type != DT_UNKNOWN) |
| continue; |
| #endif /* _DIRENT_HAVE_D_TYPE */ |
| |
| if (strcmp(dent->d_name, ".") == 0 || |
| strcmp(dent->d_name, "..") == 0) |
| continue; |
| printf("Selected interface '%s'\n", dent->d_name); |
| ctrl_iface = strdup(dent->d_name); |
| break; |
| } |
| closedir(dir); |
| } |
| #endif /* CONFIG_CTRL_IFACE_UNIX */ |
| #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE |
| struct wpa_ctrl *ctrl; |
| int ret; |
| |
| free(ctrl_iface); |
| ctrl_iface = NULL; |
| |
| ctrl = wpa_ctrl_open(NULL); |
| if (ctrl) { |
| len = sizeof(buf) - 1; |
| ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); |
| if (ret >= 0) { |
| buf[len] = '\0'; |
| pos = strchr(buf, '\n'); |
| if (pos) |
| *pos = '\0'; |
| ctrl_iface = strdup(buf); |
| } |
| wpa_ctrl_close(ctrl); |
| } |
| #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ |
| } |
| |
| if (ctrl_iface == NULL) |
| return -1; |
| |
| #ifdef CONFIG_CTRL_IFACE_UNIX |
| flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; |
| cfile = (char *) malloc(flen); |
| if (cfile == NULL) |
| return -1; |
| snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); |
| #else /* CONFIG_CTRL_IFACE_UNIX */ |
| flen = strlen(ctrl_iface) + 1; |
| cfile = (char *) malloc(flen); |
| if (cfile == NULL) |
| return -1; |
| snprintf(cfile, flen, "%s", ctrl_iface); |
| #endif /* CONFIG_CTRL_IFACE_UNIX */ |
| |
| if (ctrl_conn) { |
| wpa_ctrl_close(ctrl_conn); |
| ctrl_conn = NULL; |
| } |
| |
| if (monitor_conn) { |
| delete msgNotifier; |
| msgNotifier = NULL; |
| wpa_ctrl_detach(monitor_conn); |
| wpa_ctrl_close(monitor_conn); |
| monitor_conn = NULL; |
| } |
| |
| printf("Trying to connect to '%s'\n", cfile); |
| ctrl_conn = wpa_ctrl_open(cfile); |
| if (ctrl_conn == NULL) { |
| free(cfile); |
| return -1; |
| } |
| monitor_conn = wpa_ctrl_open(cfile); |
| free(cfile); |
| if (monitor_conn == NULL) { |
| wpa_ctrl_close(ctrl_conn); |
| return -1; |
| } |
| if (wpa_ctrl_attach(monitor_conn)) { |
| printf("Failed to attach to wpa_supplicant\n"); |
| wpa_ctrl_close(monitor_conn); |
| monitor_conn = NULL; |
| wpa_ctrl_close(ctrl_conn); |
| ctrl_conn = NULL; |
| return -1; |
| } |
| |
| #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) |
| msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), |
| QSocketNotifier::Read, this); |
| connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); |
| #endif |
| |
| adapterSelect->clear(); |
| adapterSelect->insertItem(ctrl_iface); |
| adapterSelect->setCurrentItem(0); |
| |
| len = sizeof(buf) - 1; |
| if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) { |
| buf[len] = '\0'; |
| pos = buf; |
| while (*pos) { |
| pos2 = strchr(pos, '\n'); |
| if (pos2) |
| *pos2 = '\0'; |
| if (strcmp(pos, ctrl_iface) != 0) |
| adapterSelect->insertItem(pos); |
| if (pos2) |
| pos = pos2 + 1; |
| else |
| break; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| static void wpa_gui_msg_cb(char *msg, size_t) |
| { |
| /* This should not happen anymore since two control connections are used. */ |
| printf("missed message: %s\n", msg); |
| } |
| |
| |
| int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) |
| { |
| int ret; |
| |
| if (ctrl_conn == NULL) |
| return -3; |
| ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, |
| wpa_gui_msg_cb); |
| if (ret == -2) { |
| printf("'%s' command timed out.\n", cmd); |
| } else if (ret < 0) { |
| printf("'%s' command failed.\n", cmd); |
| } |
| |
| return ret; |
| } |
| |
| |
| void WpaGui::updateStatus() |
| { |
| char buf[2048], *start, *end, *pos; |
| size_t len; |
| |
| pingsToStatusUpdate = 10; |
| |
| len = sizeof(buf) - 1; |
| if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { |
| textStatus->setText("Could not get status from wpa_supplicant"); |
| textAuthentication->clear(); |
| textEncryption->clear(); |
| textSsid->clear(); |
| textBssid->clear(); |
| textIpAddress->clear(); |
| return; |
| } |
| |
| buf[len] = '\0'; |
| |
| bool auth_updated = false, ssid_updated = false; |
| bool bssid_updated = false, ipaddr_updated = false; |
| bool status_updated = false; |
| char *pairwise_cipher = NULL, *group_cipher = NULL; |
| |
| start = buf; |
| while (*start) { |
| bool last = false; |
| end = strchr(start, '\n'); |
| if (end == NULL) { |
| last = true; |
| end = start; |
| while (end[0] && end[1]) |
| end++; |
| } |
| *end = '\0'; |
| |
| pos = strchr(start, '='); |
| if (pos) { |
| *pos++ = '\0'; |
| if (strcmp(start, "bssid") == 0) { |
| bssid_updated = true; |
| textBssid->setText(pos); |
| } else if (strcmp(start, "ssid") == 0) { |
| ssid_updated = true; |
| textSsid->setText(pos); |
| } else if (strcmp(start, "ip_address") == 0) { |
| ipaddr_updated = true; |
| textIpAddress->setText(pos); |
| } else if (strcmp(start, "wpa_state") == 0) { |
| status_updated = true; |
| textStatus->setText(pos); |
| } else if (strcmp(start, "key_mgmt") == 0) { |
| auth_updated = true; |
| textAuthentication->setText(pos); |
| /* TODO: could add EAP status to this */ |
| } else if (strcmp(start, "pairwise_cipher") == 0) { |
| pairwise_cipher = pos; |
| } else if (strcmp(start, "group_cipher") == 0) { |
| group_cipher = pos; |
| } |
| } |
| |
| if (last) |
| break; |
| start = end + 1; |
| } |
| |
| if (pairwise_cipher || group_cipher) { |
| QString encr; |
| if (pairwise_cipher && group_cipher && |
| strcmp(pairwise_cipher, group_cipher) != 0) { |
| encr.append(pairwise_cipher); |
| encr.append(" + "); |
| encr.append(group_cipher); |
| } else if (pairwise_cipher) { |
| encr.append(pairwise_cipher); |
| } else if (group_cipher) { |
| encr.append(group_cipher); |
| encr.append(" [group key only]"); |
| } else { |
| encr.append("?"); |
| } |
| textEncryption->setText(encr); |
| } else |
| textEncryption->clear(); |
| |
| if (!status_updated) |
| textStatus->clear(); |
| if (!auth_updated) |
| textAuthentication->clear(); |
| if (!ssid_updated) |
| textSsid->clear(); |
| if (!bssid_updated) |
| textBssid->clear(); |
| if (!ipaddr_updated) |
| textIpAddress->clear(); |
| } |
| |
| |
| void WpaGui::updateNetworks() |
| { |
| char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; |
| size_t len; |
| int first_active = -1; |
| bool selected = false; |
| |
| if (!networkMayHaveChanged) |
| return; |
| |
| networkSelect->clear(); |
| |
| if (ctrl_conn == NULL) |
| return; |
| |
| len = sizeof(buf) - 1; |
| if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) |
| return; |
| |
| buf[len] = '\0'; |
| start = strchr(buf, '\n'); |
| if (start == NULL) |
| return; |
| start++; |
| |
| while (*start) { |
| bool last = false; |
| end = strchr(start, '\n'); |
| if (end == NULL) { |
| last = true; |
| end = start; |
| while (end[0] && end[1]) |
| end++; |
| } |
| *end = '\0'; |
| |
| id = start; |
| ssid = strchr(id, '\t'); |
| if (ssid == NULL) |
| break; |
| *ssid++ = '\0'; |
| bssid = strchr(ssid, '\t'); |
| if (bssid == NULL) |
| break; |
| *bssid++ = '\0'; |
| flags = strchr(bssid, '\t'); |
| if (flags == NULL) |
| break; |
| *flags++ = '\0'; |
| |
| QString network(id); |
| network.append(": "); |
| network.append(ssid); |
| networkSelect->insertItem(network); |
| |
| if (strstr(flags, "[CURRENT]")) { |
| networkSelect->setCurrentItem(networkSelect->count() - 1); |
| selected = true; |
| } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL) |
| first_active = networkSelect->count() - 1; |
| |
| if (last) |
| break; |
| start = end + 1; |
| } |
| |
| if (!selected && first_active >= 0) |
| networkSelect->setCurrentItem(first_active); |
| |
| networkMayHaveChanged = false; |
| } |
| |
| |
| void WpaGui::helpIndex() |
| { |
| printf("helpIndex\n"); |
| } |
| |
| |
| void WpaGui::helpContents() |
| { |
| printf("helpContents\n"); |
| } |
| |
| |
| void WpaGui::helpAbout() |
| { |
| QMessageBox::about(this, "wpa_gui for wpa_supplicant", |
| "Copyright (c) 2003-2008,\n" |
| "Jouni Malinen <[email protected]>\n" |
| "and contributors.\n" |
| "\n" |
| "This program is free software. You can\n" |
| "distribute it and/or modify it under the terms of\n" |
| "the GNU General Public License version 2.\n" |
| "\n" |
| "Alternatively, this software may be distributed\n" |
| "under the terms of the BSD license.\n" |
| "\n" |
| "This product includes software developed\n" |
| "by the OpenSSL Project for use in the\n" |
| "OpenSSL Toolkit (http://www.openssl.org/)\n"); |
| } |
| |
| |
| void WpaGui::disconnect() |
| { |
| char reply[10]; |
| size_t reply_len = sizeof(reply); |
| ctrlRequest("DISCONNECT", reply, &reply_len); |
| } |
| |
| |
| void WpaGui::scan() |
| { |
| if (scanres) { |
| scanres->close(); |
| delete scanres; |
| } |
| |
| scanres = new ScanResults(); |
| if (scanres == NULL) |
| return; |
| scanres->setWpaGui(this); |
| scanres->show(); |
| scanres->exec(); |
| } |
| |
| |
| void WpaGui::eventHistory() |
| { |
| if (eh) { |
| eh->close(); |
| delete eh; |
| } |
| |
| eh = new EventHistory(); |
| if (eh == NULL) |
| return; |
| eh->addEvents(msgs); |
| eh->show(); |
| eh->exec(); |
| } |
| |
| |
| void WpaGui::ping() |
| { |
| char buf[10]; |
| size_t len; |
| |
| #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE |
| /* |
| * QSocketNotifier cannot be used with Windows named pipes, so use a timer |
| * to check for received messages for now. This could be optimized be doing |
| * something specific to named pipes or Windows events, but it is not clear |
| * what would be the best way of doing that in Qt. |
| */ |
| receiveMsgs(); |
| #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ |
| |
| if (scanres && !scanres->isVisible()) { |
| delete scanres; |
| scanres = NULL; |
| } |
| |
| if (eh && !eh->isVisible()) { |
| delete eh; |
| eh = NULL; |
| } |
| |
| if (udr && !udr->isVisible()) { |
| delete udr; |
| udr = NULL; |
| } |
| |
| len = sizeof(buf) - 1; |
| if (ctrlRequest("PING", buf, &len) < 0) { |
| printf("PING failed - trying to reconnect\n"); |
| if (openCtrlConnection(ctrl_iface) >= 0) { |
| printf("Reconnected successfully\n"); |
| pingsToStatusUpdate = 0; |
| } |
| } |
| |
| pingsToStatusUpdate--; |
| if (pingsToStatusUpdate <= 0) { |
| updateStatus(); |
| updateNetworks(); |
| } |
| } |
| |
| |
| static int str_match(const char *a, const char *b) |
| { |
| return strncmp(a, b, strlen(b)) == 0; |
| } |
| |
| |
| void WpaGui::processMsg(char *msg) |
| { |
| char *pos = msg, *pos2; |
| int priority = 2; |
| |
| if (*pos == '<') { |
| /* skip priority */ |
| pos++; |
| priority = atoi(pos); |
| pos = strchr(pos, '>'); |
| if (pos) |
| pos++; |
| else |
| pos = msg; |
| } |
| |
| WpaMsg wm(pos, priority); |
| if (eh) |
| eh->addEvent(wm); |
| msgs.append(wm); |
| while (msgs.count() > 100) |
| msgs.pop_front(); |
| |
| /* Update last message with truncated version of the event */ |
| if (strncmp(pos, "CTRL-", 5) == 0) { |
| pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); |
| if (pos2) |
| pos2++; |
| else |
| pos2 = pos; |
| } else |
| pos2 = pos; |
| QString lastmsg = pos2; |
| lastmsg.truncate(40); |
| textLastMessage->setText(lastmsg); |
| |
| pingsToStatusUpdate = 0; |
| networkMayHaveChanged = true; |
| |
| if (str_match(pos, WPA_CTRL_REQ)) |
| processCtrlReq(pos + strlen(WPA_CTRL_REQ)); |
| } |
| |
| |
| void WpaGui::processCtrlReq(const char *req) |
| { |
| if (udr) { |
| udr->close(); |
| delete udr; |
| } |
| udr = new UserDataRequest(); |
| if (udr == NULL) |
| return; |
| if (udr->setParams(this, req) < 0) { |
| delete udr; |
| udr = NULL; |
| return; |
| } |
| udr->show(); |
| udr->exec(); |
| } |
| |
| |
| void WpaGui::receiveMsgs() |
| { |
| char buf[256]; |
| size_t len; |
| |
| while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { |
| len = sizeof(buf) - 1; |
| if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { |
| buf[len] = '\0'; |
| processMsg(buf); |
| } |
| } |
| } |
| |
| |
| void WpaGui::connectB() |
| { |
| char reply[10]; |
| size_t reply_len = sizeof(reply); |
| ctrlRequest("REASSOCIATE", reply, &reply_len); |
| } |
| |
| |
| void WpaGui::selectNetwork( const QString &sel ) |
| { |
| QString cmd(sel); |
| char reply[10]; |
| size_t reply_len = sizeof(reply); |
| |
| int pos = cmd.find(':'); |
| if (pos < 0) { |
| printf("Invalid selectNetwork '%s'\n", cmd.ascii()); |
| return; |
| } |
| cmd.truncate(pos); |
| cmd.prepend("SELECT_NETWORK "); |
| ctrlRequest(cmd.ascii(), reply, &reply_len); |
| } |
| |
| |
| void WpaGui::editNetwork() |
| { |
| QString sel(networkSelect->currentText()); |
| int pos = sel.find(':'); |
| if (pos < 0) { |
| printf("Invalid selectNetwork '%s'\n", sel.ascii()); |
| return; |
| } |
| sel.truncate(pos); |
| |
| NetworkConfig *nc = new NetworkConfig(); |
| if (nc == NULL) |
| return; |
| nc->setWpaGui(this); |
| |
| nc->paramsFromConfig(sel.toInt()); |
| nc->show(); |
| nc->exec(); |
| } |
| |
| |
| void WpaGui::triggerUpdate() |
| { |
| updateStatus(); |
| networkMayHaveChanged = true; |
| updateNetworks(); |
| } |
| |
| |
| void WpaGui::addNetwork() |
| { |
| NetworkConfig *nc = new NetworkConfig(); |
| if (nc == NULL) |
| return; |
| nc->setWpaGui(this); |
| nc->newNetwork(); |
| nc->show(); |
| nc->exec(); |
| } |
| |
| |
| void WpaGui::selectAdapter( const QString & sel ) |
| { |
| if (openCtrlConnection(sel.ascii()) < 0) |
| printf("Failed to open control connection to wpa_supplicant.\n"); |
| updateStatus(); |
| updateNetworks(); |
| } |