1/* 2 * wpa_gui - Peers class 3 * Copyright (c) 2009, Atheros Communications 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include <cstdio> 16#include <QImageReader> 17#include <QMessageBox> 18 19#include "common/wpa_ctrl.h" 20#include "wpagui.h" 21#include "stringquery.h" 22#include "peers.h" 23 24 25enum { 26 peer_role_address = Qt::UserRole + 1, 27 peer_role_type, 28 peer_role_uuid, 29 peer_role_details, 30 peer_role_pri_dev_type, 31 peer_role_ssid, 32 peer_role_config_methods, 33 peer_role_dev_passwd_id, 34 peer_role_bss_id 35}; 36 37/* 38 * TODO: 39 * - add current AP info (e.g., from WPS) in station mode 40 */ 41 42enum peer_type { 43 PEER_TYPE_ASSOCIATED_STATION, 44 PEER_TYPE_AP, 45 PEER_TYPE_AP_WPS, 46 PEER_TYPE_WPS_PIN_NEEDED, 47 PEER_TYPE_WPS_ER_AP, 48 PEER_TYPE_WPS_ER_AP_UNCONFIGURED, 49 PEER_TYPE_WPS_ER_ENROLLEE, 50 PEER_TYPE_WPS_ENROLLEE 51}; 52 53 54Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags) 55 : QDialog(parent) 56{ 57 setupUi(this); 58 59 if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) 60 { 61 default_icon = new QIcon(":/icons/wpa_gui.svg"); 62 ap_icon = new QIcon(":/icons/ap.svg"); 63 laptop_icon = new QIcon(":/icons/laptop.svg"); 64 } else { 65 default_icon = new QIcon(":/icons/wpa_gui.png"); 66 ap_icon = new QIcon(":/icons/ap.png"); 67 laptop_icon = new QIcon(":/icons/laptop.png"); 68 } 69 70 peers->setModel(&model); 71 peers->setResizeMode(QListView::Adjust); 72 73 peers->setContextMenuPolicy(Qt::CustomContextMenu); 74 connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)), 75 this, SLOT(context_menu(const QPoint &))); 76 77 wpagui = NULL; 78} 79 80 81void Peers::setWpaGui(WpaGui *_wpagui) 82{ 83 wpagui = _wpagui; 84 update_peers(); 85} 86 87 88Peers::~Peers() 89{ 90 delete default_icon; 91 delete ap_icon; 92 delete laptop_icon; 93} 94 95 96void Peers::languageChange() 97{ 98 retranslateUi(this); 99} 100 101 102QString Peers::ItemType(int type) 103{ 104 QString title; 105 switch (type) { 106 case PEER_TYPE_ASSOCIATED_STATION: 107 title = tr("Associated station"); 108 break; 109 case PEER_TYPE_AP: 110 title = tr("AP"); 111 break; 112 case PEER_TYPE_AP_WPS: 113 title = tr("WPS AP"); 114 break; 115 case PEER_TYPE_WPS_PIN_NEEDED: 116 title = tr("WPS PIN needed"); 117 break; 118 case PEER_TYPE_WPS_ER_AP: 119 title = tr("ER: WPS AP"); 120 break; 121 case PEER_TYPE_WPS_ER_AP_UNCONFIGURED: 122 title = tr("ER: WPS AP (Unconfigured)"); 123 break; 124 case PEER_TYPE_WPS_ER_ENROLLEE: 125 title = tr("ER: WPS Enrollee"); 126 break; 127 case PEER_TYPE_WPS_ENROLLEE: 128 title = tr("WPS Enrollee"); 129 break; 130 } 131 return title; 132} 133 134 135void Peers::context_menu(const QPoint &pos) 136{ 137 QMenu *menu = new QMenu; 138 if (menu == NULL) 139 return; 140 141 QModelIndex idx = peers->indexAt(pos); 142 if (idx.isValid()) { 143 ctx_item = model.itemFromIndex(idx); 144 int type = ctx_item->data(peer_role_type).toInt(); 145 menu->addAction(Peers::ItemType(type))->setEnabled(false); 146 menu->addSeparator(); 147 148 int config_methods = -1; 149 QVariant var = ctx_item->data(peer_role_config_methods); 150 if (var.isValid()) 151 config_methods = var.toInt(); 152 153 if ((type == PEER_TYPE_ASSOCIATED_STATION || 154 type == PEER_TYPE_AP_WPS || 155 type == PEER_TYPE_WPS_PIN_NEEDED || 156 type == PEER_TYPE_WPS_ER_ENROLLEE || 157 type == PEER_TYPE_WPS_ENROLLEE) && 158 (config_methods == -1 || (config_methods & 0x010c))) { 159 menu->addAction(tr("Enter WPS PIN"), this, 160 SLOT(enter_pin())); 161 } 162 163 if (type == PEER_TYPE_AP_WPS) { 164 menu->addAction(tr("Connect (PBC)"), this, 165 SLOT(connect_pbc())); 166 } 167 168 if ((type == PEER_TYPE_ASSOCIATED_STATION || 169 type == PEER_TYPE_WPS_ER_ENROLLEE || 170 type == PEER_TYPE_WPS_ENROLLEE) && 171 config_methods >= 0 && (config_methods & 0x0080)) { 172 menu->addAction(tr("Enroll (PBC)"), this, 173 SLOT(connect_pbc())); 174 } 175 176 if (type == PEER_TYPE_WPS_ER_AP) { 177 menu->addAction(tr("Learn Configuration"), this, 178 SLOT(learn_ap_config())); 179 } 180 181 menu->addAction(tr("Properties"), this, SLOT(properties())); 182 } else { 183 ctx_item = NULL; 184 menu->addAction(QString(tr("Refresh")), this, 185 SLOT(ctx_refresh())); 186 } 187 188 menu->exec(peers->mapToGlobal(pos)); 189} 190 191 192void Peers::enter_pin() 193{ 194 if (ctx_item == NULL) 195 return; 196 197 int peer_type = ctx_item->data(peer_role_type).toInt(); 198 QString uuid; 199 QString addr; 200 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) 201 uuid = ctx_item->data(peer_role_uuid).toString(); 202 else 203 addr = ctx_item->data(peer_role_address).toString(); 204 205 StringQuery input(tr("PIN:")); 206 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 207 if (input.exec() != QDialog::Accepted) 208 return; 209 210 char cmd[100]; 211 char reply[100]; 212 size_t reply_len; 213 214 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { 215 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s", 216 uuid.toAscii().constData(), 217 input.get_string().toAscii().constData()); 218 } else { 219 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", 220 addr.toAscii().constData(), 221 input.get_string().toAscii().constData()); 222 } 223 reply_len = sizeof(reply) - 1; 224 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 225 QMessageBox msg; 226 msg.setIcon(QMessageBox::Warning); 227 msg.setText(tr("Failed to set the WPS PIN.")); 228 msg.exec(); 229 } 230} 231 232 233void Peers::ctx_refresh() 234{ 235 update_peers(); 236} 237 238 239void Peers::add_station(QString info) 240{ 241 QStringList lines = info.split(QRegExp("\\n")); 242 QString name; 243 244 for (QStringList::Iterator it = lines.begin(); 245 it != lines.end(); it++) { 246 int pos = (*it).indexOf('=') + 1; 247 if (pos < 1) 248 continue; 249 250 if ((*it).startsWith("wpsDeviceName=")) 251 name = (*it).mid(pos); 252 } 253 254 if (name.isEmpty()) 255 name = lines[0]; 256 257 QStandardItem *item = new QStandardItem(*laptop_icon, name); 258 if (item) { 259 item->setData(lines[0], peer_role_address); 260 item->setData(PEER_TYPE_ASSOCIATED_STATION, 261 peer_role_type); 262 item->setData(info, peer_role_details); 263 item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION)); 264 model.appendRow(item); 265 } 266} 267 268 269void Peers::add_stations() 270{ 271 char reply[2048]; 272 size_t reply_len; 273 char cmd[30]; 274 int res; 275 276 reply_len = sizeof(reply) - 1; 277 if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0) 278 return; 279 280 do { 281 reply[reply_len] = '\0'; 282 QString info(reply); 283 char *txt = reply; 284 while (*txt != '\0' && *txt != '\n') 285 txt++; 286 *txt++ = '\0'; 287 if (strncmp(reply, "FAIL", 4) == 0 || 288 strncmp(reply, "UNKNOWN", 7) == 0) 289 break; 290 291 add_station(info); 292 293 reply_len = sizeof(reply) - 1; 294 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); 295 res = wpagui->ctrlRequest(cmd, reply, &reply_len); 296 } while (res >= 0); 297} 298 299 300void Peers::add_single_station(const char *addr) 301{ 302 char reply[2048]; 303 size_t reply_len; 304 char cmd[30]; 305 306 reply_len = sizeof(reply) - 1; 307 snprintf(cmd, sizeof(cmd), "STA %s", addr); 308 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 309 return; 310 311 reply[reply_len] = '\0'; 312 QString info(reply); 313 char *txt = reply; 314 while (*txt != '\0' && *txt != '\n') 315 txt++; 316 *txt++ = '\0'; 317 if (strncmp(reply, "FAIL", 4) == 0 || 318 strncmp(reply, "UNKNOWN", 7) == 0) 319 return; 320 321 add_station(info); 322} 323 324 325void Peers::remove_bss(int id) 326{ 327 if (model.rowCount() == 0) 328 return; 329 330 QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, 331 id); 332 if (lst.size() == 0) 333 return; 334 model.removeRow(lst[0].row()); 335} 336 337 338bool Peers::add_bss(const char *cmd) 339{ 340 char reply[2048]; 341 size_t reply_len; 342 343 reply_len = sizeof(reply) - 1; 344 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 345 return false; 346 reply[reply_len] = '\0'; 347 348 QString bss(reply); 349 if (bss.isEmpty() || bss.startsWith("FAIL")) 350 return false; 351 352 QString ssid, bssid, flags, wps_name, pri_dev_type; 353 int id = -1; 354 355 QStringList lines = bss.split(QRegExp("\\n")); 356 for (QStringList::Iterator it = lines.begin(); 357 it != lines.end(); it++) { 358 int pos = (*it).indexOf('=') + 1; 359 if (pos < 1) 360 continue; 361 362 if ((*it).startsWith("bssid=")) 363 bssid = (*it).mid(pos); 364 else if ((*it).startsWith("id=")) 365 id = (*it).mid(pos).toInt(); 366 else if ((*it).startsWith("flags=")) 367 flags = (*it).mid(pos); 368 else if ((*it).startsWith("ssid=")) 369 ssid = (*it).mid(pos); 370 else if ((*it).startsWith("wps_device_name=")) 371 wps_name = (*it).mid(pos); 372 else if ((*it).startsWith("wps_primary_device_type=")) 373 pri_dev_type = (*it).mid(pos); 374 } 375 376 QString name = wps_name; 377 if (name.isEmpty()) 378 name = ssid + "\n" + bssid; 379 380 QStandardItem *item = new QStandardItem(*ap_icon, name); 381 if (item) { 382 item->setData(bssid, peer_role_address); 383 if (id >= 0) 384 item->setData(id, peer_role_bss_id); 385 int type; 386 if (flags.contains("[WPS")) 387 type = PEER_TYPE_AP_WPS; 388 else 389 type = PEER_TYPE_AP; 390 item->setData(type, peer_role_type); 391 392 for (int i = 0; i < lines.size(); i++) { 393 if (lines[i].length() > 60) { 394 lines[i].remove(60, lines[i].length()); 395 lines[i] += ".."; 396 } 397 } 398 item->setToolTip(ItemType(type)); 399 item->setData(lines.join("\n"), peer_role_details); 400 if (!pri_dev_type.isEmpty()) 401 item->setData(pri_dev_type, 402 peer_role_pri_dev_type); 403 if (!ssid.isEmpty()) 404 item->setData(ssid, peer_role_ssid); 405 model.appendRow(item); 406 } 407 408 return true; 409} 410 411 412void Peers::add_scan_results() 413{ 414 int index; 415 char cmd[20]; 416 417 index = 0; 418 while (wpagui) { 419 snprintf(cmd, sizeof(cmd), "BSS %d", index++); 420 if (index > 1000) 421 break; 422 423 if (!add_bss(cmd)) 424 break; 425 } 426} 427 428 429void Peers::update_peers() 430{ 431 model.clear(); 432 if (wpagui == NULL) 433 return; 434 435 char reply[20]; 436 size_t replylen = sizeof(reply) - 1; 437 wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); 438 439 add_stations(); 440 add_scan_results(); 441} 442 443 444QStandardItem * Peers::find_addr(QString addr) 445{ 446 if (model.rowCount() == 0) 447 return NULL; 448 449 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, 450 addr); 451 if (lst.size() == 0) 452 return NULL; 453 return model.itemFromIndex(lst[0]); 454} 455 456 457QStandardItem * Peers::find_uuid(QString uuid) 458{ 459 if (model.rowCount() == 0) 460 return NULL; 461 462 QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, 463 uuid); 464 if (lst.size() == 0) 465 return NULL; 466 return model.itemFromIndex(lst[0]); 467} 468 469 470void Peers::event_notify(WpaMsg msg) 471{ 472 QString text = msg.getMsg(); 473 474 if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { 475 /* 476 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 477 * 02:2a:c4:18:5b:f3 478 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] 479 */ 480 QStringList items = text.split(' '); 481 QString uuid = items[1]; 482 QString addr = items[2]; 483 QString name = ""; 484 485 QStandardItem *item = find_addr(addr); 486 if (item) 487 return; 488 489 int pos = text.indexOf('['); 490 if (pos >= 0) { 491 int pos2 = text.lastIndexOf(']'); 492 if (pos2 >= pos) { 493 items = text.mid(pos + 1, pos2 - pos - 1). 494 split('|'); 495 name = items[0]; 496 items.append(addr); 497 } 498 } 499 500 item = new QStandardItem(*laptop_icon, name); 501 if (item) { 502 item->setData(addr, peer_role_address); 503 item->setData(PEER_TYPE_WPS_PIN_NEEDED, 504 peer_role_type); 505 item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); 506 item->setData(items.join("\n"), peer_role_details); 507 item->setData(items[5], peer_role_pri_dev_type); 508 model.appendRow(item); 509 } 510 return; 511 } 512 513 if (text.startsWith(AP_STA_CONNECTED)) { 514 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ 515 QStringList items = text.split(' '); 516 QString addr = items[1]; 517 QStandardItem *item = find_addr(addr); 518 if (item == NULL || item->data(peer_role_type).toInt() != 519 PEER_TYPE_ASSOCIATED_STATION) 520 add_single_station(addr.toAscii().constData()); 521 return; 522 } 523 524 if (text.startsWith(AP_STA_DISCONNECTED)) { 525 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ 526 QStringList items = text.split(' '); 527 QString addr = items[1]; 528 529 if (model.rowCount() == 0) 530 return; 531 532 QModelIndexList lst = model.match(model.index(0, 0), 533 peer_role_address, addr); 534 for (int i = 0; i < lst.size(); i++) { 535 QStandardItem *item = model.itemFromIndex(lst[i]); 536 if (item && item->data(peer_role_type).toInt() == 537 PEER_TYPE_ASSOCIATED_STATION) 538 model.removeRow(lst[i].row()); 539 } 540 return; 541 } 542 543 if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { 544 /* 545 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 546 * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 547 * |Very friendly name|Company|Long description of the model| 548 * WAP|http://w1.fi/|http://w1.fi/hostapd/ 549 */ 550 QStringList items = text.split(' '); 551 if (items.size() < 5) 552 return; 553 QString uuid = items[1]; 554 QString addr = items[2]; 555 QString pri_dev_type = items[3].mid(13); 556 int wps_state = items[4].mid(10).toInt(); 557 558 int pos = text.indexOf('|'); 559 if (pos < 0) 560 return; 561 items = text.mid(pos + 1).split('|'); 562 if (items.size() < 1) 563 return; 564 565 QStandardItem *item = find_uuid(uuid); 566 if (item) 567 return; 568 569 item = new QStandardItem(*ap_icon, items[0]); 570 if (item) { 571 item->setData(uuid, peer_role_uuid); 572 item->setData(addr, peer_role_address); 573 int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: 574 PEER_TYPE_WPS_ER_AP_UNCONFIGURED; 575 item->setData(type, peer_role_type); 576 item->setToolTip(ItemType(type)); 577 item->setData(pri_dev_type, peer_role_pri_dev_type); 578 item->setData(items.join(QString("\n")), 579 peer_role_details); 580 model.appendRow(item); 581 } 582 583 return; 584 } 585 586 if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { 587 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ 588 QStringList items = text.split(' '); 589 if (items.size() < 2) 590 return; 591 if (model.rowCount() == 0) 592 return; 593 594 QModelIndexList lst = model.match(model.index(0, 0), 595 peer_role_uuid, items[1]); 596 for (int i = 0; i < lst.size(); i++) { 597 QStandardItem *item = model.itemFromIndex(lst[i]); 598 if (item && 599 (item->data(peer_role_type).toInt() == 600 PEER_TYPE_WPS_ER_AP || 601 item->data(peer_role_type).toInt() == 602 PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) 603 model.removeRow(lst[i].row()); 604 } 605 return; 606 } 607 608 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { 609 /* 610 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 611 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 612 * pri_dev_type=1-0050F204-1 613 * |Wireless Client|Company|cmodel|123|12345| 614 */ 615 QStringList items = text.split(' '); 616 if (items.size() < 3) 617 return; 618 QString uuid = items[1]; 619 QString addr = items[2]; 620 QString pri_dev_type = items[6].mid(13); 621 int config_methods = -1; 622 int dev_passwd_id = -1; 623 624 for (int i = 3; i < items.size(); i++) { 625 int pos = items[i].indexOf('=') + 1; 626 if (pos < 1) 627 continue; 628 QString val = items[i].mid(pos); 629 if (items[i].startsWith("config_methods=")) { 630 config_methods = val.toInt(0, 0); 631 } else if (items[i].startsWith("dev_passwd_id=")) { 632 dev_passwd_id = val.toInt(); 633 } 634 } 635 636 int pos = text.indexOf('|'); 637 if (pos < 0) 638 return; 639 items = text.mid(pos + 1).split('|'); 640 if (items.size() < 1) 641 return; 642 QString name = items[0]; 643 if (name.length() == 0) 644 name = addr; 645 646 remove_enrollee_uuid(uuid); 647 648 QStandardItem *item; 649 item = new QStandardItem(*laptop_icon, name); 650 if (item) { 651 item->setData(uuid, peer_role_uuid); 652 item->setData(addr, peer_role_address); 653 item->setData(PEER_TYPE_WPS_ER_ENROLLEE, 654 peer_role_type); 655 item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); 656 item->setData(items.join(QString("\n")), 657 peer_role_details); 658 item->setData(pri_dev_type, peer_role_pri_dev_type); 659 if (config_methods >= 0) 660 item->setData(config_methods, 661 peer_role_config_methods); 662 if (dev_passwd_id >= 0) 663 item->setData(dev_passwd_id, 664 peer_role_dev_passwd_id); 665 model.appendRow(item); 666 } 667 668 return; 669 } 670 671 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { 672 /* 673 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 674 * 02:66:a0:ee:17:27 675 */ 676 QStringList items = text.split(' '); 677 if (items.size() < 2) 678 return; 679 remove_enrollee_uuid(items[1]); 680 return; 681 } 682 683 if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { 684 /* TODO: need to time out this somehow or remove on successful 685 * WPS run, etc. */ 686 /* 687 * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 688 * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 689 * [Wireless Client] 690 * (MAC addr, UUID-E, pri dev type, config methods, 691 * dev passwd id, request type, [dev name]) 692 */ 693 QStringList items = text.split(' '); 694 if (items.size() < 7) 695 return; 696 QString addr = items[1]; 697 QString uuid = items[2]; 698 QString pri_dev_type = items[3]; 699 int config_methods = items[4].toInt(0, 0); 700 int dev_passwd_id = items[5].toInt(); 701 QString name; 702 703 int pos = text.indexOf('['); 704 if (pos >= 0) { 705 int pos2 = text.lastIndexOf(']'); 706 if (pos2 >= pos) { 707 QStringList items2 = 708 text.mid(pos + 1, pos2 - pos - 1). 709 split('|'); 710 name = items2[0]; 711 } 712 } 713 if (name.isEmpty()) 714 name = addr; 715 716 QStandardItem *item; 717 718 item = find_uuid(uuid); 719 if (item) { 720 QVariant var = item->data(peer_role_config_methods); 721 QVariant var2 = item->data(peer_role_dev_passwd_id); 722 if ((var.isValid() && config_methods != var.toInt()) || 723 (var2.isValid() && dev_passwd_id != var2.toInt())) 724 remove_enrollee_uuid(uuid); 725 else 726 return; 727 } 728 729 item = new QStandardItem(*laptop_icon, name); 730 if (item) { 731 item->setData(uuid, peer_role_uuid); 732 item->setData(addr, peer_role_address); 733 item->setData(PEER_TYPE_WPS_ENROLLEE, 734 peer_role_type); 735 item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); 736 item->setData(items.join(QString("\n")), 737 peer_role_details); 738 item->setData(pri_dev_type, peer_role_pri_dev_type); 739 item->setData(config_methods, 740 peer_role_config_methods); 741 item->setData(dev_passwd_id, peer_role_dev_passwd_id); 742 model.appendRow(item); 743 } 744 745 return; 746 } 747 748 if (text.startsWith(WPA_EVENT_BSS_ADDED)) { 749 /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ 750 QStringList items = text.split(' '); 751 if (items.size() < 2) 752 return; 753 char cmd[20]; 754 snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); 755 add_bss(cmd); 756 return; 757 } 758 759 if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { 760 /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ 761 QStringList items = text.split(' '); 762 if (items.size() < 2) 763 return; 764 remove_bss(items[1].toInt()); 765 return; 766 } 767} 768 769 770void Peers::closeEvent(QCloseEvent *) 771{ 772 if (wpagui) { 773 char reply[20]; 774 size_t replylen = sizeof(reply) - 1; 775 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); 776 } 777} 778 779 780void Peers::done(int r) 781{ 782 QDialog::done(r); 783 close(); 784} 785 786 787void Peers::remove_enrollee_uuid(QString uuid) 788{ 789 if (model.rowCount() == 0) 790 return; 791 792 QModelIndexList lst = model.match(model.index(0, 0), 793 peer_role_uuid, uuid); 794 for (int i = 0; i < lst.size(); i++) { 795 QStandardItem *item = model.itemFromIndex(lst[i]); 796 if (item == NULL) 797 continue; 798 int type = item->data(peer_role_type).toInt(); 799 if (type == PEER_TYPE_WPS_ER_ENROLLEE || 800 type == PEER_TYPE_WPS_ENROLLEE) 801 model.removeRow(lst[i].row()); 802 } 803} 804 805 806void Peers::properties() 807{ 808 if (ctx_item == NULL) 809 return; 810 811 QMessageBox msg(this); 812 msg.setStandardButtons(QMessageBox::Ok); 813 msg.setDefaultButton(QMessageBox::Ok); 814 msg.setEscapeButton(QMessageBox::Ok); 815 msg.setWindowTitle(tr("Peer Properties")); 816 817 int type = ctx_item->data(peer_role_type).toInt(); 818 QString title = Peers::ItemType(type); 819 820 msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); 821 822 QVariant var; 823 QString info; 824 825 var = ctx_item->data(peer_role_address); 826 if (var.isValid()) 827 info += tr("Address: ") + var.toString() + QString("\n"); 828 829 var = ctx_item->data(peer_role_uuid); 830 if (var.isValid()) 831 info += tr("UUID: ") + var.toString() + QString("\n"); 832 833 var = ctx_item->data(peer_role_pri_dev_type); 834 if (var.isValid()) 835 info += tr("Primary Device Type: ") + var.toString() + 836 QString("\n"); 837 838 var = ctx_item->data(peer_role_ssid); 839 if (var.isValid()) 840 info += tr("SSID: ") + var.toString() + QString("\n"); 841 842 var = ctx_item->data(peer_role_config_methods); 843 if (var.isValid()) { 844 int methods = var.toInt(); 845 info += tr("Configuration Methods: "); 846 if (methods & 0x0001) 847 info += tr("[USBA]"); 848 if (methods & 0x0002) 849 info += tr("[Ethernet]"); 850 if (methods & 0x0004) 851 info += tr("[Label]"); 852 if (methods & 0x0008) 853 info += tr("[Display]"); 854 if (methods & 0x0010) 855 info += tr("[Ext. NFC Token]"); 856 if (methods & 0x0020) 857 info += tr("[Int. NFC Token]"); 858 if (methods & 0x0040) 859 info += tr("[NFC Interface]"); 860 if (methods & 0x0080) 861 info += tr("[Push Button]"); 862 if (methods & 0x0100) 863 info += tr("[Keypad]"); 864 info += "\n"; 865 } 866 867 var = ctx_item->data(peer_role_dev_passwd_id); 868 if (var.isValid()) { 869 info += tr("Device Password ID: ") + var.toString(); 870 switch (var.toInt()) { 871 case 0: 872 info += tr(" (Default PIN)"); 873 break; 874 case 1: 875 info += tr(" (User-specified PIN)"); 876 break; 877 case 2: 878 info += tr(" (Machine-specified PIN)"); 879 break; 880 case 3: 881 info += tr(" (Rekey)"); 882 break; 883 case 4: 884 info += tr(" (Push Button)"); 885 break; 886 case 5: 887 info += tr(" (Registrar-specified)"); 888 break; 889 } 890 info += "\n"; 891 } 892 893 msg.setInformativeText(info); 894 895 var = ctx_item->data(peer_role_details); 896 if (var.isValid()) 897 msg.setDetailedText(var.toString()); 898 899 msg.exec(); 900} 901 902 903void Peers::connect_pbc() 904{ 905 if (ctx_item == NULL) 906 return; 907 908 char cmd[100]; 909 char reply[100]; 910 size_t reply_len; 911 912 int peer_type = ctx_item->data(peer_role_type).toInt(); 913 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { 914 snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", 915 ctx_item->data(peer_role_uuid).toString().toAscii(). 916 constData()); 917 } else { 918 snprintf(cmd, sizeof(cmd), "WPS_PBC"); 919 } 920 reply_len = sizeof(reply) - 1; 921 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 922 QMessageBox msg; 923 msg.setIcon(QMessageBox::Warning); 924 msg.setText(tr("Failed to start WPS PBC.")); 925 msg.exec(); 926 } 927} 928 929 930void Peers::learn_ap_config() 931{ 932 if (ctx_item == NULL) 933 return; 934 935 QString uuid = ctx_item->data(peer_role_uuid).toString(); 936 937 StringQuery input(tr("AP PIN:")); 938 input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); 939 if (input.exec() != QDialog::Accepted) 940 return; 941 942 char cmd[100]; 943 char reply[100]; 944 size_t reply_len; 945 946 snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", 947 uuid.toAscii().constData(), 948 input.get_string().toAscii().constData()); 949 reply_len = sizeof(reply) - 1; 950 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 951 QMessageBox msg; 952 msg.setIcon(QMessageBox::Warning); 953 msg.setText(tr("Failed to start learning AP configuration.")); 954 msg.exec(); 955 } 956} 957