729 lines
15 KiB
C
729 lines
15 KiB
C
/****************************************************************************
|
|
** 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
|
|
|
|
|
|
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 {
|
|
encr.append(group_cipher);
|
|
encr.append(" [group key only]");
|
|
}
|
|
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 <j@w1.fi>\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();
|
|
}
|