2 * wpa_gui - WpaGui class
3 * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
16 /* Need to get getopt() */
21 #include <QMessageBox>
26 #include "userdatarequest.h"
27 #include "networkconfig.h"
29 WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
36 connect(helpIndexAction, SIGNAL(activated()), this, SLOT(helpIndex()));
37 connect(helpContentsAction, SIGNAL(activated()), this,
38 SLOT(helpContents()));
39 connect(helpAboutAction, SIGNAL(activated()), this, SLOT(helpAbout()));
40 connect(fileExitAction, SIGNAL(activated()), this, SLOT(close()));
41 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
42 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
43 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
44 connect(fileEventHistoryAction, SIGNAL(activated()), this,
45 SLOT(eventHistory()));
46 connect(networkSelect, SIGNAL(activated(const QString&)), this,
47 SLOT(selectNetwork(const QString&)));
48 connect(fileEdit_networkAction, SIGNAL(activated()), this,
50 connect(fileAdd_NetworkAction, SIGNAL(activated()), this,
52 connect(adapterSelect, SIGNAL(activated(const QString&)), this,
53 SLOT(selectAdapter(const QString&)));
62 ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
66 textStatus->setText("connecting to wpa_supplicant");
67 timer = new QTimer(this);
68 connect(timer, SIGNAL(timeout()), SLOT(ping()));
69 timer->start(1000, FALSE);
71 if (openCtrlConnection(ctrl_iface) < 0) {
72 printf("Failed to open control connection to "
77 networkMayHaveChanged = true;
87 wpa_ctrl_detach(monitor_conn);
88 wpa_ctrl_close(monitor_conn);
92 wpa_ctrl_close(ctrl_conn);
117 free(ctrl_iface_dir);
118 ctrl_iface_dir = NULL;
122 void WpaGui::languageChange()
128 void WpaGui::parse_argv()
132 c = getopt(qApp->argc(), qApp->argv(), "i:p:");
138 ctrl_iface = strdup(optarg);
141 free(ctrl_iface_dir);
142 ctrl_iface_dir = strdup(optarg);
149 int WpaGui::openCtrlConnection(const char *ifname)
153 char buf[2048], *pos, *pos2;
157 if (ifname != ctrl_iface) {
159 ctrl_iface = strdup(ifname);
162 #ifdef CONFIG_CTRL_IFACE_UDP
164 ctrl_iface = strdup("udp");
165 #endif /* CONFIG_CTRL_IFACE_UDP */
166 #ifdef CONFIG_CTRL_IFACE_UNIX
168 DIR *dir = opendir(ctrl_iface_dir);
172 while ((dent = readdir(dir))) {
173 #ifdef _DIRENT_HAVE_D_TYPE
174 /* Skip the file if it is not a socket.
175 * Also accept DT_UNKNOWN (0) in case
176 * the C library or underlying file
177 * system does not support d_type. */
178 if (dent->d_type != DT_SOCK &&
179 dent->d_type != DT_UNKNOWN)
181 #endif /* _DIRENT_HAVE_D_TYPE */
183 if (strcmp(dent->d_name, ".") == 0 ||
184 strcmp(dent->d_name, "..") == 0)
186 printf("Selected interface '%s'\n",
188 ctrl_iface = strdup(dent->d_name);
193 #endif /* CONFIG_CTRL_IFACE_UNIX */
194 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
195 struct wpa_ctrl *ctrl;
201 ctrl = wpa_ctrl_open(NULL);
203 len = sizeof(buf) - 1;
204 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
208 pos = strchr(buf, '\n');
211 ctrl_iface = strdup(buf);
213 wpa_ctrl_close(ctrl);
215 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
218 if (ctrl_iface == NULL)
221 #ifdef CONFIG_CTRL_IFACE_UNIX
222 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
223 cfile = (char *) malloc(flen);
226 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
227 #else /* CONFIG_CTRL_IFACE_UNIX */
228 flen = strlen(ctrl_iface) + 1;
229 cfile = (char *) malloc(flen);
232 snprintf(cfile, flen, "%s", ctrl_iface);
233 #endif /* CONFIG_CTRL_IFACE_UNIX */
236 wpa_ctrl_close(ctrl_conn);
243 wpa_ctrl_detach(monitor_conn);
244 wpa_ctrl_close(monitor_conn);
248 printf("Trying to connect to '%s'\n", cfile);
249 ctrl_conn = wpa_ctrl_open(cfile);
250 if (ctrl_conn == NULL) {
254 monitor_conn = wpa_ctrl_open(cfile);
256 if (monitor_conn == NULL) {
257 wpa_ctrl_close(ctrl_conn);
260 if (wpa_ctrl_attach(monitor_conn)) {
261 printf("Failed to attach to wpa_supplicant\n");
262 wpa_ctrl_close(monitor_conn);
264 wpa_ctrl_close(ctrl_conn);
269 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
270 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
271 QSocketNotifier::Read, this);
272 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
275 adapterSelect->clear();
276 adapterSelect->insertItem(ctrl_iface);
277 adapterSelect->setCurrentItem(0);
279 len = sizeof(buf) - 1;
280 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
285 pos2 = strchr(pos, '\n');
288 if (strcmp(pos, ctrl_iface) != 0)
289 adapterSelect->insertItem(pos);
301 static void wpa_gui_msg_cb(char *msg, size_t)
303 /* This should not happen anymore since two control connections are
305 printf("missed message: %s\n", msg);
309 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
313 if (ctrl_conn == NULL)
315 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
318 printf("'%s' command timed out.\n", cmd);
320 printf("'%s' command failed.\n", cmd);
326 void WpaGui::updateStatus()
328 char buf[2048], *start, *end, *pos;
331 pingsToStatusUpdate = 10;
333 len = sizeof(buf) - 1;
334 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
335 textStatus->setText("Could not get status from "
337 textAuthentication->clear();
338 textEncryption->clear();
341 textIpAddress->clear();
347 bool auth_updated = false, ssid_updated = false;
348 bool bssid_updated = false, ipaddr_updated = false;
349 bool status_updated = false;
350 char *pairwise_cipher = NULL, *group_cipher = NULL;
355 end = strchr(start, '\n');
359 while (end[0] && end[1])
364 pos = strchr(start, '=');
367 if (strcmp(start, "bssid") == 0) {
368 bssid_updated = true;
369 textBssid->setText(pos);
370 } else if (strcmp(start, "ssid") == 0) {
372 textSsid->setText(pos);
373 } else if (strcmp(start, "ip_address") == 0) {
374 ipaddr_updated = true;
375 textIpAddress->setText(pos);
376 } else if (strcmp(start, "wpa_state") == 0) {
377 status_updated = true;
378 textStatus->setText(pos);
379 } else if (strcmp(start, "key_mgmt") == 0) {
381 textAuthentication->setText(pos);
382 /* TODO: could add EAP status to this */
383 } else if (strcmp(start, "pairwise_cipher") == 0) {
384 pairwise_cipher = pos;
385 } else if (strcmp(start, "group_cipher") == 0) {
395 if (pairwise_cipher || group_cipher) {
397 if (pairwise_cipher && group_cipher &&
398 strcmp(pairwise_cipher, group_cipher) != 0) {
399 encr.append(pairwise_cipher);
401 encr.append(group_cipher);
402 } else if (pairwise_cipher) {
403 encr.append(pairwise_cipher);
404 } else if (group_cipher) {
405 encr.append(group_cipher);
406 encr.append(" [group key only]");
410 textEncryption->setText(encr);
412 textEncryption->clear();
417 textAuthentication->clear();
423 textIpAddress->clear();
427 void WpaGui::updateNetworks()
429 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
431 int first_active = -1;
432 bool selected = false;
434 if (!networkMayHaveChanged)
437 networkSelect->clear();
439 if (ctrl_conn == NULL)
442 len = sizeof(buf) - 1;
443 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
447 start = strchr(buf, '\n');
454 end = strchr(start, '\n');
458 while (end[0] && end[1])
464 ssid = strchr(id, '\t');
468 bssid = strchr(ssid, '\t');
472 flags = strchr(bssid, '\t');
478 network.append(": ");
479 network.append(ssid);
480 networkSelect->insertItem(network);
482 if (strstr(flags, "[CURRENT]")) {
483 networkSelect->setCurrentItem(networkSelect->count() -
486 } else if (first_active < 0 &&
487 strstr(flags, "[DISABLED]") == NULL)
488 first_active = networkSelect->count() - 1;
495 if (!selected && first_active >= 0)
496 networkSelect->setCurrentItem(first_active);
498 networkMayHaveChanged = false;
502 void WpaGui::helpIndex()
504 printf("helpIndex\n");
508 void WpaGui::helpContents()
510 printf("helpContents\n");
514 void WpaGui::helpAbout()
516 QMessageBox::about(this, "wpa_gui for wpa_supplicant",
517 "Copyright (c) 2003-2008,\n"
518 "Jouni Malinen <j@w1.fi>\n"
519 "and contributors.\n"
521 "This program is free software. You can\n"
522 "distribute it and/or modify it under the terms "
524 "the GNU General Public License version 2.\n"
526 "Alternatively, this software may be distributed\n"
527 "under the terms of the BSD license.\n"
529 "This product includes software developed\n"
530 "by the OpenSSL Project for use in the\n"
531 "OpenSSL Toolkit (http://www.openssl.org/)\n");
535 void WpaGui::disconnect()
538 size_t reply_len = sizeof(reply);
539 ctrlRequest("DISCONNECT", reply, &reply_len);
550 scanres = new ScanResults();
553 scanres->setWpaGui(this);
559 void WpaGui::eventHistory()
566 eh = new EventHistory();
580 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
582 * QSocketNotifier cannot be used with Windows named pipes, so use a
583 * timer to check for received messages for now. This could be
584 * optimized be doing something specific to named pipes or Windows
585 * events, but it is not clear what would be the best way of doing that
589 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
591 if (scanres && !scanres->isVisible()) {
596 if (eh && !eh->isVisible()) {
601 if (udr && !udr->isVisible()) {
606 len = sizeof(buf) - 1;
607 if (ctrlRequest("PING", buf, &len) < 0) {
608 printf("PING failed - trying to reconnect\n");
609 if (openCtrlConnection(ctrl_iface) >= 0) {
610 printf("Reconnected successfully\n");
611 pingsToStatusUpdate = 0;
615 pingsToStatusUpdate--;
616 if (pingsToStatusUpdate <= 0) {
623 static int str_match(const char *a, const char *b)
625 return strncmp(a, b, strlen(b)) == 0;
629 void WpaGui::processMsg(char *msg)
631 char *pos = msg, *pos2;
637 priority = atoi(pos);
638 pos = strchr(pos, '>');
645 WpaMsg wm(pos, priority);
649 while (msgs.count() > 100)
652 /* Update last message with truncated version of the event */
653 if (strncmp(pos, "CTRL-", 5) == 0) {
654 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
661 QString lastmsg = pos2;
662 lastmsg.truncate(40);
663 textLastMessage->setText(lastmsg);
665 pingsToStatusUpdate = 0;
666 networkMayHaveChanged = true;
668 if (str_match(pos, WPA_CTRL_REQ))
669 processCtrlReq(pos + strlen(WPA_CTRL_REQ));
673 void WpaGui::processCtrlReq(const char *req)
679 udr = new UserDataRequest();
682 if (udr->setParams(this, req) < 0) {
692 void WpaGui::receiveMsgs()
697 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
698 len = sizeof(buf) - 1;
699 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
707 void WpaGui::connectB()
710 size_t reply_len = sizeof(reply);
711 ctrlRequest("REASSOCIATE", reply, &reply_len);
715 void WpaGui::selectNetwork( const QString &sel )
719 size_t reply_len = sizeof(reply);
721 int pos = cmd.find(':');
723 printf("Invalid selectNetwork '%s'\n", cmd.ascii());
727 cmd.prepend("SELECT_NETWORK ");
728 ctrlRequest(cmd.ascii(), reply, &reply_len);
732 void WpaGui::editNetwork()
734 QString sel(networkSelect->currentText());
735 int pos = sel.find(':');
737 printf("Invalid selectNetwork '%s'\n", sel.ascii());
742 NetworkConfig *nc = new NetworkConfig();
747 nc->paramsFromConfig(sel.toInt());
753 void WpaGui::triggerUpdate()
756 networkMayHaveChanged = true;
761 void WpaGui::addNetwork()
763 NetworkConfig *nc = new NetworkConfig();
773 void WpaGui::selectAdapter( const QString & sel )
775 if (openCtrlConnection(sel.ascii()) < 0)
776 printf("Failed to open control connection to "
777 "wpa_supplicant.\n");