wpagui.ui.h revision 8d520ff1dc2da35cdca849e982051b86468016d8
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
21void 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
49void 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
89void 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
110int 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
259static 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
266int 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
284void 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
382void 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
455void WpaGui::helpIndex()
456{
457    printf("helpIndex\n");
458}
459
460
461void WpaGui::helpContents()
462{
463    printf("helpContents\n");
464}
465
466
467void WpaGui::helpAbout()
468{
469    QMessageBox::about(this, "wpa_gui for wpa_supplicant",
470		       "Copyright (c) 2003-2008,\n"
471		       "Jouni Malinen <j@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
487void WpaGui::disconnect()
488{
489    char reply[10];
490    size_t reply_len = sizeof(reply);
491    ctrlRequest("DISCONNECT", reply, &reply_len);
492}
493
494
495void 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
511void 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
527void 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
574static int str_match(const char *a, const char *b)
575{
576    return strncmp(a, b, strlen(b)) == 0;
577}
578
579
580void 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
624void 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
643void 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
658void WpaGui::connectB()
659{
660    char reply[10];
661    size_t reply_len = sizeof(reply);
662    ctrlRequest("REASSOCIATE", reply, &reply_len);
663}
664
665
666void 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
683void 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
704void WpaGui::triggerUpdate()
705{
706    updateStatus();
707    networkMayHaveChanged = true;
708    updateNetworks();
709}
710
711
712void 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
724void 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