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
init()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
destroy()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
parse_argv()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
openCtrlConnection(const char * ifname)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
wpa_gui_msg_cb(char * msg,size_t)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
ctrlRequest(const char * cmd,char * buf,size_t * buflen)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
updateStatus()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
updateNetworks()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
helpIndex()455 void WpaGui::helpIndex()
456 {
457 printf("helpIndex\n");
458 }
459
460
helpContents()461 void WpaGui::helpContents()
462 {
463 printf("helpContents\n");
464 }
465
466
helpAbout()467 void 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
disconnect()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
scan()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
eventHistory()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
ping()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
str_match(const char * a,const char * b)574 static int str_match(const char *a, const char *b)
575 {
576 return strncmp(a, b, strlen(b)) == 0;
577 }
578
579
processMsg(char * msg)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
processCtrlReq(const char * req)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
receiveMsgs()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
connectB()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
selectNetwork(const QString & sel)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
editNetwork()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
triggerUpdate()704 void WpaGui::triggerUpdate()
705 {
706 updateStatus();
707 networkMayHaveChanged = true;
708 updateNetworks();
709 }
710
711
addNetwork()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
selectAdapter(const QString & sel)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