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>
21 #include <QCloseEvent>
26 #include "userdatarequest.h"
27 #include "networkconfig.h"
29 WpaGui::WpaGui(QWidget
*parent
, const char *, Qt::WFlags
)
36 connect(fileEventHistoryAction
, SIGNAL(triggered()), this,
37 SLOT(eventHistory()));
38 connect(fileSaveConfigAction
, SIGNAL(triggered()), this,
40 connect(fileExitAction
, SIGNAL(triggered()), this, SLOT(close()));
41 connect(networkAddAction
, SIGNAL(triggered()), this,
43 connect(networkEditAction
, SIGNAL(triggered()), this,
44 SLOT(editSelectedNetwork()));
45 connect(networkRemoveAction
, SIGNAL(triggered()), this,
46 SLOT(removeSelectedNetwork()));
47 connect(networkEnableAllAction
, SIGNAL(triggered()), this,
48 SLOT(enableAllNetworks()));
49 connect(networkDisableAllAction
, SIGNAL(triggered()), this,
50 SLOT(disableAllNetworks()));
51 connect(networkRemoveAllAction
, SIGNAL(triggered()), this,
52 SLOT(removeAllNetworks()));
53 connect(helpIndexAction
, SIGNAL(triggered()), this, SLOT(helpIndex()));
54 connect(helpContentsAction
, SIGNAL(triggered()), this,
55 SLOT(helpContents()));
56 connect(helpAboutAction
, SIGNAL(triggered()), this, SLOT(helpAbout()));
57 connect(disconnectButton
, SIGNAL(clicked()), this, SLOT(disconnect()));
58 connect(scanButton
, SIGNAL(clicked()), this, SLOT(scan()));
59 connect(connectButton
, SIGNAL(clicked()), this, SLOT(connectB()));
60 connect(adapterSelect
, SIGNAL(activated(const QString
&)), this,
61 SLOT(selectAdapter(const QString
&)));
62 connect(networkSelect
, SIGNAL(activated(const QString
&)), this,
63 SLOT(selectNetwork(const QString
&)));
64 connect(addNetworkButton
, SIGNAL(clicked()), this, SLOT(addNetwork()));
65 connect(editNetworkButton
, SIGNAL(clicked()), this,
66 SLOT(editListedNetwork()));
67 connect(removeNetworkButton
, SIGNAL(clicked()), this,
68 SLOT(removeListedNetwork()));
69 connect(networkList
, SIGNAL(itemSelectionChanged()), this,
70 SLOT(updateNetworkDisabledStatus()));
71 connect(enableRadioButton
, SIGNAL(toggled(bool)), this,
72 SLOT(enableListedNetwork(bool)));
73 connect(disableRadioButton
, SIGNAL(toggled(bool)), this,
74 SLOT(disableListedNetwork(bool)));
75 connect(scanNetworkButton
, SIGNAL(clicked()), this, SLOT(scan()));
76 connect(networkList
, SIGNAL(itemDoubleClicked(QListWidgetItem
*)),
77 this, SLOT(editListedNetwork()));
86 ctrl_iface_dir
= strdup("/var/run/wpa_supplicant");
90 textStatus
->setText("connecting to wpa_supplicant");
91 timer
= new QTimer(this);
92 connect(timer
, SIGNAL(timeout()), SLOT(ping()));
93 timer
->setSingleShot(FALSE
);
96 if (openCtrlConnection(ctrl_iface
) < 0) {
97 printf("Failed to open control connection to "
102 networkMayHaveChanged
= true;
112 wpa_ctrl_detach(monitor_conn
);
113 wpa_ctrl_close(monitor_conn
);
117 wpa_ctrl_close(ctrl_conn
);
142 free(ctrl_iface_dir
);
143 ctrl_iface_dir
= NULL
;
147 void WpaGui::languageChange()
153 void WpaGui::parse_argv()
157 c
= getopt(qApp
->argc(), qApp
->argv(), "i:p:");
163 ctrl_iface
= strdup(optarg
);
166 free(ctrl_iface_dir
);
167 ctrl_iface_dir
= strdup(optarg
);
174 int WpaGui::openCtrlConnection(const char *ifname
)
178 char buf
[2048], *pos
, *pos2
;
182 if (ifname
!= ctrl_iface
) {
184 ctrl_iface
= strdup(ifname
);
187 #ifdef CONFIG_CTRL_IFACE_UDP
189 ctrl_iface
= strdup("udp");
190 #endif /* CONFIG_CTRL_IFACE_UDP */
191 #ifdef CONFIG_CTRL_IFACE_UNIX
193 DIR *dir
= opendir(ctrl_iface_dir
);
197 while ((dent
= readdir(dir
))) {
198 #ifdef _DIRENT_HAVE_D_TYPE
199 /* Skip the file if it is not a socket.
200 * Also accept DT_UNKNOWN (0) in case
201 * the C library or underlying file
202 * system does not support d_type. */
203 if (dent
->d_type
!= DT_SOCK
&&
204 dent
->d_type
!= DT_UNKNOWN
)
206 #endif /* _DIRENT_HAVE_D_TYPE */
208 if (strcmp(dent
->d_name
, ".") == 0 ||
209 strcmp(dent
->d_name
, "..") == 0)
211 printf("Selected interface '%s'\n",
213 ctrl_iface
= strdup(dent
->d_name
);
218 #endif /* CONFIG_CTRL_IFACE_UNIX */
219 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
220 struct wpa_ctrl
*ctrl
;
226 ctrl
= wpa_ctrl_open(NULL
);
228 len
= sizeof(buf
) - 1;
229 ret
= wpa_ctrl_request(ctrl
, "INTERFACES", 10, buf
,
233 pos
= strchr(buf
, '\n');
236 ctrl_iface
= strdup(buf
);
238 wpa_ctrl_close(ctrl
);
240 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
243 if (ctrl_iface
== NULL
)
246 #ifdef CONFIG_CTRL_IFACE_UNIX
247 flen
= strlen(ctrl_iface_dir
) + strlen(ctrl_iface
) + 2;
248 cfile
= (char *) malloc(flen
);
251 snprintf(cfile
, flen
, "%s/%s", ctrl_iface_dir
, ctrl_iface
);
252 #else /* CONFIG_CTRL_IFACE_UNIX */
253 flen
= strlen(ctrl_iface
) + 1;
254 cfile
= (char *) malloc(flen
);
257 snprintf(cfile
, flen
, "%s", ctrl_iface
);
258 #endif /* CONFIG_CTRL_IFACE_UNIX */
261 wpa_ctrl_close(ctrl_conn
);
268 wpa_ctrl_detach(monitor_conn
);
269 wpa_ctrl_close(monitor_conn
);
273 printf("Trying to connect to '%s'\n", cfile
);
274 ctrl_conn
= wpa_ctrl_open(cfile
);
275 if (ctrl_conn
== NULL
) {
279 monitor_conn
= wpa_ctrl_open(cfile
);
281 if (monitor_conn
== NULL
) {
282 wpa_ctrl_close(ctrl_conn
);
285 if (wpa_ctrl_attach(monitor_conn
)) {
286 printf("Failed to attach to wpa_supplicant\n");
287 wpa_ctrl_close(monitor_conn
);
289 wpa_ctrl_close(ctrl_conn
);
294 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
295 msgNotifier
= new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn
),
296 QSocketNotifier::Read
, this);
297 connect(msgNotifier
, SIGNAL(activated(int)), SLOT(receiveMsgs()));
300 adapterSelect
->clear();
301 adapterSelect
->addItem(ctrl_iface
);
302 adapterSelect
->setCurrentIndex(0);
304 len
= sizeof(buf
) - 1;
305 if (wpa_ctrl_request(ctrl_conn
, "INTERFACES", 10, buf
, &len
, NULL
) >=
310 pos2
= strchr(pos
, '\n');
313 if (strcmp(pos
, ctrl_iface
) != 0)
314 adapterSelect
->addItem(pos
);
326 static void wpa_gui_msg_cb(char *msg
, size_t)
328 /* This should not happen anymore since two control connections are
330 printf("missed message: %s\n", msg
);
334 int WpaGui::ctrlRequest(const char *cmd
, char *buf
, size_t *buflen
)
338 if (ctrl_conn
== NULL
)
340 ret
= wpa_ctrl_request(ctrl_conn
, cmd
, strlen(cmd
), buf
, buflen
,
343 printf("'%s' command timed out.\n", cmd
);
345 printf("'%s' command failed.\n", cmd
);
351 void WpaGui::updateStatus()
353 char buf
[2048], *start
, *end
, *pos
;
356 pingsToStatusUpdate
= 10;
358 len
= sizeof(buf
) - 1;
359 if (ctrl_conn
== NULL
|| ctrlRequest("STATUS", buf
, &len
) < 0) {
360 textStatus
->setText("Could not get status from "
362 textAuthentication
->clear();
363 textEncryption
->clear();
366 textIpAddress
->clear();
372 bool auth_updated
= false, ssid_updated
= false;
373 bool bssid_updated
= false, ipaddr_updated
= false;
374 bool status_updated
= false;
375 char *pairwise_cipher
= NULL
, *group_cipher
= NULL
;
380 end
= strchr(start
, '\n');
384 while (end
[0] && end
[1])
389 pos
= strchr(start
, '=');
392 if (strcmp(start
, "bssid") == 0) {
393 bssid_updated
= true;
394 textBssid
->setText(pos
);
395 } else if (strcmp(start
, "ssid") == 0) {
397 textSsid
->setText(pos
);
398 } else if (strcmp(start
, "ip_address") == 0) {
399 ipaddr_updated
= true;
400 textIpAddress
->setText(pos
);
401 } else if (strcmp(start
, "wpa_state") == 0) {
402 status_updated
= true;
403 textStatus
->setText(pos
);
404 } else if (strcmp(start
, "key_mgmt") == 0) {
406 textAuthentication
->setText(pos
);
407 /* TODO: could add EAP status to this */
408 } else if (strcmp(start
, "pairwise_cipher") == 0) {
409 pairwise_cipher
= pos
;
410 } else if (strcmp(start
, "group_cipher") == 0) {
420 if (pairwise_cipher
|| group_cipher
) {
422 if (pairwise_cipher
&& group_cipher
&&
423 strcmp(pairwise_cipher
, group_cipher
) != 0) {
424 encr
.append(pairwise_cipher
);
426 encr
.append(group_cipher
);
427 } else if (pairwise_cipher
) {
428 encr
.append(pairwise_cipher
);
430 encr
.append(group_cipher
);
431 encr
.append(" [group key only]");
433 textEncryption
->setText(encr
);
435 textEncryption
->clear();
440 textAuthentication
->clear();
446 textIpAddress
->clear();
450 void WpaGui::updateNetworks()
452 char buf
[2048], *start
, *end
, *id
, *ssid
, *bssid
, *flags
;
454 int first_active
= -1;
455 int was_selected
= -1;
456 bool current
= false;
458 if (!networkMayHaveChanged
)
461 if (networkList
->currentRow() >= 0)
462 was_selected
= networkList
->currentRow();
464 networkSelect
->clear();
465 networkList
->clear();
467 if (ctrl_conn
== NULL
)
470 len
= sizeof(buf
) - 1;
471 if (ctrlRequest("LIST_NETWORKS", buf
, &len
) < 0)
475 start
= strchr(buf
, '\n');
482 end
= strchr(start
, '\n');
486 while (end
[0] && end
[1])
492 ssid
= strchr(id
, '\t');
496 bssid
= strchr(ssid
, '\t');
500 flags
= strchr(bssid
, '\t');
506 network
.append(": ");
507 network
.append(ssid
);
508 networkSelect
->addItem(network
);
509 networkList
->addItem(network
);
511 if (strstr(flags
, "[CURRENT]")) {
512 networkSelect
->setCurrentIndex(networkSelect
->count() -
515 } else if (first_active
< 0 &&
516 strstr(flags
, "[DISABLED]") == NULL
)
517 first_active
= networkSelect
->count() - 1;
524 if (networkSelect
->count() > 1)
525 networkSelect
->addItem("Select any network");
527 if (!current
&& first_active
>= 0)
528 networkSelect
->setCurrentIndex(first_active
);
530 if (was_selected
>= 0 && networkList
->count() > 0) {
531 if (was_selected
< networkList
->count())
532 networkList
->setCurrentRow(was_selected
);
534 networkList
->setCurrentRow(networkList
->count() - 1);
537 networkList
->setCurrentRow(networkSelect
->currentIndex());
539 networkMayHaveChanged
= false;
543 void WpaGui::helpIndex()
545 printf("helpIndex\n");
549 void WpaGui::helpContents()
551 printf("helpContents\n");
555 void WpaGui::helpAbout()
557 QMessageBox::about(this, "wpa_gui for wpa_supplicant",
558 "Copyright (c) 2003-2008,\n"
559 "Jouni Malinen <j@w1.fi>\n"
560 "and contributors.\n"
562 "This program is free software. You can\n"
563 "distribute it and/or modify it under the terms "
565 "the GNU General Public License version 2.\n"
567 "Alternatively, this software may be distributed\n"
568 "under the terms of the BSD license.\n"
570 "This product includes software developed\n"
571 "by the OpenSSL Project for use in the\n"
572 "OpenSSL Toolkit (http://www.openssl.org/)\n");
576 void WpaGui::disconnect()
579 size_t reply_len
= sizeof(reply
);
580 ctrlRequest("DISCONNECT", reply
, &reply_len
);
591 scanres
= new ScanResults();
594 scanres
->setWpaGui(this);
600 void WpaGui::eventHistory()
607 eh
= new EventHistory();
621 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
623 * QSocketNotifier cannot be used with Windows named pipes, so use a
624 * timer to check for received messages for now. This could be
625 * optimized be doing something specific to named pipes or Windows
626 * events, but it is not clear what would be the best way of doing that
630 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
632 if (scanres
&& !scanres
->isVisible()) {
637 if (eh
&& !eh
->isVisible()) {
642 if (udr
&& !udr
->isVisible()) {
647 len
= sizeof(buf
) - 1;
648 if (ctrlRequest("PING", buf
, &len
) < 0) {
649 printf("PING failed - trying to reconnect\n");
650 if (openCtrlConnection(ctrl_iface
) >= 0) {
651 printf("Reconnected successfully\n");
652 pingsToStatusUpdate
= 0;
656 pingsToStatusUpdate
--;
657 if (pingsToStatusUpdate
<= 0) {
664 static int str_match(const char *a
, const char *b
)
666 return strncmp(a
, b
, strlen(b
)) == 0;
670 void WpaGui::processMsg(char *msg
)
672 char *pos
= msg
, *pos2
;
678 priority
= atoi(pos
);
679 pos
= strchr(pos
, '>');
686 WpaMsg
wm(pos
, priority
);
690 while (msgs
.count() > 100)
693 /* Update last message with truncated version of the event */
694 if (strncmp(pos
, "CTRL-", 5) == 0) {
695 pos2
= strchr(pos
, str_match(pos
, WPA_CTRL_REQ
) ? ':' : ' ');
702 QString lastmsg
= pos2
;
703 lastmsg
.truncate(40);
704 textLastMessage
->setText(lastmsg
);
706 pingsToStatusUpdate
= 0;
707 networkMayHaveChanged
= true;
709 if (str_match(pos
, WPA_CTRL_REQ
))
710 processCtrlReq(pos
+ strlen(WPA_CTRL_REQ
));
711 else if (str_match(pos
, WPA_EVENT_SCAN_RESULTS
) && scanres
)
712 scanres
->updateResults();
716 void WpaGui::processCtrlReq(const char *req
)
722 udr
= new UserDataRequest();
725 if (udr
->setParams(this, req
) < 0) {
735 void WpaGui::receiveMsgs()
740 while (monitor_conn
&& wpa_ctrl_pending(monitor_conn
) > 0) {
741 len
= sizeof(buf
) - 1;
742 if (wpa_ctrl_recv(monitor_conn
, buf
, &len
) == 0) {
750 void WpaGui::connectB()
753 size_t reply_len
= sizeof(reply
);
754 ctrlRequest("REASSOCIATE", reply
, &reply_len
);
758 void WpaGui::selectNetwork( const QString
&sel
)
762 size_t reply_len
= sizeof(reply
);
764 if (cmd
.startsWith("Select any")) {
767 int pos
= cmd
.indexOf(':');
769 printf("Invalid selectNetwork '%s'\n",
770 cmd
.toAscii().constData());
775 cmd
.prepend("SELECT_NETWORK ");
776 ctrlRequest(cmd
.toAscii().constData(), reply
, &reply_len
);
781 void WpaGui::enableNetwork(const QString
&sel
)
785 size_t reply_len
= sizeof(reply
);
787 if (!cmd
.startsWith("all")) {
788 int pos
= cmd
.indexOf(':');
790 printf("Invalid enableNetwork '%s'\n",
791 cmd
.toAscii().constData());
796 cmd
.prepend("ENABLE_NETWORK ");
797 ctrlRequest(cmd
.toAscii().constData(), reply
, &reply_len
);
802 void WpaGui::disableNetwork(const QString
&sel
)
806 size_t reply_len
= sizeof(reply
);
808 if (!cmd
.startsWith("all")) {
809 int pos
= cmd
.indexOf(':');
811 printf("Invalid disableNetwork '%s'\n",
812 cmd
.toAscii().constData());
817 cmd
.prepend("DISABLE_NETWORK ");
818 ctrlRequest(cmd
.toAscii().constData(), reply
, &reply_len
);
823 void WpaGui::editNetwork(const QString
&sel
)
828 if (!cmd
.startsWith("Select any")) {
829 int pos
= sel
.indexOf(':');
831 printf("Invalid editNetwork '%s'\n",
832 cmd
.toAscii().constData());
839 NetworkConfig
*nc
= new NetworkConfig();
845 nc
->paramsFromConfig(id
);
854 void WpaGui::editSelectedNetwork()
856 if (networkSelect
->count() < 1) {
857 QMessageBox::information(this, "No Networks",
858 "There are no networks to edit.\n");
861 QString
sel(networkSelect
->currentText());
866 void WpaGui::editListedNetwork()
868 if (networkList
->currentRow() < 0) {
869 QMessageBox::information(this, "Select A Network",
870 "Select a network from the list to"
874 QString
sel(networkList
->currentItem()->text());
879 void WpaGui::triggerUpdate()
882 networkMayHaveChanged
= true;
887 void WpaGui::addNetwork()
889 NetworkConfig
*nc
= new NetworkConfig();
899 void WpaGui::removeNetwork(const QString
&sel
)
903 size_t reply_len
= sizeof(reply
);
905 if (cmd
.startsWith("Select any"))
908 if (!cmd
.startsWith("all")) {
909 int pos
= cmd
.indexOf(':');
911 printf("Invalid removeNetwork '%s'\n",
912 cmd
.toAscii().constData());
917 cmd
.prepend("REMOVE_NETWORK ");
918 ctrlRequest(cmd
.toAscii().constData(), reply
, &reply_len
);
923 void WpaGui::removeSelectedNetwork()
925 if (networkSelect
->count() < 1) {
926 QMessageBox::information(this, "No Networks",
927 "There are no networks to remove.\n");
930 QString
sel(networkSelect
->currentText());
935 void WpaGui::removeListedNetwork()
937 if (networkList
->currentRow() < 0) {
938 QMessageBox::information(this, "Select A Network",
939 "Select a network from the list to"
943 QString
sel(networkList
->currentItem()->text());
948 void WpaGui::enableAllNetworks()
955 void WpaGui::disableAllNetworks()
962 void WpaGui::removeAllNetworks()
969 int WpaGui::getNetworkDisabled(const QString
&sel
)
973 size_t reply_len
= sizeof(reply
) - 1;
974 int pos
= cmd
.indexOf(':');
976 printf("Invalid getNetworkDisabled '%s'\n",
977 cmd
.toAscii().constData());
981 cmd
.prepend("GET_NETWORK ");
982 cmd
.append(" disabled");
984 if (ctrlRequest(cmd
.toAscii().constData(), reply
, &reply_len
) >= 0
986 reply
[reply_len
] = '\0';
987 if (!str_match(reply
, "FAIL"))
995 void WpaGui::updateNetworkDisabledStatus()
997 if (networkList
->currentRow() < 0)
1000 QString
sel(networkList
->currentItem()->text());
1002 switch (getNetworkDisabled(sel
)) {
1004 if (!enableRadioButton
->isChecked())
1005 enableRadioButton
->setChecked(true);
1008 if (!disableRadioButton
->isChecked())
1009 disableRadioButton
->setChecked(true);
1015 void WpaGui::enableListedNetwork(bool enabled
)
1017 if (networkList
->currentRow() < 0 || !enabled
)
1020 QString
sel(networkList
->currentItem()->text());
1022 if (getNetworkDisabled(sel
) == 1)
1027 void WpaGui::disableListedNetwork(bool disabled
)
1029 if (networkList
->currentRow() < 0 || !disabled
)
1032 QString
sel(networkList
->currentItem()->text());
1034 if (getNetworkDisabled(sel
) == 0)
1035 disableNetwork(sel
);
1039 void WpaGui::saveConfig()
1044 len
= sizeof(buf
) - 1;
1045 ctrlRequest("SAVE_CONFIG", buf
, &len
);
1049 if (str_match(buf
, "FAIL"))
1050 QMessageBox::warning(this, "Failed to save configuration",
1051 "The configuration could not be saved.\n"
1053 "The update_config=1 configuration option\n"
1054 "must be used for configuration saving to\n"
1057 QMessageBox::information(this, "Saved configuration",
1058 "The current configuration was saved."
1063 void WpaGui::selectAdapter( const QString
& sel
)
1065 if (openCtrlConnection(sel
.toAscii().constData()) < 0)
1066 printf("Failed to open control connection to "
1067 "wpa_supplicant.\n");
1073 void WpaGui::closeEvent(QCloseEvent
*event
)