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() */
20 #include <QMessageBox>
25 #include "userdatarequest.h"
26 #include "networkconfig.h"
28 WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
35 connect(helpIndexAction, SIGNAL(activated()), this, SLOT(helpIndex()));
36 connect(helpContentsAction, SIGNAL(activated()), this,
37 SLOT(helpContents()));
38 connect(helpAboutAction, SIGNAL(activated()), this, SLOT(helpAbout()));
39 connect(fileExitAction, SIGNAL(activated()), this, SLOT(close()));
40 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
41 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
42 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
43 connect(fileEventHistoryAction, SIGNAL(activated()), this,
44 SLOT(eventHistory()));
45 connect(networkSelect, SIGNAL(activated(const QString&)), this,
46 SLOT(selectNetwork(const QString&)));
47 connect(fileEdit_networkAction, SIGNAL(activated()), this,
49 connect(fileAdd_NetworkAction, SIGNAL(activated()), this,
51 connect(adapterSelect, SIGNAL(activated(const QString&)), this,
52 SLOT(selectAdapter(const QString&)));
61 ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
65 textStatus->setText("connecting to wpa_supplicant");
66 timer = new QTimer(this);
67 connect(timer, SIGNAL(timeout()), SLOT(ping()));
68 timer->start(1000, FALSE);
70 if (openCtrlConnection(ctrl_iface) < 0) {
71 printf("Failed to open control connection to "
76 networkMayHaveChanged = true;
86 wpa_ctrl_detach(monitor_conn);
87 wpa_ctrl_close(monitor_conn);
91 wpa_ctrl_close(ctrl_conn);
116 free(ctrl_iface_dir);
117 ctrl_iface_dir = NULL;
121 void WpaGui::languageChange()
127 void WpaGui::parse_argv()
131 c = getopt(qApp->argc(), qApp->argv(), "i:p:");
137 ctrl_iface = strdup(optarg);
140 free(ctrl_iface_dir);
141 ctrl_iface_dir = strdup(optarg);
148 int WpaGui::openCtrlConnection(const char *ifname)
152 char buf[2048], *pos, *pos2;
156 if (ifname != ctrl_iface) {
158 ctrl_iface = strdup(ifname);
161 #ifdef CONFIG_CTRL_IFACE_UDP
163 ctrl_iface = strdup("udp");
164 #endif /* CONFIG_CTRL_IFACE_UDP */
165 #ifdef CONFIG_CTRL_IFACE_UNIX
167 DIR *dir = opendir(ctrl_iface_dir);
171 while ((dent = readdir(dir))) {
172 #ifdef _DIRENT_HAVE_D_TYPE
173 /* Skip the file if it is not a socket.
174 * Also accept DT_UNKNOWN (0) in case
175 * the C library or underlying file
176 * system does not support d_type. */
177 if (dent->d_type != DT_SOCK &&
178 dent->d_type != DT_UNKNOWN)
180 #endif /* _DIRENT_HAVE_D_TYPE */
182 if (strcmp(dent->d_name, ".") == 0 ||
183 strcmp(dent->d_name, "..") == 0)
185 printf("Selected interface '%s'\n",
187 ctrl_iface = strdup(dent->d_name);
192 #endif /* CONFIG_CTRL_IFACE_UNIX */
193 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
194 struct wpa_ctrl *ctrl;
200 ctrl = wpa_ctrl_open(NULL);
202 len = sizeof(buf) - 1;
203 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
207 pos = strchr(buf, '\n');
210 ctrl_iface = strdup(buf);
212 wpa_ctrl_close(ctrl);
214 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
217 if (ctrl_iface == NULL)
220 #ifdef CONFIG_CTRL_IFACE_UNIX
221 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
222 cfile = (char *) malloc(flen);
225 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
226 #else /* CONFIG_CTRL_IFACE_UNIX */
227 flen = strlen(ctrl_iface) + 1;
228 cfile = (char *) malloc(flen);
231 snprintf(cfile, flen, "%s", ctrl_iface);
232 #endif /* CONFIG_CTRL_IFACE_UNIX */
235 wpa_ctrl_close(ctrl_conn);
242 wpa_ctrl_detach(monitor_conn);
243 wpa_ctrl_close(monitor_conn);
247 printf("Trying to connect to '%s'\n", cfile);
248 ctrl_conn = wpa_ctrl_open(cfile);
249 if (ctrl_conn == NULL) {
253 monitor_conn = wpa_ctrl_open(cfile);
255 if (monitor_conn == NULL) {
256 wpa_ctrl_close(ctrl_conn);
259 if (wpa_ctrl_attach(monitor_conn)) {
260 printf("Failed to attach to wpa_supplicant\n");
261 wpa_ctrl_close(monitor_conn);
263 wpa_ctrl_close(ctrl_conn);
268 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
269 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
270 QSocketNotifier::Read, this);
271 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
274 adapterSelect->clear();
275 adapterSelect->insertItem(ctrl_iface);
276 adapterSelect->setCurrentItem(0);
278 len = sizeof(buf) - 1;
279 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
284 pos2 = strchr(pos, '\n');
287 if (strcmp(pos, ctrl_iface) != 0)
288 adapterSelect->insertItem(pos);
300 static void wpa_gui_msg_cb(char *msg, size_t)
302 /* This should not happen anymore since two control connections are
304 printf("missed message: %s\n", msg);
308 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
312 if (ctrl_conn == NULL)
314 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
317 printf("'%s' command timed out.\n", cmd);
319 printf("'%s' command failed.\n", cmd);
325 void WpaGui::updateStatus()
327 char buf[2048], *start, *end, *pos;
330 pingsToStatusUpdate = 10;
332 len = sizeof(buf) - 1;
333 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
334 textStatus->setText("Could not get status from "
336 textAuthentication->clear();
337 textEncryption->clear();
340 textIpAddress->clear();
346 bool auth_updated = false, ssid_updated = false;
347 bool bssid_updated = false, ipaddr_updated = false;
348 bool status_updated = false;
349 char *pairwise_cipher = NULL, *group_cipher = NULL;
354 end = strchr(start, '\n');
358 while (end[0] && end[1])
363 pos = strchr(start, '=');
366 if (strcmp(start, "bssid") == 0) {
367 bssid_updated = true;
368 textBssid->setText(pos);
369 } else if (strcmp(start, "ssid") == 0) {
371 textSsid->setText(pos);
372 } else if (strcmp(start, "ip_address") == 0) {
373 ipaddr_updated = true;
374 textIpAddress->setText(pos);
375 } else if (strcmp(start, "wpa_state") == 0) {
376 status_updated = true;
377 textStatus->setText(pos);
378 } else if (strcmp(start, "key_mgmt") == 0) {
380 textAuthentication->setText(pos);
381 /* TODO: could add EAP status to this */
382 } else if (strcmp(start, "pairwise_cipher") == 0) {
383 pairwise_cipher = pos;
384 } else if (strcmp(start, "group_cipher") == 0) {
394 if (pairwise_cipher || group_cipher) {
396 if (pairwise_cipher && group_cipher &&
397 strcmp(pairwise_cipher, group_cipher) != 0) {
398 encr.append(pairwise_cipher);
400 encr.append(group_cipher);
401 } else if (pairwise_cipher) {
402 encr.append(pairwise_cipher);
403 } else if (group_cipher) {
404 encr.append(group_cipher);
405 encr.append(" [group key only]");
409 textEncryption->setText(encr);
411 textEncryption->clear();
416 textAuthentication->clear();
422 textIpAddress->clear();
426 void WpaGui::updateNetworks()
428 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
430 int first_active = -1;
431 bool selected = false;
433 if (!networkMayHaveChanged)
436 networkSelect->clear();
438 if (ctrl_conn == NULL)
441 len = sizeof(buf) - 1;
442 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
446 start = strchr(buf, '\n');
453 end = strchr(start, '\n');
457 while (end[0] && end[1])
463 ssid = strchr(id, '\t');
467 bssid = strchr(ssid, '\t');
471 flags = strchr(bssid, '\t');
477 network.append(": ");
478 network.append(ssid);
479 networkSelect->insertItem(network);
481 if (strstr(flags, "[CURRENT]")) {
482 networkSelect->setCurrentItem(networkSelect->count() -
485 } else if (first_active < 0 &&
486 strstr(flags, "[DISABLED]") == NULL)
487 first_active = networkSelect->count() - 1;
494 if (!selected && first_active >= 0)
495 networkSelect->setCurrentItem(first_active);
497 networkMayHaveChanged = false;
501 void WpaGui::helpIndex()
503 printf("helpIndex\n");
507 void WpaGui::helpContents()
509 printf("helpContents\n");
513 void WpaGui::helpAbout()
515 QMessageBox::about(this, "wpa_gui for wpa_supplicant",
516 "Copyright (c) 2003-2008,\n"
517 "Jouni Malinen <j@w1.fi>\n"
518 "and contributors.\n"
520 "This program is free software. You can\n"
521 "distribute it and/or modify it under the terms "
523 "the GNU General Public License version 2.\n"
525 "Alternatively, this software may be distributed\n"
526 "under the terms of the BSD license.\n"
528 "This product includes software developed\n"
529 "by the OpenSSL Project for use in the\n"
530 "OpenSSL Toolkit (http://www.openssl.org/)\n");
534 void WpaGui::disconnect()
537 size_t reply_len = sizeof(reply);
538 ctrlRequest("DISCONNECT", reply, &reply_len);
549 scanres = new ScanResults();
552 scanres->setWpaGui(this);
558 void WpaGui::eventHistory()
565 eh = new EventHistory();
579 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
581 * QSocketNotifier cannot be used with Windows named pipes, so use a
582 * timer to check for received messages for now. This could be
583 * optimized be doing something specific to named pipes or Windows
584 * events, but it is not clear what would be the best way of doing that
588 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
590 if (scanres && !scanres->isVisible()) {
595 if (eh && !eh->isVisible()) {
600 if (udr && !udr->isVisible()) {
605 len = sizeof(buf) - 1;
606 if (ctrlRequest("PING", buf, &len) < 0) {
607 printf("PING failed - trying to reconnect\n");
608 if (openCtrlConnection(ctrl_iface) >= 0) {
609 printf("Reconnected successfully\n");
610 pingsToStatusUpdate = 0;
614 pingsToStatusUpdate--;
615 if (pingsToStatusUpdate <= 0) {
622 static int str_match(const char *a, const char *b)
624 return strncmp(a, b, strlen(b)) == 0;
628 void WpaGui::processMsg(char *msg)
630 char *pos = msg, *pos2;
636 priority = atoi(pos);
637 pos = strchr(pos, '>');
644 WpaMsg wm(pos, priority);
648 while (msgs.count() > 100)
651 /* Update last message with truncated version of the event */
652 if (strncmp(pos, "CTRL-", 5) == 0) {
653 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
660 QString lastmsg = pos2;
661 lastmsg.truncate(40);
662 textLastMessage->setText(lastmsg);
664 pingsToStatusUpdate = 0;
665 networkMayHaveChanged = true;
667 if (str_match(pos, WPA_CTRL_REQ))
668 processCtrlReq(pos + strlen(WPA_CTRL_REQ));
672 void WpaGui::processCtrlReq(const char *req)
678 udr = new UserDataRequest();
681 if (udr->setParams(this, req) < 0) {
691 void WpaGui::receiveMsgs()
696 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
697 len = sizeof(buf) - 1;
698 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
706 void WpaGui::connectB()
709 size_t reply_len = sizeof(reply);
710 ctrlRequest("REASSOCIATE", reply, &reply_len);
714 void WpaGui::selectNetwork( const QString &sel )
718 size_t reply_len = sizeof(reply);
720 int pos = cmd.find(':');
722 printf("Invalid selectNetwork '%s'\n", cmd.ascii());
726 cmd.prepend("SELECT_NETWORK ");
727 ctrlRequest(cmd.ascii(), reply, &reply_len);
731 void WpaGui::editNetwork()
733 QString sel(networkSelect->currentText());
734 int pos = sel.find(':');
736 printf("Invalid selectNetwork '%s'\n", sel.ascii());
741 NetworkConfig *nc = new NetworkConfig();
746 nc->paramsFromConfig(sel.toInt());
752 void WpaGui::triggerUpdate()
755 networkMayHaveChanged = true;
760 void WpaGui::addNetwork()
762 NetworkConfig *nc = new NetworkConfig();
772 void WpaGui::selectAdapter( const QString & sel )
774 if (openCtrlConnection(sel.ascii()) < 0)
775 printf("Failed to open control connection to "
776 "wpa_supplicant.\n");