Home | History | Annotate | Download | only in wpa_gui
      1 /****************************************************************************
      2 ** ui.h extension file, included from the uic-generated form implementation.
      3 **
      4 ** If you want to add, delete, or rename functions or slots, use
      5 ** Qt Designer to update this file, preserving your code.
      6 **
      7 ** You should not define a constructor or destructor in this file.
      8 ** Instead, write your code in functions called init() and destroy().
      9 ** These will automatically be called by the form's constructor and
     10 ** destructor.
     11 *****************************************************************************/
     12 
     13 
     14 #ifdef __MINGW32__
     15 /* Need to get getopt() */
     16 #include <unistd.h>
     17 #endif
     18 
     19 #include <stdlib.h>
     20 
     21 void WpaGui::init()
     22 {
     23     eh = NULL;
     24     scanres = NULL;
     25     udr = NULL;
     26     ctrl_iface = NULL;
     27     ctrl_conn = NULL;
     28     monitor_conn = NULL;
     29     msgNotifier = NULL;
     30     ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
     31 
     32     parse_argv();
     33 
     34     textStatus->setText("connecting to wpa_supplicant");
     35     timer = new QTimer(this);
     36     connect(timer, SIGNAL(timeout()), SLOT(ping()));
     37     timer->start(1000, FALSE);
     38 
     39     if (openCtrlConnection(ctrl_iface) < 0) {
     40 	printf("Failed to open control connection to wpa_supplicant.\n");
     41     }
     42 
     43     updateStatus();
     44     networkMayHaveChanged = true;
     45     updateNetworks();
     46 }
     47 
     48 
     49 void WpaGui::destroy()
     50 {
     51     delete msgNotifier;
     52 
     53     if (monitor_conn) {
     54 	wpa_ctrl_detach(monitor_conn);
     55 	wpa_ctrl_close(monitor_conn);
     56 	monitor_conn = NULL;
     57     }
     58     if (ctrl_conn) {
     59 	wpa_ctrl_close(ctrl_conn);
     60 	ctrl_conn = NULL;
     61     }
     62 
     63     if (eh) {
     64 	eh->close();
     65 	delete eh;
     66 	eh = NULL;
     67     }
     68 
     69     if (scanres) {
     70 	scanres->close();
     71 	delete scanres;
     72 	scanres = NULL;
     73     }
     74 
     75     if (udr) {
     76 	udr->close();
     77 	delete udr;
     78 	udr = NULL;
     79     }
     80 
     81     free(ctrl_iface);
     82     ctrl_iface = NULL;
     83 
     84     free(ctrl_iface_dir);
     85     ctrl_iface_dir = NULL;
     86 }
     87 
     88 
     89 void WpaGui::parse_argv()
     90 {
     91     int c;
     92     for (;;) {
     93 	c = getopt(qApp->argc(), qApp->argv(), "i:p:");
     94 	if (c < 0)
     95 	    break;
     96 	switch (c) {
     97 	case 'i':
     98 	    free(ctrl_iface);
     99 	    ctrl_iface = strdup(optarg);
    100 	    break;
    101 	case 'p':
    102 	    free(ctrl_iface_dir);
    103 	    ctrl_iface_dir = strdup(optarg);
    104 	    break;
    105 	}
    106     }
    107 }
    108 
    109 
    110 int WpaGui::openCtrlConnection(const char *ifname)
    111 {
    112     char *cfile;
    113     int flen;
    114     char buf[2048], *pos, *pos2;
    115     size_t len;
    116 
    117     if (ifname) {
    118 	if (ifname != ctrl_iface) {
    119 	    free(ctrl_iface);
    120 	    ctrl_iface = strdup(ifname);
    121 	}
    122     } else {
    123 #ifdef CONFIG_CTRL_IFACE_UDP
    124 	free(ctrl_iface);
    125 	ctrl_iface = strdup("udp");
    126 #endif /* CONFIG_CTRL_IFACE_UDP */
    127 #ifdef CONFIG_CTRL_IFACE_UNIX
    128 	struct dirent *dent;
    129 	DIR *dir = opendir(ctrl_iface_dir);
    130 	free(ctrl_iface);
    131 	ctrl_iface = NULL;
    132 	if (dir) {
    133 	    while ((dent = readdir(dir))) {
    134 #ifdef _DIRENT_HAVE_D_TYPE
    135 		/* Skip the file if it is not a socket.
    136 		 * Also accept DT_UNKNOWN (0) in case
    137 		 * the C library or underlying file
    138 		 * system does not support d_type. */
    139 		if (dent->d_type != DT_SOCK &&
    140 		    dent->d_type != DT_UNKNOWN)
    141 		    continue;
    142 #endif /* _DIRENT_HAVE_D_TYPE */
    143 
    144 		if (strcmp(dent->d_name, ".") == 0 ||
    145 		    strcmp(dent->d_name, "..") == 0)
    146 		    continue;
    147 		printf("Selected interface '%s'\n", dent->d_name);
    148 		ctrl_iface = strdup(dent->d_name);
    149 		break;
    150 	    }
    151 	    closedir(dir);
    152 	}
    153 #endif /* CONFIG_CTRL_IFACE_UNIX */
    154 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    155 	struct wpa_ctrl *ctrl;
    156 	int ret;
    157 
    158 	free(ctrl_iface);
    159 	ctrl_iface = NULL;
    160 
    161 	ctrl = wpa_ctrl_open(NULL);
    162 	if (ctrl) {
    163 	    len = sizeof(buf) - 1;
    164 	    ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
    165 	    if (ret >= 0) {
    166 		buf[len] = '\0';
    167 		pos = strchr(buf, '\n');
    168 		if (pos)
    169 		    *pos = '\0';
    170 		ctrl_iface = strdup(buf);
    171 	    }
    172 	    wpa_ctrl_close(ctrl);
    173 	}
    174 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    175     }
    176 
    177     if (ctrl_iface == NULL)
    178 	return -1;
    179 
    180 #ifdef CONFIG_CTRL_IFACE_UNIX
    181     flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
    182     cfile = (char *) malloc(flen);
    183     if (cfile == NULL)
    184 	return -1;
    185     snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
    186 #else /* CONFIG_CTRL_IFACE_UNIX */
    187     flen = strlen(ctrl_iface) + 1;
    188     cfile = (char *) malloc(flen);
    189     if (cfile == NULL)
    190 	return -1;
    191     snprintf(cfile, flen, "%s", ctrl_iface);
    192 #endif /* CONFIG_CTRL_IFACE_UNIX */
    193 
    194     if (ctrl_conn) {
    195 	wpa_ctrl_close(ctrl_conn);
    196 	ctrl_conn = NULL;
    197     }
    198 
    199     if (monitor_conn) {
    200 	delete msgNotifier;
    201 	msgNotifier = NULL;
    202 	wpa_ctrl_detach(monitor_conn);
    203 	wpa_ctrl_close(monitor_conn);
    204 	monitor_conn = NULL;
    205     }
    206 
    207     printf("Trying to connect to '%s'\n", cfile);
    208     ctrl_conn = wpa_ctrl_open(cfile);
    209     if (ctrl_conn == NULL) {
    210 	free(cfile);
    211 	return -1;
    212     }
    213     monitor_conn = wpa_ctrl_open(cfile);
    214     free(cfile);
    215     if (monitor_conn == NULL) {
    216 	wpa_ctrl_close(ctrl_conn);
    217 	return -1;
    218     }
    219     if (wpa_ctrl_attach(monitor_conn)) {
    220 	printf("Failed to attach to wpa_supplicant\n");
    221 	wpa_ctrl_close(monitor_conn);
    222 	monitor_conn = NULL;
    223 	wpa_ctrl_close(ctrl_conn);
    224 	ctrl_conn = NULL;
    225 	return -1;
    226     }
    227 
    228 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
    229     msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
    230 				      QSocketNotifier::Read, this);
    231     connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
    232 #endif
    233 
    234     adapterSelect->clear();
    235     adapterSelect->insertItem(ctrl_iface);
    236     adapterSelect->setCurrentItem(0);
    237 
    238     len = sizeof(buf) - 1;
    239     if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
    240 	buf[len] = '\0';
    241 	pos = buf;
    242 	while (*pos) {
    243 		pos2 = strchr(pos, '\n');
    244 		if (pos2)
    245 			*pos2 = '\0';
    246 		if (strcmp(pos, ctrl_iface) != 0)
    247 			adapterSelect->insertItem(pos);
    248 		if (pos2)
    249 			pos = pos2 + 1;
    250 		else
    251 			break;
    252 	}
    253     }
    254 
    255     return 0;
    256 }
    257 
    258 
    259 static void wpa_gui_msg_cb(char *msg, size_t)
    260 {
    261     /* This should not happen anymore since two control connections are used. */
    262     printf("missed message: %s\n", msg);
    263 }
    264 
    265 
    266 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
    267 {
    268     int ret;
    269 
    270     if (ctrl_conn == NULL)
    271 	return -3;
    272     ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
    273 			   wpa_gui_msg_cb);
    274     if (ret == -2) {
    275 	printf("'%s' command timed out.\n", cmd);
    276     } else if (ret < 0) {
    277 	printf("'%s' command failed.\n", cmd);
    278     }
    279 
    280     return ret;
    281 }
    282 
    283 
    284 void WpaGui::updateStatus()
    285 {
    286     char buf[2048], *start, *end, *pos;
    287     size_t len;
    288 
    289     pingsToStatusUpdate = 10;
    290 
    291     len = sizeof(buf) - 1;
    292     if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
    293 	textStatus->setText("Could not get status from wpa_supplicant");
    294 	textAuthentication->clear();
    295 	textEncryption->clear();
    296 	textSsid->clear();
    297 	textBssid->clear();
    298 	textIpAddress->clear();
    299 	return;
    300     }
    301 
    302     buf[len] = '\0';
    303 
    304     bool auth_updated = false, ssid_updated = false;
    305     bool bssid_updated = false, ipaddr_updated = false;
    306     bool status_updated = false;
    307     char *pairwise_cipher = NULL, *group_cipher = NULL;
    308 
    309     start = buf;
    310     while (*start) {
    311 	bool last = false;
    312 	end = strchr(start, '\n');
    313 	if (end == NULL) {
    314 	    last = true;
    315 	    end = start;
    316 	    while (end[0] && end[1])
    317 		end++;
    318 	}
    319 	*end = '\0';
    320 
    321 	pos = strchr(start, '=');
    322 	if (pos) {
    323 	    *pos++ = '\0';
    324 	    if (strcmp(start, "bssid") == 0) {
    325 		bssid_updated = true;
    326 		textBssid->setText(pos);
    327 	    } else if (strcmp(start, "ssid") == 0) {
    328 		ssid_updated = true;
    329 		textSsid->setText(pos);
    330 	    } else if (strcmp(start, "ip_address") == 0) {
    331 		ipaddr_updated = true;
    332 		textIpAddress->setText(pos);
    333 	    } else if (strcmp(start, "wpa_state") == 0) {
    334 		status_updated = true;
    335 		textStatus->setText(pos);
    336 	    } else if (strcmp(start, "key_mgmt") == 0) {
    337 		auth_updated = true;
    338 		textAuthentication->setText(pos);
    339 		/* TODO: could add EAP status to this */
    340 	    } else if (strcmp(start, "pairwise_cipher") == 0) {
    341 		pairwise_cipher = pos;
    342 	    } else if (strcmp(start, "group_cipher") == 0) {
    343 		group_cipher = pos;
    344 	    }
    345 	}
    346 
    347 	if (last)
    348 	    break;
    349 	start = end + 1;
    350     }
    351 
    352     if (pairwise_cipher || group_cipher) {
    353 	QString encr;
    354 	if (pairwise_cipher && group_cipher &&
    355 	    strcmp(pairwise_cipher, group_cipher) != 0) {
    356 	    encr.append(pairwise_cipher);
    357 	    encr.append(" + ");
    358 	    encr.append(group_cipher);
    359 	} else if (pairwise_cipher) {
    360 	    encr.append(pairwise_cipher);
    361 	} else if (group_cipher) {
    362 	    encr.append(group_cipher);
    363 	    encr.append(" [group key only]");
    364 	} else {
    365 	    encr.append("?");
    366 	}
    367 	textEncryption->setText(encr);
    368     } else
    369 	textEncryption->clear();
    370 
    371     if (!status_updated)
    372 	textStatus->clear();
    373     if (!auth_updated)
    374 	textAuthentication->clear();
    375     if (!ssid_updated)
    376 	textSsid->clear();
    377     if (!bssid_updated)
    378 	textBssid->clear();
    379     if (!ipaddr_updated)
    380 	textIpAddress->clear();
    381 }
    382 
    383 
    384 void WpaGui::updateNetworks()
    385 {
    386     char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
    387     size_t len;
    388     int first_active = -1;
    389     bool selected = false;
    390 
    391     if (!networkMayHaveChanged)
    392 	return;
    393 
    394     networkSelect->clear();
    395 
    396     if (ctrl_conn == NULL)
    397 	return;
    398 
    399     len = sizeof(buf) - 1;
    400     if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    401 	return;
    402 
    403     buf[len] = '\0';
    404     start = strchr(buf, '\n');
    405     if (start == NULL)
    406 	return;
    407     start++;
    408 
    409     while (*start) {
    410 	bool last = false;
    411 	end = strchr(start, '\n');
    412 	if (end == NULL) {
    413 	    last = true;
    414 	    end = start;
    415 	    while (end[0] && end[1])
    416 		end++;
    417 	}
    418 	*end = '\0';
    419 
    420 	id = start;
    421 	ssid = strchr(id, '\t');
    422 	if (ssid == NULL)
    423 	    break;
    424 	*ssid++ = '\0';
    425 	bssid = strchr(ssid, '\t');
    426 	if (bssid == NULL)
    427 	    break;
    428 	*bssid++ = '\0';
    429 	flags = strchr(bssid, '\t');
    430 	if (flags == NULL)
    431 	    break;
    432 	*flags++ = '\0';
    433 
    434 	QString network(id);
    435 	network.append(": ");
    436 	network.append(ssid);
    437 	networkSelect->insertItem(network);
    438 
    439 	if (strstr(flags, "[CURRENT]")) {
    440 	    networkSelect->setCurrentItem(networkSelect->count() - 1);
    441 	    selected = true;
    442 	} else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
    443 	    first_active = networkSelect->count() - 1;
    444 
    445 	if (last)
    446 	    break;
    447 	start = end + 1;
    448     }
    449 
    450     if (!selected && first_active >= 0)
    451 	networkSelect->setCurrentItem(first_active);
    452 
    453     networkMayHaveChanged = false;
    454 }
    455 
    456 
    457 void WpaGui::helpIndex()
    458 {
    459     printf("helpIndex\n");
    460 }
    461 
    462 
    463 void WpaGui::helpContents()
    464 {
    465     printf("helpContents\n");
    466 }
    467 
    468 
    469 void WpaGui::helpAbout()
    470 {
    471     QMessageBox::about(this, "wpa_gui for wpa_supplicant",
    472 		       "Copyright (c) 2003-2008,\n"
    473 		       "Jouni Malinen <j (at) w1.fi>\n"
    474 		       "and contributors.\n"
    475 		       "\n"
    476 		       "This program is free software. You can\n"
    477 		       "distribute it and/or modify it under the terms of\n"
    478 		       "the GNU General Public License version 2.\n"
    479 		       "\n"
    480 		       "Alternatively, this software may be distributed\n"
    481 		       "under the terms of the BSD license.\n"
    482 		       "\n"
    483 		       "This product includes software developed\n"
    484 		       "by the OpenSSL Project for use in the\n"
    485 		       "OpenSSL Toolkit (http://www.openssl.org/)\n");
    486 }
    487 
    488 
    489 void WpaGui::disconnect()
    490 {
    491     char reply[10];
    492     size_t reply_len = sizeof(reply);
    493     ctrlRequest("DISCONNECT", reply, &reply_len);
    494 }
    495 
    496 
    497 void WpaGui::scan()
    498 {
    499     if (scanres) {
    500 	scanres->close();
    501 	delete scanres;
    502     }
    503 
    504     scanres = new ScanResults();
    505     if (scanres == NULL)
    506 	return;
    507     scanres->setWpaGui(this);
    508     scanres->show();
    509     scanres->exec();
    510 }
    511 
    512 
    513 void WpaGui::eventHistory()
    514 {
    515     if (eh) {
    516 	eh->close();
    517 	delete eh;
    518     }
    519 
    520     eh = new EventHistory();
    521     if (eh == NULL)
    522 	return;
    523     eh->addEvents(msgs);
    524     eh->show();
    525     eh->exec();
    526 }
    527 
    528 
    529 void WpaGui::ping()
    530 {
    531     char buf[10];
    532     size_t len;
    533 
    534 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    535     /*
    536      * QSocketNotifier cannot be used with Windows named pipes, so use a timer
    537      * to check for received messages for now. This could be optimized be doing
    538      * something specific to named pipes or Windows events, but it is not clear
    539      * what would be the best way of doing that in Qt.
    540      */
    541     receiveMsgs();
    542 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    543 
    544     if (scanres && !scanres->isVisible()) {
    545 	delete scanres;
    546 	scanres = NULL;
    547     }
    548 
    549     if (eh && !eh->isVisible()) {
    550 	delete eh;
    551 	eh = NULL;
    552     }
    553 
    554     if (udr && !udr->isVisible()) {
    555 	delete udr;
    556 	udr = NULL;
    557     }
    558 
    559     len = sizeof(buf) - 1;
    560     if (ctrlRequest("PING", buf, &len) < 0) {
    561 	printf("PING failed - trying to reconnect\n");
    562 	if (openCtrlConnection(ctrl_iface) >= 0) {
    563 	    printf("Reconnected successfully\n");
    564 	    pingsToStatusUpdate = 0;
    565 	}
    566     }
    567 
    568     pingsToStatusUpdate--;
    569     if (pingsToStatusUpdate <= 0) {
    570 	updateStatus();
    571 	updateNetworks();
    572     }
    573 }
    574 
    575 
    576 static int str_match(const char *a, const char *b)
    577 {
    578     return strncmp(a, b, strlen(b)) == 0;
    579 }
    580 
    581 
    582 void WpaGui::processMsg(char *msg)
    583 {
    584     char *pos = msg, *pos2;
    585     int priority = 2;
    586 
    587     if (*pos == '<') {
    588 	/* skip priority */
    589 	pos++;
    590 	priority = atoi(pos);
    591 	pos = strchr(pos, '>');
    592 	if (pos)
    593 	    pos++;
    594 	else
    595 	    pos = msg;
    596     }
    597 
    598     WpaMsg wm(pos, priority);
    599     if (eh)
    600 	eh->addEvent(wm);
    601     msgs.append(wm);
    602     while (msgs.count() > 100)
    603 	msgs.pop_front();
    604 
    605     /* Update last message with truncated version of the event */
    606     if (strncmp(pos, "CTRL-", 5) == 0) {
    607 	pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
    608 	if (pos2)
    609 	    pos2++;
    610 	else
    611 	    pos2 = pos;
    612     } else
    613 	pos2 = pos;
    614     QString lastmsg = pos2;
    615     lastmsg.truncate(40);
    616     textLastMessage->setText(lastmsg);
    617 
    618     pingsToStatusUpdate = 0;
    619     networkMayHaveChanged = true;
    620 
    621     if (str_match(pos, WPA_CTRL_REQ))
    622 	processCtrlReq(pos + strlen(WPA_CTRL_REQ));
    623 }
    624 
    625 
    626 void WpaGui::processCtrlReq(const char *req)
    627 {
    628     if (udr) {
    629 	udr->close();
    630 	delete udr;
    631     }
    632     udr = new UserDataRequest();
    633     if (udr == NULL)
    634 	return;
    635     if (udr->setParams(this, req) < 0) {
    636 	delete udr;
    637 	udr = NULL;
    638 	return;
    639     }
    640     udr->show();
    641     udr->exec();
    642 }
    643 
    644 
    645 void WpaGui::receiveMsgs()
    646 {
    647     char buf[256];
    648     size_t len;
    649 
    650     while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
    651 	len = sizeof(buf) - 1;
    652 	if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
    653 	    buf[len] = '\0';
    654 	    processMsg(buf);
    655 	}
    656     }
    657 }
    658 
    659 
    660 void WpaGui::connectB()
    661 {
    662     char reply[10];
    663     size_t reply_len = sizeof(reply);
    664     ctrlRequest("REASSOCIATE", reply, &reply_len);
    665 }
    666 
    667 
    668 void WpaGui::selectNetwork( const QString &sel )
    669 {
    670     QString cmd(sel);
    671     char reply[10];
    672     size_t reply_len = sizeof(reply);
    673 
    674     int pos = cmd.find(':');
    675     if (pos < 0) {
    676 	printf("Invalid selectNetwork '%s'\n", cmd.ascii());
    677 	return;
    678     }
    679     cmd.truncate(pos);
    680     cmd.prepend("SELECT_NETWORK ");
    681     ctrlRequest(cmd.ascii(), reply, &reply_len);
    682 }
    683 
    684 
    685 void WpaGui::editNetwork()
    686 {
    687     QString sel(networkSelect->currentText());
    688     int pos = sel.find(':');
    689     if (pos < 0) {
    690 	printf("Invalid selectNetwork '%s'\n", sel.ascii());
    691 	return;
    692     }
    693     sel.truncate(pos);
    694 
    695     NetworkConfig *nc = new NetworkConfig();
    696     if (nc == NULL)
    697 	return;
    698     nc->setWpaGui(this);
    699 
    700     nc->paramsFromConfig(sel.toInt());
    701     nc->show();
    702     nc->exec();
    703 }
    704 
    705 
    706 void WpaGui::triggerUpdate()
    707 {
    708     updateStatus();
    709     networkMayHaveChanged = true;
    710     updateNetworks();
    711 }
    712 
    713 
    714 void WpaGui::addNetwork()
    715 {
    716     NetworkConfig *nc = new NetworkConfig();
    717     if (nc == NULL)
    718 	return;
    719     nc->setWpaGui(this);
    720     nc->newNetwork();
    721     nc->show();
    722     nc->exec();
    723 }
    724 
    725 
    726 void WpaGui::selectAdapter( const QString & sel )
    727 {
    728     if (openCtrlConnection(sel.ascii()) < 0)
    729 	printf("Failed to open control connection to wpa_supplicant.\n");
    730     updateStatus();
    731     updateNetworks();
    732 }
    733