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 {
    362 	    encr.append(group_cipher);
    363 	    encr.append(" [group key only]");
    364 	}
    365 	textEncryption->setText(encr);
    366     } else
    367 	textEncryption->clear();
    368 
    369     if (!status_updated)
    370 	textStatus->clear();
    371     if (!auth_updated)
    372 	textAuthentication->clear();
    373     if (!ssid_updated)
    374 	textSsid->clear();
    375     if (!bssid_updated)
    376 	textBssid->clear();
    377     if (!ipaddr_updated)
    378 	textIpAddress->clear();
    379 }
    380 
    381 
    382 void WpaGui::updateNetworks()
    383 {
    384     char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
    385     size_t len;
    386     int first_active = -1;
    387     bool selected = false;
    388 
    389     if (!networkMayHaveChanged)
    390 	return;
    391 
    392     networkSelect->clear();
    393 
    394     if (ctrl_conn == NULL)
    395 	return;
    396 
    397     len = sizeof(buf) - 1;
    398     if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    399 	return;
    400 
    401     buf[len] = '\0';
    402     start = strchr(buf, '\n');
    403     if (start == NULL)
    404 	return;
    405     start++;
    406 
    407     while (*start) {
    408 	bool last = false;
    409 	end = strchr(start, '\n');
    410 	if (end == NULL) {
    411 	    last = true;
    412 	    end = start;
    413 	    while (end[0] && end[1])
    414 		end++;
    415 	}
    416 	*end = '\0';
    417 
    418 	id = start;
    419 	ssid = strchr(id, '\t');
    420 	if (ssid == NULL)
    421 	    break;
    422 	*ssid++ = '\0';
    423 	bssid = strchr(ssid, '\t');
    424 	if (bssid == NULL)
    425 	    break;
    426 	*bssid++ = '\0';
    427 	flags = strchr(bssid, '\t');
    428 	if (flags == NULL)
    429 	    break;
    430 	*flags++ = '\0';
    431 
    432 	QString network(id);
    433 	network.append(": ");
    434 	network.append(ssid);
    435 	networkSelect->insertItem(network);
    436 
    437 	if (strstr(flags, "[CURRENT]")) {
    438 	    networkSelect->setCurrentItem(networkSelect->count() - 1);
    439 	    selected = true;
    440 	} else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
    441 	    first_active = networkSelect->count() - 1;
    442 
    443 	if (last)
    444 	    break;
    445 	start = end + 1;
    446     }
    447 
    448     if (!selected && first_active >= 0)
    449 	networkSelect->setCurrentItem(first_active);
    450 
    451     networkMayHaveChanged = false;
    452 }
    453 
    454 
    455 void WpaGui::helpIndex()
    456 {
    457     printf("helpIndex\n");
    458 }
    459 
    460 
    461 void WpaGui::helpContents()
    462 {
    463     printf("helpContents\n");
    464 }
    465 
    466 
    467 void WpaGui::helpAbout()
    468 {
    469     QMessageBox::about(this, "wpa_gui for wpa_supplicant",
    470 		       "Copyright (c) 2003-2008,\n"
    471 		       "Jouni Malinen <j (at) w1.fi>\n"
    472 		       "and contributors.\n"
    473 		       "\n"
    474 		       "This program is free software. You can\n"
    475 		       "distribute it and/or modify it under the terms of\n"
    476 		       "the GNU General Public License version 2.\n"
    477 		       "\n"
    478 		       "Alternatively, this software may be distributed\n"
    479 		       "under the terms of the BSD license.\n"
    480 		       "\n"
    481 		       "This product includes software developed\n"
    482 		       "by the OpenSSL Project for use in the\n"
    483 		       "OpenSSL Toolkit (http://www.openssl.org/)\n");
    484 }
    485 
    486 
    487 void WpaGui::disconnect()
    488 {
    489     char reply[10];
    490     size_t reply_len = sizeof(reply);
    491     ctrlRequest("DISCONNECT", reply, &reply_len);
    492 }
    493 
    494 
    495 void WpaGui::scan()
    496 {
    497     if (scanres) {
    498 	scanres->close();
    499 	delete scanres;
    500     }
    501 
    502     scanres = new ScanResults();
    503     if (scanres == NULL)
    504 	return;
    505     scanres->setWpaGui(this);
    506     scanres->show();
    507     scanres->exec();
    508 }
    509 
    510 
    511 void WpaGui::eventHistory()
    512 {
    513     if (eh) {
    514 	eh->close();
    515 	delete eh;
    516     }
    517 
    518     eh = new EventHistory();
    519     if (eh == NULL)
    520 	return;
    521     eh->addEvents(msgs);
    522     eh->show();
    523     eh->exec();
    524 }
    525 
    526 
    527 void WpaGui::ping()
    528 {
    529     char buf[10];
    530     size_t len;
    531 
    532 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    533     /*
    534      * QSocketNotifier cannot be used with Windows named pipes, so use a timer
    535      * to check for received messages for now. This could be optimized be doing
    536      * something specific to named pipes or Windows events, but it is not clear
    537      * what would be the best way of doing that in Qt.
    538      */
    539     receiveMsgs();
    540 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    541 
    542     if (scanres && !scanres->isVisible()) {
    543 	delete scanres;
    544 	scanres = NULL;
    545     }
    546 
    547     if (eh && !eh->isVisible()) {
    548 	delete eh;
    549 	eh = NULL;
    550     }
    551 
    552     if (udr && !udr->isVisible()) {
    553 	delete udr;
    554 	udr = NULL;
    555     }
    556 
    557     len = sizeof(buf) - 1;
    558     if (ctrlRequest("PING", buf, &len) < 0) {
    559 	printf("PING failed - trying to reconnect\n");
    560 	if (openCtrlConnection(ctrl_iface) >= 0) {
    561 	    printf("Reconnected successfully\n");
    562 	    pingsToStatusUpdate = 0;
    563 	}
    564     }
    565 
    566     pingsToStatusUpdate--;
    567     if (pingsToStatusUpdate <= 0) {
    568 	updateStatus();
    569 	updateNetworks();
    570     }
    571 }
    572 
    573 
    574 static int str_match(const char *a, const char *b)
    575 {
    576     return strncmp(a, b, strlen(b)) == 0;
    577 }
    578 
    579 
    580 void WpaGui::processMsg(char *msg)
    581 {
    582     char *pos = msg, *pos2;
    583     int priority = 2;
    584 
    585     if (*pos == '<') {
    586 	/* skip priority */
    587 	pos++;
    588 	priority = atoi(pos);
    589 	pos = strchr(pos, '>');
    590 	if (pos)
    591 	    pos++;
    592 	else
    593 	    pos = msg;
    594     }
    595 
    596     WpaMsg wm(pos, priority);
    597     if (eh)
    598 	eh->addEvent(wm);
    599     msgs.append(wm);
    600     while (msgs.count() > 100)
    601 	msgs.pop_front();
    602 
    603     /* Update last message with truncated version of the event */
    604     if (strncmp(pos, "CTRL-", 5) == 0) {
    605 	pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
    606 	if (pos2)
    607 	    pos2++;
    608 	else
    609 	    pos2 = pos;
    610     } else
    611 	pos2 = pos;
    612     QString lastmsg = pos2;
    613     lastmsg.truncate(40);
    614     textLastMessage->setText(lastmsg);
    615 
    616     pingsToStatusUpdate = 0;
    617     networkMayHaveChanged = true;
    618 
    619     if (str_match(pos, WPA_CTRL_REQ))
    620 	processCtrlReq(pos + strlen(WPA_CTRL_REQ));
    621 }
    622 
    623 
    624 void WpaGui::processCtrlReq(const char *req)
    625 {
    626     if (udr) {
    627 	udr->close();
    628 	delete udr;
    629     }
    630     udr = new UserDataRequest();
    631     if (udr == NULL)
    632 	return;
    633     if (udr->setParams(this, req) < 0) {
    634 	delete udr;
    635 	udr = NULL;
    636 	return;
    637     }
    638     udr->show();
    639     udr->exec();
    640 }
    641 
    642 
    643 void WpaGui::receiveMsgs()
    644 {
    645     char buf[256];
    646     size_t len;
    647 
    648     while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
    649 	len = sizeof(buf) - 1;
    650 	if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
    651 	    buf[len] = '\0';
    652 	    processMsg(buf);
    653 	}
    654     }
    655 }
    656 
    657 
    658 void WpaGui::connectB()
    659 {
    660     char reply[10];
    661     size_t reply_len = sizeof(reply);
    662     ctrlRequest("REASSOCIATE", reply, &reply_len);
    663 }
    664 
    665 
    666 void WpaGui::selectNetwork( const QString &sel )
    667 {
    668     QString cmd(sel);
    669     char reply[10];
    670     size_t reply_len = sizeof(reply);
    671 
    672     int pos = cmd.find(':');
    673     if (pos < 0) {
    674 	printf("Invalid selectNetwork '%s'\n", cmd.ascii());
    675 	return;
    676     }
    677     cmd.truncate(pos);
    678     cmd.prepend("SELECT_NETWORK ");
    679     ctrlRequest(cmd.ascii(), reply, &reply_len);
    680 }
    681 
    682 
    683 void WpaGui::editNetwork()
    684 {
    685     QString sel(networkSelect->currentText());
    686     int pos = sel.find(':');
    687     if (pos < 0) {
    688 	printf("Invalid selectNetwork '%s'\n", sel.ascii());
    689 	return;
    690     }
    691     sel.truncate(pos);
    692 
    693     NetworkConfig *nc = new NetworkConfig();
    694     if (nc == NULL)
    695 	return;
    696     nc->setWpaGui(this);
    697 
    698     nc->paramsFromConfig(sel.toInt());
    699     nc->show();
    700     nc->exec();
    701 }
    702 
    703 
    704 void WpaGui::triggerUpdate()
    705 {
    706     updateStatus();
    707     networkMayHaveChanged = true;
    708     updateNetworks();
    709 }
    710 
    711 
    712 void WpaGui::addNetwork()
    713 {
    714     NetworkConfig *nc = new NetworkConfig();
    715     if (nc == NULL)
    716 	return;
    717     nc->setWpaGui(this);
    718     nc->newNetwork();
    719     nc->show();
    720     nc->exec();
    721 }
    722 
    723 
    724 void WpaGui::selectAdapter( const QString & sel )
    725 {
    726     if (openCtrlConnection(sel.ascii()) < 0)
    727 	printf("Failed to open control connection to wpa_supplicant.\n");
    728     updateStatus();
    729     updateNetworks();
    730 }
    731