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)