1 /* 2 * wpa_gui - Peers class 3 * Copyright (c) 2009-2010, 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 25 enum { 26 peer_role_address = Qt::UserRole + 1, 27 peer_role_type, 28 peer_role_uuid, 29 peer_role_details, 30 peer_role_ifname, 31 peer_role_pri_dev_type, 32 peer_role_ssid, 33 peer_role_config_methods, 34 peer_role_dev_passwd_id, 35 peer_role_bss_id, 36 peer_role_selected_method, 37 peer_role_selected_pin, 38 peer_role_requested_method, 39 peer_role_network_id 40 }; 41 42 enum selected_method { 43 SEL_METHOD_NONE, 44 SEL_METHOD_PIN_PEER_DISPLAY, 45 SEL_METHOD_PIN_LOCAL_DISPLAY 46 }; 47 48 /* 49 * TODO: 50 * - add current AP info (e.g., from WPS) in station mode 51 */ 52 53 enum peer_type { 54 PEER_TYPE_ASSOCIATED_STATION, 55 PEER_TYPE_AP, 56 PEER_TYPE_AP_WPS, 57 PEER_TYPE_WPS_PIN_NEEDED, 58 PEER_TYPE_P2P, 59 PEER_TYPE_P2P_CLIENT, 60 PEER_TYPE_P2P_GROUP, 61 PEER_TYPE_P2P_PERSISTENT_GROUP_GO, 62 PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT, 63 PEER_TYPE_P2P_INVITATION, 64 PEER_TYPE_WPS_ER_AP, 65 PEER_TYPE_WPS_ER_AP_UNCONFIGURED, 66 PEER_TYPE_WPS_ER_ENROLLEE, 67 PEER_TYPE_WPS_ENROLLEE 68 }; 69 70 71 Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags) 72 : QDialog(parent) 73 { 74 setupUi(this); 75 76 if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) 77 { 78 default_icon = new QIcon(":/icons/wpa_gui.svg"); 79 ap_icon = new QIcon(":/icons/ap.svg"); 80 laptop_icon = new QIcon(":/icons/laptop.svg"); 81 group_icon = new QIcon(":/icons/group.svg"); 82 invitation_icon = new QIcon(":/icons/invitation.svg"); 83 } else { 84 default_icon = new QIcon(":/icons/wpa_gui.png"); 85 ap_icon = new QIcon(":/icons/ap.png"); 86 laptop_icon = new QIcon(":/icons/laptop.png"); 87 group_icon = new QIcon(":/icons/group.png"); 88 invitation_icon = new QIcon(":/icons/invitation.png"); 89 } 90 91 peers->setModel(&model); 92 peers->setResizeMode(QListView::Adjust); 93 peers->setDragEnabled(false); 94 peers->setSelectionMode(QAbstractItemView::NoSelection); 95 96 peers->setContextMenuPolicy(Qt::CustomContextMenu); 97 connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)), 98 this, SLOT(context_menu(const QPoint &))); 99 100 wpagui = NULL; 101 hide_ap = false; 102 } 103 104 105 void Peers::setWpaGui(WpaGui *_wpagui) 106 { 107 wpagui = _wpagui; 108 update_peers(); 109 } 110 111 112 Peers::~Peers() 113 { 114 delete default_icon; 115 delete ap_icon; 116 delete laptop_icon; 117 delete group_icon; 118 delete invitation_icon; 119 } 120 121 122 void Peers::languageChange() 123 { 124 retranslateUi(this); 125 } 126 127 128 QString Peers::ItemType(int type) 129 { 130 QString title; 131 switch (type) { 132 case PEER_TYPE_ASSOCIATED_STATION: 133 title = tr("Associated station"); 134 break; 135 case PEER_TYPE_AP: 136 title = tr("AP"); 137 break; 138 case PEER_TYPE_AP_WPS: 139 title = tr("WPS AP"); 140 break; 141 case PEER_TYPE_WPS_PIN_NEEDED: 142 title = tr("WPS PIN needed"); 143 break; 144 case PEER_TYPE_P2P: 145 title = tr("P2P Device"); 146 break; 147 case PEER_TYPE_P2P_CLIENT: 148 title = tr("P2P Device (group client)"); 149 break; 150 case PEER_TYPE_P2P_GROUP: 151 title = tr("P2P Group"); 152 break; 153 case PEER_TYPE_P2P_PERSISTENT_GROUP_GO: 154 title = tr("P2P Persistent Group (GO)"); 155 break; 156 case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT: 157 title = tr("P2P Persistent Group (client)"); 158 break; 159 case PEER_TYPE_P2P_INVITATION: 160 title = tr("P2P Invitation"); 161 break; 162 case PEER_TYPE_WPS_ER_AP: 163 title = tr("ER: WPS AP"); 164 break; 165 case PEER_TYPE_WPS_ER_AP_UNCONFIGURED: 166 title = tr("ER: WPS AP (Unconfigured)"); 167 break; 168 case PEER_TYPE_WPS_ER_ENROLLEE: 169 title = tr("ER: WPS Enrollee"); 170 break; 171 case PEER_TYPE_WPS_ENROLLEE: 172 title = tr("WPS Enrollee"); 173 break; 174 } 175 return title; 176 } 177 178 179 void Peers::context_menu(const QPoint &pos) 180 { 181 QMenu *menu = new QMenu; 182 if (menu == NULL) 183 return; 184 185 QModelIndex idx = peers->indexAt(pos); 186 if (idx.isValid()) { 187 ctx_item = model.itemFromIndex(idx); 188 int type = ctx_item->data(peer_role_type).toInt(); 189 menu->addAction(Peers::ItemType(type))->setEnabled(false); 190 menu->addSeparator(); 191 192 int config_methods = -1; 193 QVariant var = ctx_item->data(peer_role_config_methods); 194 if (var.isValid()) 195 config_methods = var.toInt(); 196 197 enum selected_method method = SEL_METHOD_NONE; 198 var = ctx_item->data(peer_role_selected_method); 199 if (var.isValid()) 200 method = (enum selected_method) var.toInt(); 201 202 if ((type == PEER_TYPE_ASSOCIATED_STATION || 203 type == PEER_TYPE_AP_WPS || 204 type == PEER_TYPE_WPS_PIN_NEEDED || 205 type == PEER_TYPE_WPS_ER_ENROLLEE || 206 type == PEER_TYPE_WPS_ENROLLEE) && 207 (config_methods == -1 || (config_methods & 0x010c))) { 208 menu->addAction(tr("Enter WPS PIN"), this, 209 SLOT(enter_pin())); 210 } 211 212 if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) { 213 menu->addAction(tr("P2P Connect"), this, 214 SLOT(ctx_p2p_connect())); 215 if (method == SEL_METHOD_NONE && 216 config_methods > -1 && 217 config_methods & 0x0080 /* PBC */ && 218 config_methods != 0x0080) 219 menu->addAction(tr("P2P Connect (PBC)"), this, 220 SLOT(connect_pbc())); 221 if (method == SEL_METHOD_NONE) { 222 menu->addAction(tr("P2P Request PIN"), this, 223 SLOT(ctx_p2p_req_pin())); 224 menu->addAction(tr("P2P Show PIN"), this, 225 SLOT(ctx_p2p_show_pin())); 226 } 227 228 if (config_methods > -1 && (config_methods & 0x0100)) { 229 /* Peer has Keypad */ 230 menu->addAction(tr("P2P Display PIN"), this, 231 SLOT(ctx_p2p_display_pin())); 232 } 233 234 if (config_methods > -1 && (config_methods & 0x000c)) { 235 /* Peer has Label or Display */ 236 menu->addAction(tr("P2P Enter PIN"), this, 237 SLOT(ctx_p2p_enter_pin())); 238 } 239 } 240 241 if (type == PEER_TYPE_P2P_GROUP) { 242 menu->addAction(tr("Show passphrase"), this, 243 SLOT(ctx_p2p_show_passphrase())); 244 menu->addAction(tr("Remove P2P Group"), this, 245 SLOT(ctx_p2p_remove_group())); 246 } 247 248 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || 249 type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT || 250 type == PEER_TYPE_P2P_INVITATION) { 251 menu->addAction(tr("Start group"), this, 252 SLOT(ctx_p2p_start_persistent())); 253 } 254 255 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || 256 type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) { 257 menu->addAction(tr("Invite"), this, 258 SLOT(ctx_p2p_invite())); 259 } 260 261 if (type == PEER_TYPE_P2P_INVITATION) { 262 menu->addAction(tr("Ignore"), this, 263 SLOT(ctx_p2p_delete())); 264 } 265 266 if (type == PEER_TYPE_AP_WPS) { 267 menu->addAction(tr("Connect (PBC)"), this, 268 SLOT(connect_pbc())); 269 } 270 271 if ((type == PEER_TYPE_ASSOCIATED_STATION || 272 type == PEER_TYPE_WPS_ER_ENROLLEE || 273 type == PEER_TYPE_WPS_ENROLLEE) && 274 config_methods >= 0 && (config_methods & 0x0080)) { 275 menu->addAction(tr("Enroll (PBC)"), this, 276 SLOT(connect_pbc())); 277 } 278 279 if (type == PEER_TYPE_WPS_ER_AP) { 280 menu->addAction(tr("Learn Configuration"), this, 281 SLOT(learn_ap_config())); 282 } 283 284 menu->addAction(tr("Properties"), this, SLOT(properties())); 285 } else { 286 ctx_item = NULL; 287 menu->addAction(QString(tr("Refresh")), this, 288 SLOT(ctx_refresh())); 289 menu->addAction(tr("Start P2P discovery"), this, 290 SLOT(ctx_p2p_start())); 291 menu->addAction(tr("Stop P2P discovery"), this, 292 SLOT(ctx_p2p_stop())); 293 menu->addAction(tr("P2P listen only"), this, 294 SLOT(ctx_p2p_listen())); 295 menu->addAction(tr("Start P2P group"), this, 296 SLOT(ctx_p2p_start_group())); 297 if (hide_ap) 298 menu->addAction(tr("Show AP entries"), this, 299 SLOT(ctx_show_ap())); 300 else 301 menu->addAction(tr("Hide AP entries"), this, 302 SLOT(ctx_hide_ap())); 303 } 304 305 menu->exec(peers->mapToGlobal(pos)); 306 } 307 308 309 void Peers::enter_pin() 310 { 311 if (ctx_item == NULL) 312 return; 313 314 int peer_type = ctx_item->data(peer_role_type).toInt(); 315 QString uuid; 316 QString addr; 317 addr = ctx_item->data(peer_role_address).toString(); 318 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) 319 uuid = ctx_item->data(peer_role_uuid).toString(); 320 321 StringQuery input(tr("PIN:")); 322 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 323 if (input.exec() != QDialog::Accepted) 324 return; 325 326 char cmd[100]; 327 char reply[100]; 328 size_t reply_len; 329 330 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { 331 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s", 332 uuid.toAscii().constData(), 333 input.get_string().toAscii().constData(), 334 addr.toAscii().constData()); 335 } else { 336 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", 337 addr.toAscii().constData(), 338 input.get_string().toAscii().constData()); 339 } 340 reply_len = sizeof(reply) - 1; 341 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 342 QMessageBox msg; 343 msg.setIcon(QMessageBox::Warning); 344 msg.setText(tr("Failed to set the WPS PIN.")); 345 msg.exec(); 346 } 347 } 348 349 350 void Peers::ctx_refresh() 351 { 352 update_peers(); 353 } 354 355 356 void Peers::ctx_p2p_start() 357 { 358 char reply[20]; 359 size_t reply_len; 360 reply_len = sizeof(reply) - 1; 361 if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 || 362 memcmp(reply, "FAIL", 4) == 0) { 363 QMessageBox msg; 364 msg.setIcon(QMessageBox::Warning); 365 msg.setText("Failed to start P2P discovery."); 366 msg.exec(); 367 } 368 } 369 370 371 void Peers::ctx_p2p_stop() 372 { 373 char reply[20]; 374 size_t reply_len; 375 reply_len = sizeof(reply) - 1; 376 wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len); 377 } 378 379 380 void Peers::ctx_p2p_listen() 381 { 382 char reply[20]; 383 size_t reply_len; 384 reply_len = sizeof(reply) - 1; 385 if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 || 386 memcmp(reply, "FAIL", 4) == 0) { 387 QMessageBox msg; 388 msg.setIcon(QMessageBox::Warning); 389 msg.setText("Failed to start P2P listen."); 390 msg.exec(); 391 } 392 } 393 394 395 void Peers::ctx_p2p_start_group() 396 { 397 char reply[20]; 398 size_t reply_len; 399 reply_len = sizeof(reply) - 1; 400 if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 || 401 memcmp(reply, "FAIL", 4) == 0) { 402 QMessageBox msg; 403 msg.setIcon(QMessageBox::Warning); 404 msg.setText("Failed to start P2P group."); 405 msg.exec(); 406 } 407 } 408 409 410 void Peers::add_station(QString info) 411 { 412 QStringList lines = info.split(QRegExp("\\n")); 413 QString name; 414 415 for (QStringList::Iterator it = lines.begin(); 416 it != lines.end(); it++) { 417 int pos = (*it).indexOf('=') + 1; 418 if (pos < 1) 419 continue; 420 421 if ((*it).startsWith("wpsDeviceName=")) 422 name = (*it).mid(pos); 423 else if ((*it).startsWith("p2p_device_name=")) 424 name = (*it).mid(pos); 425 } 426 427 if (name.isEmpty()) 428 name = lines[0]; 429 430 QStandardItem *item = new QStandardItem(*laptop_icon, name); 431 if (item) { 432 /* Remove WPS enrollee entry if one is still pending */ 433 if (model.rowCount() > 0) { 434 QModelIndexList lst = model.match(model.index(0, 0), 435 peer_role_address, 436 lines[0]); 437 for (int i = 0; i < lst.size(); i++) { 438 QStandardItem *item; 439 item = model.itemFromIndex(lst[i]); 440 if (item == NULL) 441 continue; 442 int type = item->data(peer_role_type).toInt(); 443 if (type == PEER_TYPE_WPS_ENROLLEE) { 444 model.removeRow(lst[i].row()); 445 break; 446 } 447 } 448 } 449 450 item->setData(lines[0], peer_role_address); 451 item->setData(PEER_TYPE_ASSOCIATED_STATION, 452 peer_role_type); 453 item->setData(info, peer_role_details); 454 item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION)); 455 model.appendRow(item); 456 } 457 } 458 459 460 void Peers::add_stations() 461 { 462 char reply[2048]; 463 size_t reply_len; 464 char cmd[30]; 465 int res; 466 467 reply_len = sizeof(reply) - 1; 468 if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0) 469 return; 470 471 do { 472 reply[reply_len] = '\0'; 473 QString info(reply); 474 char *txt = reply; 475 while (*txt != '\0' && *txt != '\n') 476 txt++; 477 *txt++ = '\0'; 478 if (strncmp(reply, "FAIL", 4) == 0 || 479 strncmp(reply, "UNKNOWN", 7) == 0) 480 break; 481 482 add_station(info); 483 484 reply_len = sizeof(reply) - 1; 485 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); 486 res = wpagui->ctrlRequest(cmd, reply, &reply_len); 487 } while (res >= 0); 488 } 489 490 491 void Peers::add_single_station(const char *addr) 492 { 493 char reply[2048]; 494 size_t reply_len; 495 char cmd[30]; 496 497 reply_len = sizeof(reply) - 1; 498 snprintf(cmd, sizeof(cmd), "STA %s", addr); 499 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 500 return; 501 502 reply[reply_len] = '\0'; 503 QString info(reply); 504 char *txt = reply; 505 while (*txt != '\0' && *txt != '\n') 506 txt++; 507 *txt++ = '\0'; 508 if (strncmp(reply, "FAIL", 4) == 0 || 509 strncmp(reply, "UNKNOWN", 7) == 0) 510 return; 511 512 add_station(info); 513 } 514 515 516 void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params) 517 { 518 /* 519 * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0 520 * dev_type=1-0050f204-1 dev_name='Wireless Client' 521 * config_methods=0x8c 522 */ 523 524 QStringList items = 525 params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); 526 QString addr = ""; 527 QString name = ""; 528 int config_methods = 0; 529 QString dev_type; 530 531 for (int i = 0; i < items.size(); i++) { 532 QString str = items.at(i); 533 int pos = str.indexOf('=') + 1; 534 if (str.startsWith("dev_name='")) 535 name = str.section('\'', 1, -2); 536 else if (str.startsWith("config_methods=")) 537 config_methods = 538 str.section('=', 1).toInt(0, 0); 539 else if (str.startsWith("dev=")) 540 addr = str.mid(pos); 541 else if (str.startsWith("dev_type=") && dev_type.isEmpty()) 542 dev_type = str.mid(pos); 543 } 544 545 QStandardItem *item = find_addr(addr); 546 if (item) 547 return; 548 549 item = new QStandardItem(*default_icon, name); 550 if (item) { 551 /* TODO: indicate somehow the relationship to the group owner 552 * (parent) */ 553 item->setData(addr, peer_role_address); 554 item->setData(config_methods, peer_role_config_methods); 555 item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type); 556 if (!dev_type.isEmpty()) 557 item->setData(dev_type, peer_role_pri_dev_type); 558 item->setData(items.join(QString("\n")), peer_role_details); 559 item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT)); 560 model.appendRow(item); 561 } 562 } 563 564 565 void Peers::remove_bss(int id) 566 { 567 if (model.rowCount() == 0) 568 return; 569 570 QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, 571 id); 572 if (lst.size() == 0) 573 return; 574 model.removeRow(lst[0].row()); 575 } 576 577 578 bool Peers::add_bss(const char *cmd) 579 { 580 char reply[2048]; 581 size_t reply_len; 582 583 if (hide_ap) 584 return false; 585 586 reply_len = sizeof(reply) - 1; 587 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 588 return false; 589 reply[reply_len] = '\0'; 590 591 QString bss(reply); 592 if (bss.isEmpty() || bss.startsWith("FAIL")) 593 return false; 594 595 QString ssid, bssid, flags, wps_name, pri_dev_type; 596 int id = -1; 597 598 QStringList lines = bss.split(QRegExp("\\n")); 599 for (QStringList::Iterator it = lines.begin(); 600 it != lines.end(); it++) { 601 int pos = (*it).indexOf('=') + 1; 602 if (pos < 1) 603 continue; 604 605 if ((*it).startsWith("bssid=")) 606 bssid = (*it).mid(pos); 607 else if ((*it).startsWith("id=")) 608 id = (*it).mid(pos).toInt(); 609 else if ((*it).startsWith("flags=")) 610 flags = (*it).mid(pos); 611 else if ((*it).startsWith("ssid=")) 612 ssid = (*it).mid(pos); 613 else if ((*it).startsWith("wps_device_name=")) 614 wps_name = (*it).mid(pos); 615 else if ((*it).startsWith("wps_primary_device_type=")) 616 pri_dev_type = (*it).mid(pos); 617 } 618 619 QString name = wps_name; 620 if (name.isEmpty()) 621 name = ssid + "\n" + bssid; 622 623 QStandardItem *item = new QStandardItem(*ap_icon, name); 624 if (item) { 625 item->setData(bssid, peer_role_address); 626 if (id >= 0) 627 item->setData(id, peer_role_bss_id); 628 int type; 629 if (flags.contains("[WPS")) 630 type = PEER_TYPE_AP_WPS; 631 else 632 type = PEER_TYPE_AP; 633 item->setData(type, peer_role_type); 634 635 for (int i = 0; i < lines.size(); i++) { 636 if (lines[i].length() > 60) { 637 lines[i].remove(60, lines[i].length()); 638 lines[i] += ".."; 639 } 640 } 641 item->setToolTip(ItemType(type)); 642 item->setData(lines.join("\n"), peer_role_details); 643 if (!pri_dev_type.isEmpty()) 644 item->setData(pri_dev_type, 645 peer_role_pri_dev_type); 646 if (!ssid.isEmpty()) 647 item->setData(ssid, peer_role_ssid); 648 model.appendRow(item); 649 650 lines = bss.split(QRegExp("\\n")); 651 for (QStringList::Iterator it = lines.begin(); 652 it != lines.end(); it++) { 653 if ((*it).startsWith("p2p_group_client:")) 654 add_p2p_group_client(item, 655 (*it).mid(18)); 656 } 657 } 658 659 return true; 660 } 661 662 663 void Peers::add_scan_results() 664 { 665 int index; 666 char cmd[20]; 667 668 index = 0; 669 while (wpagui) { 670 snprintf(cmd, sizeof(cmd), "BSS %d", index++); 671 if (index > 1000) 672 break; 673 674 if (!add_bss(cmd)) 675 break; 676 } 677 } 678 679 680 void Peers::add_persistent(int id, const char *ssid, const char *bssid) 681 { 682 char cmd[100]; 683 char reply[100]; 684 size_t reply_len; 685 int mode; 686 687 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id); 688 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 689 return; 690 reply[reply_len] = '\0'; 691 mode = atoi(reply); 692 693 QString name = ssid; 694 name = '[' + name + ']'; 695 696 QStandardItem *item = new QStandardItem(*group_icon, name); 697 if (!item) 698 return; 699 700 int type; 701 if (mode == 3) 702 type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO; 703 else 704 type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT; 705 item->setData(type, peer_role_type); 706 item->setToolTip(ItemType(type)); 707 item->setData(ssid, peer_role_ssid); 708 if (bssid && strcmp(bssid, "any") == 0) 709 bssid = NULL; 710 if (bssid) 711 item->setData(bssid, peer_role_address); 712 item->setData(id, peer_role_network_id); 713 item->setBackground(Qt::BDiagPattern); 714 715 model.appendRow(item); 716 } 717 718 719 void Peers::add_persistent_groups() 720 { 721 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; 722 size_t len; 723 724 len = sizeof(buf) - 1; 725 if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 726 return; 727 728 buf[len] = '\0'; 729 start = strchr(buf, '\n'); 730 if (start == NULL) 731 return; 732 start++; 733 734 while (*start) { 735 bool last = false; 736 end = strchr(start, '\n'); 737 if (end == NULL) { 738 last = true; 739 end = start; 740 while (end[0] && end[1]) 741 end++; 742 } 743 *end = '\0'; 744 745 id = start; 746 ssid = strchr(id, '\t'); 747 if (ssid == NULL) 748 break; 749 *ssid++ = '\0'; 750 bssid = strchr(ssid, '\t'); 751 if (bssid == NULL) 752 break; 753 *bssid++ = '\0'; 754 flags = strchr(bssid, '\t'); 755 if (flags == NULL) 756 break; 757 *flags++ = '\0'; 758 759 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) 760 add_persistent(atoi(id), ssid, bssid); 761 762 if (last) 763 break; 764 start = end + 1; 765 } 766 } 767 768 769 void Peers::update_peers() 770 { 771 model.clear(); 772 if (wpagui == NULL) 773 return; 774 775 char reply[20]; 776 size_t replylen = sizeof(reply) - 1; 777 wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); 778 779 add_stations(); 780 add_scan_results(); 781 add_persistent_groups(); 782 } 783 784 785 QStandardItem * Peers::find_addr(QString addr) 786 { 787 if (model.rowCount() == 0) 788 return NULL; 789 790 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, 791 addr); 792 if (lst.size() == 0) 793 return NULL; 794 return model.itemFromIndex(lst[0]); 795 } 796 797 798 QStandardItem * Peers::find_addr_type(QString addr, int type) 799 { 800 if (model.rowCount() == 0) 801 return NULL; 802 803 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, 804 addr); 805 for (int i = 0; i < lst.size(); i++) { 806 QStandardItem *item = model.itemFromIndex(lst[i]); 807 if (item->data(peer_role_type).toInt() == type) 808 return item; 809 } 810 return NULL; 811 } 812 813 814 QStandardItem * Peers::find_uuid(QString uuid) 815 { 816 if (model.rowCount() == 0) 817 return NULL; 818 819 QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, 820 uuid); 821 if (lst.size() == 0) 822 return NULL; 823 return model.itemFromIndex(lst[0]); 824 } 825 826 827 void Peers::event_notify(WpaMsg msg) 828 { 829 QString text = msg.getMsg(); 830 831 if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { 832 /* 833 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 834 * 02:2a:c4:18:5b:f3 835 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] 836 */ 837 QStringList items = text.split(' '); 838 QString uuid = items[1]; 839 QString addr = items[2]; 840 QString name = ""; 841 842 QStandardItem *item = find_addr(addr); 843 if (item) 844 return; 845 846 int pos = text.indexOf('['); 847 if (pos >= 0) { 848 int pos2 = text.lastIndexOf(']'); 849 if (pos2 >= pos) { 850 items = text.mid(pos + 1, pos2 - pos - 1). 851 split('|'); 852 name = items[0]; 853 items.append(addr); 854 } 855 } 856 857 item = new QStandardItem(*laptop_icon, name); 858 if (item) { 859 item->setData(addr, peer_role_address); 860 item->setData(PEER_TYPE_WPS_PIN_NEEDED, 861 peer_role_type); 862 item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); 863 item->setData(items.join("\n"), peer_role_details); 864 item->setData(items[5], peer_role_pri_dev_type); 865 model.appendRow(item); 866 } 867 return; 868 } 869 870 if (text.startsWith(AP_STA_CONNECTED)) { 871 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ 872 QStringList items = text.split(' '); 873 QString addr = items[1]; 874 QStandardItem *item = find_addr(addr); 875 if (item == NULL || item->data(peer_role_type).toInt() != 876 PEER_TYPE_ASSOCIATED_STATION) 877 add_single_station(addr.toAscii().constData()); 878 return; 879 } 880 881 if (text.startsWith(AP_STA_DISCONNECTED)) { 882 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ 883 QStringList items = text.split(' '); 884 QString addr = items[1]; 885 886 if (model.rowCount() == 0) 887 return; 888 889 QModelIndexList lst = model.match(model.index(0, 0), 890 peer_role_address, addr, -1); 891 for (int i = 0; i < lst.size(); i++) { 892 QStandardItem *item = model.itemFromIndex(lst[i]); 893 if (item && item->data(peer_role_type).toInt() == 894 PEER_TYPE_ASSOCIATED_STATION) { 895 model.removeRow(lst[i].row()); 896 break; 897 } 898 } 899 return; 900 } 901 902 if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) { 903 /* 904 * P2P-DEVICE-FOUND 02:b5:64:63:30:63 905 * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1 906 * name='Wireless Client' config_methods=0x84 dev_capab=0x21 907 * group_capab=0x0 908 */ 909 QStringList items = 910 text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); 911 QString addr = items[1]; 912 QString name = ""; 913 QString pri_dev_type; 914 int config_methods = 0; 915 for (int i = 0; i < items.size(); i++) { 916 QString str = items.at(i); 917 if (str.startsWith("name='")) 918 name = str.section('\'', 1, -2); 919 else if (str.startsWith("config_methods=")) 920 config_methods = 921 str.section('=', 1).toInt(0, 0); 922 else if (str.startsWith("pri_dev_type=")) 923 pri_dev_type = str.section('=', 1); 924 } 925 926 QStandardItem *item = find_addr(addr); 927 if (item) { 928 int type = item->data(peer_role_type).toInt(); 929 if (type == PEER_TYPE_P2P) 930 return; 931 } 932 933 item = new QStandardItem(*default_icon, name); 934 if (item) { 935 item->setData(addr, peer_role_address); 936 item->setData(config_methods, 937 peer_role_config_methods); 938 item->setData(PEER_TYPE_P2P, peer_role_type); 939 if (!pri_dev_type.isEmpty()) 940 item->setData(pri_dev_type, 941 peer_role_pri_dev_type); 942 item->setData(items.join(QString("\n")), 943 peer_role_details); 944 item->setToolTip(ItemType(PEER_TYPE_P2P)); 945 model.appendRow(item); 946 } 947 948 item = find_addr_type(addr, 949 PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT); 950 if (item) 951 item->setBackground(Qt::NoBrush); 952 } 953 954 if (text.startsWith(P2P_EVENT_GROUP_STARTED)) { 955 /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F" 956 * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7 957 * [PERSISTENT] */ 958 QStringList items = text.split(' '); 959 if (items.size() < 4) 960 return; 961 962 int pos = text.indexOf(" ssid=\""); 963 if (pos < 0) 964 return; 965 QString ssid = text.mid(pos + 7); 966 pos = ssid.indexOf(" passphrase=\""); 967 if (pos < 0) 968 pos = ssid.indexOf(" psk="); 969 if (pos >= 0) 970 ssid.truncate(pos); 971 pos = ssid.lastIndexOf('"'); 972 if (pos >= 0) 973 ssid.truncate(pos); 974 975 QStandardItem *item = new QStandardItem(*group_icon, ssid); 976 if (item) { 977 item->setData(PEER_TYPE_P2P_GROUP, peer_role_type); 978 item->setData(items[1], peer_role_ifname); 979 QString details; 980 if (items[2] == "GO") { 981 details = tr("P2P GO for interface ") + 982 items[1]; 983 } else { 984 details = tr("P2P client for interface ") + 985 items[1]; 986 } 987 if (text.contains(" [PERSISTENT]")) 988 details += "\nPersistent group"; 989 item->setData(details, peer_role_details); 990 item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP)); 991 model.appendRow(item); 992 } 993 } 994 995 if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) { 996 /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */ 997 QStringList items = text.split(' '); 998 if (items.size() < 2) 999 return; 1000 1001 if (model.rowCount() == 0) 1002 return; 1003 1004 QModelIndexList lst = model.match(model.index(0, 0), 1005 peer_role_ifname, items[1]); 1006 for (int i = 0; i < lst.size(); i++) 1007 model.removeRow(lst[i].row()); 1008 return; 1009 } 1010 1011 if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) { 1012 /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */ 1013 QStringList items = text.split(' '); 1014 if (items.size() < 3) 1015 return; 1016 QString addr = items[1]; 1017 QString pin = items[2]; 1018 1019 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); 1020 if (item == NULL) 1021 return; 1022 item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, 1023 peer_role_selected_method); 1024 item->setData(pin, peer_role_selected_pin); 1025 QVariant var = item->data(peer_role_requested_method); 1026 if (var.isValid() && 1027 var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) { 1028 ctx_item = item; 1029 ctx_p2p_display_pin_pd(); 1030 } 1031 return; 1032 } 1033 1034 if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) { 1035 /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */ 1036 QStringList items = text.split(' '); 1037 if (items.size() < 2) 1038 return; 1039 QString addr = items[1]; 1040 1041 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); 1042 if (item == NULL) 1043 return; 1044 item->setData(SEL_METHOD_PIN_PEER_DISPLAY, 1045 peer_role_selected_method); 1046 QVariant var = item->data(peer_role_requested_method); 1047 if (var.isValid() && 1048 var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) { 1049 ctx_item = item; 1050 ctx_p2p_connect(); 1051 } 1052 return; 1053 } 1054 1055 if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) { 1056 /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */ 1057 QStringList items = text.split(' '); 1058 if (items.size() < 3) 1059 return; 1060 if (!items[1].startsWith("sa=") || 1061 !items[2].startsWith("persistent=")) 1062 return; 1063 QString addr = items[1].mid(3); 1064 int id = items[2].mid(11).toInt(); 1065 1066 char cmd[100]; 1067 char reply[100]; 1068 size_t reply_len; 1069 1070 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id); 1071 reply_len = sizeof(reply) - 1; 1072 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 1073 return; 1074 reply[reply_len] = '\0'; 1075 QString name; 1076 char *pos = strrchr(reply, '"'); 1077 if (pos && reply[0] == '"') { 1078 *pos = '\0'; 1079 name = reply + 1; 1080 } else 1081 name = reply; 1082 1083 QStandardItem *item; 1084 item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION); 1085 if (item) 1086 model.removeRow(item->row()); 1087 1088 item = new QStandardItem(*invitation_icon, name); 1089 if (!item) 1090 return; 1091 item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type); 1092 item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION)); 1093 item->setData(addr, peer_role_address); 1094 item->setData(id, peer_role_network_id); 1095 1096 model.appendRow(item); 1097 1098 enable_persistent(id); 1099 1100 return; 1101 } 1102 1103 if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) { 1104 /* P2P-INVITATION-RESULT status=1 */ 1105 /* TODO */ 1106 return; 1107 } 1108 1109 if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { 1110 /* 1111 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 1112 * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 1113 * |Very friendly name|Company|Long description of the model| 1114 * WAP|http://w1.fi/|http://w1.fi/hostapd/ 1115 */ 1116 QStringList items = text.split(' '); 1117 if (items.size() < 5) 1118 return; 1119 QString uuid = items[1]; 1120 QString addr = items[2]; 1121 QString pri_dev_type = items[3].mid(13); 1122 int wps_state = items[4].mid(10).toInt(); 1123 1124 int pos = text.indexOf('|'); 1125 if (pos < 0) 1126 return; 1127 items = text.mid(pos + 1).split('|'); 1128 if (items.size() < 1) 1129 return; 1130 1131 QStandardItem *item = find_uuid(uuid); 1132 if (item) 1133 return; 1134 1135 item = new QStandardItem(*ap_icon, items[0]); 1136 if (item) { 1137 item->setData(uuid, peer_role_uuid); 1138 item->setData(addr, peer_role_address); 1139 int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: 1140 PEER_TYPE_WPS_ER_AP_UNCONFIGURED; 1141 item->setData(type, peer_role_type); 1142 item->setToolTip(ItemType(type)); 1143 item->setData(pri_dev_type, peer_role_pri_dev_type); 1144 item->setData(items.join(QString("\n")), 1145 peer_role_details); 1146 model.appendRow(item); 1147 } 1148 1149 return; 1150 } 1151 1152 if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { 1153 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ 1154 QStringList items = text.split(' '); 1155 if (items.size() < 2) 1156 return; 1157 if (model.rowCount() == 0) 1158 return; 1159 1160 QModelIndexList lst = model.match(model.index(0, 0), 1161 peer_role_uuid, items[1]); 1162 for (int i = 0; i < lst.size(); i++) { 1163 QStandardItem *item = model.itemFromIndex(lst[i]); 1164 if (item && 1165 (item->data(peer_role_type).toInt() == 1166 PEER_TYPE_WPS_ER_AP || 1167 item->data(peer_role_type).toInt() == 1168 PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) 1169 model.removeRow(lst[i].row()); 1170 } 1171 return; 1172 } 1173 1174 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { 1175 /* 1176 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 1177 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 1178 * pri_dev_type=1-0050F204-1 1179 * |Wireless Client|Company|cmodel|123|12345| 1180 */ 1181 QStringList items = text.split(' '); 1182 if (items.size() < 3) 1183 return; 1184 QString uuid = items[1]; 1185 QString addr = items[2]; 1186 QString pri_dev_type = items[6].mid(13); 1187 int config_methods = -1; 1188 int dev_passwd_id = -1; 1189 1190 for (int i = 3; i < items.size(); i++) { 1191 int pos = items[i].indexOf('=') + 1; 1192 if (pos < 1) 1193 continue; 1194 QString val = items[i].mid(pos); 1195 if (items[i].startsWith("config_methods=")) { 1196 config_methods = val.toInt(0, 0); 1197 } else if (items[i].startsWith("dev_passwd_id=")) { 1198 dev_passwd_id = val.toInt(); 1199 } 1200 } 1201 1202 int pos = text.indexOf('|'); 1203 if (pos < 0) 1204 return; 1205 items = text.mid(pos + 1).split('|'); 1206 if (items.size() < 1) 1207 return; 1208 QString name = items[0]; 1209 if (name.length() == 0) 1210 name = addr; 1211 1212 remove_enrollee_uuid(uuid); 1213 1214 QStandardItem *item; 1215 item = new QStandardItem(*laptop_icon, name); 1216 if (item) { 1217 item->setData(uuid, peer_role_uuid); 1218 item->setData(addr, peer_role_address); 1219 item->setData(PEER_TYPE_WPS_ER_ENROLLEE, 1220 peer_role_type); 1221 item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); 1222 item->setData(items.join(QString("\n")), 1223 peer_role_details); 1224 item->setData(pri_dev_type, peer_role_pri_dev_type); 1225 if (config_methods >= 0) 1226 item->setData(config_methods, 1227 peer_role_config_methods); 1228 if (dev_passwd_id >= 0) 1229 item->setData(dev_passwd_id, 1230 peer_role_dev_passwd_id); 1231 model.appendRow(item); 1232 } 1233 1234 return; 1235 } 1236 1237 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { 1238 /* 1239 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 1240 * 02:66:a0:ee:17:27 1241 */ 1242 QStringList items = text.split(' '); 1243 if (items.size() < 2) 1244 return; 1245 remove_enrollee_uuid(items[1]); 1246 return; 1247 } 1248 1249 if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { 1250 /* TODO: need to time out this somehow or remove on successful 1251 * WPS run, etc. */ 1252 /* 1253 * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 1254 * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 1255 * [Wireless Client] 1256 * (MAC addr, UUID-E, pri dev type, config methods, 1257 * dev passwd id, request type, [dev name]) 1258 */ 1259 QStringList items = text.split(' '); 1260 if (items.size() < 7) 1261 return; 1262 QString addr = items[1]; 1263 QString uuid = items[2]; 1264 QString pri_dev_type = items[3]; 1265 int config_methods = items[4].toInt(0, 0); 1266 int dev_passwd_id = items[5].toInt(); 1267 QString name; 1268 1269 QStandardItem *item = find_addr(addr); 1270 if (item) { 1271 int type = item->data(peer_role_type).toInt(); 1272 if (type == PEER_TYPE_ASSOCIATED_STATION) 1273 return; /* already associated */ 1274 } 1275 1276 int pos = text.indexOf('['); 1277 if (pos >= 0) { 1278 int pos2 = text.lastIndexOf(']'); 1279 if (pos2 >= pos) { 1280 QStringList items2 = 1281 text.mid(pos + 1, pos2 - pos - 1). 1282 split('|'); 1283 name = items2[0]; 1284 } 1285 } 1286 if (name.isEmpty()) 1287 name = addr; 1288 1289 item = find_uuid(uuid); 1290 if (item) { 1291 QVariant var = item->data(peer_role_config_methods); 1292 QVariant var2 = item->data(peer_role_dev_passwd_id); 1293 if ((var.isValid() && config_methods != var.toInt()) || 1294 (var2.isValid() && dev_passwd_id != var2.toInt())) 1295 remove_enrollee_uuid(uuid); 1296 else 1297 return; 1298 } 1299 1300 item = new QStandardItem(*laptop_icon, name); 1301 if (item) { 1302 item->setData(uuid, peer_role_uuid); 1303 item->setData(addr, peer_role_address); 1304 item->setData(PEER_TYPE_WPS_ENROLLEE, 1305 peer_role_type); 1306 item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); 1307 item->setData(items.join(QString("\n")), 1308 peer_role_details); 1309 item->setData(pri_dev_type, peer_role_pri_dev_type); 1310 item->setData(config_methods, 1311 peer_role_config_methods); 1312 item->setData(dev_passwd_id, peer_role_dev_passwd_id); 1313 model.appendRow(item); 1314 } 1315 1316 return; 1317 } 1318 1319 if (text.startsWith(WPA_EVENT_BSS_ADDED)) { 1320 /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ 1321 QStringList items = text.split(' '); 1322 if (items.size() < 2) 1323 return; 1324 char cmd[20]; 1325 snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); 1326 add_bss(cmd); 1327 return; 1328 } 1329 1330 if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { 1331 /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ 1332 QStringList items = text.split(' '); 1333 if (items.size() < 2) 1334 return; 1335 remove_bss(items[1].toInt()); 1336 return; 1337 } 1338 } 1339 1340 1341 void Peers::ctx_p2p_connect() 1342 { 1343 if (ctx_item == NULL) 1344 return; 1345 QString addr = ctx_item->data(peer_role_address).toString(); 1346 QString arg; 1347 int config_methods = 1348 ctx_item->data(peer_role_config_methods).toInt(); 1349 enum selected_method method = SEL_METHOD_NONE; 1350 QVariant var = ctx_item->data(peer_role_selected_method); 1351 if (var.isValid()) 1352 method = (enum selected_method) var.toInt(); 1353 if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) { 1354 arg = ctx_item->data(peer_role_selected_pin).toString(); 1355 char cmd[100]; 1356 char reply[100]; 1357 size_t reply_len; 1358 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", 1359 addr.toAscii().constData(), 1360 arg.toAscii().constData()); 1361 reply_len = sizeof(reply) - 1; 1362 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1363 QMessageBox msg; 1364 msg.setIcon(QMessageBox::Warning); 1365 msg.setText("Failed to initiate P2P connect."); 1366 msg.exec(); 1367 return; 1368 } 1369 QMessageBox::information(this, 1370 tr("PIN for ") + ctx_item->text(), 1371 tr("Enter the following PIN on the\n" 1372 "peer device: ") + arg); 1373 } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) { 1374 StringQuery input(tr("PIN from peer display:")); 1375 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1376 if (input.exec() != QDialog::Accepted) 1377 return; 1378 arg = input.get_string(); 1379 } else if (config_methods == 0x0080 /* PBC */) { 1380 arg = "pbc"; 1381 } else { 1382 StringQuery input(tr("PIN:")); 1383 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1384 if (input.exec() != QDialog::Accepted) 1385 return; 1386 arg = input.get_string(); 1387 } 1388 1389 char cmd[100]; 1390 char reply[100]; 1391 size_t reply_len; 1392 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", 1393 addr.toAscii().constData(), 1394 arg.toAscii().constData()); 1395 reply_len = sizeof(reply) - 1; 1396 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1397 QMessageBox msg; 1398 msg.setIcon(QMessageBox::Warning); 1399 msg.setText("Failed to initiate P2P connect."); 1400 msg.exec(); 1401 } 1402 } 1403 1404 1405 void Peers::ctx_p2p_req_pin() 1406 { 1407 if (ctx_item == NULL) 1408 return; 1409 QString addr = ctx_item->data(peer_role_address).toString(); 1410 ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY, 1411 peer_role_requested_method); 1412 1413 char cmd[100]; 1414 char reply[100]; 1415 size_t reply_len; 1416 snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display", 1417 addr.toAscii().constData()); 1418 reply_len = sizeof(reply) - 1; 1419 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1420 QMessageBox msg; 1421 msg.setIcon(QMessageBox::Warning); 1422 msg.setText(tr("Failed to request PIN from peer.")); 1423 msg.exec(); 1424 } 1425 } 1426 1427 1428 void Peers::ctx_p2p_show_pin() 1429 { 1430 if (ctx_item == NULL) 1431 return; 1432 QString addr = ctx_item->data(peer_role_address).toString(); 1433 ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, 1434 peer_role_requested_method); 1435 1436 char cmd[100]; 1437 char reply[100]; 1438 size_t reply_len; 1439 snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad", 1440 addr.toAscii().constData()); 1441 reply_len = sizeof(reply) - 1; 1442 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1443 QMessageBox msg; 1444 msg.setIcon(QMessageBox::Warning); 1445 msg.setText(tr("Failed to request peer to enter PIN.")); 1446 msg.exec(); 1447 } 1448 } 1449 1450 1451 void Peers::ctx_p2p_display_pin() 1452 { 1453 if (ctx_item == NULL) 1454 return; 1455 QString addr = ctx_item->data(peer_role_address).toString(); 1456 1457 char cmd[100]; 1458 char reply[100]; 1459 size_t reply_len; 1460 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin", 1461 addr.toAscii().constData()); 1462 reply_len = sizeof(reply) - 1; 1463 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1464 QMessageBox msg; 1465 msg.setIcon(QMessageBox::Warning); 1466 msg.setText("Failed to initiate P2P connect."); 1467 msg.exec(); 1468 return; 1469 } 1470 reply[reply_len] = '\0'; 1471 QMessageBox::information(this, 1472 tr("PIN for ") + ctx_item->text(), 1473 tr("Enter the following PIN on the\n" 1474 "peer device: ") + reply); 1475 } 1476 1477 1478 void Peers::ctx_p2p_display_pin_pd() 1479 { 1480 if (ctx_item == NULL) 1481 return; 1482 QString addr = ctx_item->data(peer_role_address).toString(); 1483 QString arg = ctx_item->data(peer_role_selected_pin).toString(); 1484 1485 char cmd[100]; 1486 char reply[100]; 1487 size_t reply_len; 1488 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", 1489 addr.toAscii().constData(), 1490 arg.toAscii().constData()); 1491 reply_len = sizeof(reply) - 1; 1492 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1493 QMessageBox msg; 1494 msg.setIcon(QMessageBox::Warning); 1495 msg.setText("Failed to initiate P2P connect."); 1496 msg.exec(); 1497 return; 1498 } 1499 reply[reply_len] = '\0'; 1500 QMessageBox::information(this, 1501 tr("PIN for ") + ctx_item->text(), 1502 tr("Enter the following PIN on the\n" 1503 "peer device: ") + arg); 1504 } 1505 1506 1507 void Peers::ctx_p2p_enter_pin() 1508 { 1509 if (ctx_item == NULL) 1510 return; 1511 QString addr = ctx_item->data(peer_role_address).toString(); 1512 QString arg; 1513 1514 StringQuery input(tr("PIN from peer:")); 1515 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1516 if (input.exec() != QDialog::Accepted) 1517 return; 1518 arg = input.get_string(); 1519 1520 char cmd[100]; 1521 char reply[100]; 1522 size_t reply_len; 1523 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad", 1524 addr.toAscii().constData(), 1525 arg.toAscii().constData()); 1526 reply_len = sizeof(reply) - 1; 1527 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1528 QMessageBox msg; 1529 msg.setIcon(QMessageBox::Warning); 1530 msg.setText("Failed to initiate P2P connect."); 1531 msg.exec(); 1532 } 1533 } 1534 1535 1536 void Peers::ctx_p2p_remove_group() 1537 { 1538 if (ctx_item == NULL) 1539 return; 1540 char cmd[100]; 1541 char reply[100]; 1542 size_t reply_len; 1543 snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", 1544 ctx_item->data(peer_role_ifname).toString().toAscii(). 1545 constData()); 1546 reply_len = sizeof(reply) - 1; 1547 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1548 QMessageBox msg; 1549 msg.setIcon(QMessageBox::Warning); 1550 msg.setText("Failed to remove P2P Group."); 1551 msg.exec(); 1552 } 1553 } 1554 1555 1556 void Peers::closeEvent(QCloseEvent *) 1557 { 1558 if (wpagui) { 1559 char reply[20]; 1560 size_t replylen = sizeof(reply) - 1; 1561 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); 1562 } 1563 } 1564 1565 1566 void Peers::done(int r) 1567 { 1568 QDialog::done(r); 1569 close(); 1570 } 1571 1572 1573 void Peers::remove_enrollee_uuid(QString uuid) 1574 { 1575 if (model.rowCount() == 0) 1576 return; 1577 1578 QModelIndexList lst = model.match(model.index(0, 0), 1579 peer_role_uuid, uuid); 1580 for (int i = 0; i < lst.size(); i++) { 1581 QStandardItem *item = model.itemFromIndex(lst[i]); 1582 if (item == NULL) 1583 continue; 1584 int type = item->data(peer_role_type).toInt(); 1585 if (type == PEER_TYPE_WPS_ER_ENROLLEE || 1586 type == PEER_TYPE_WPS_ENROLLEE) 1587 model.removeRow(lst[i].row()); 1588 } 1589 } 1590 1591 1592 void Peers::properties() 1593 { 1594 if (ctx_item == NULL) 1595 return; 1596 1597 QMessageBox msg(this); 1598 msg.setStandardButtons(QMessageBox::Ok); 1599 msg.setDefaultButton(QMessageBox::Ok); 1600 msg.setEscapeButton(QMessageBox::Ok); 1601 msg.setWindowTitle(tr("Peer Properties")); 1602 1603 int type = ctx_item->data(peer_role_type).toInt(); 1604 QString title = Peers::ItemType(type); 1605 1606 msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); 1607 1608 QVariant var; 1609 QString info; 1610 1611 var = ctx_item->data(peer_role_address); 1612 if (var.isValid()) 1613 info += tr("Address: ") + var.toString() + QString("\n"); 1614 1615 var = ctx_item->data(peer_role_uuid); 1616 if (var.isValid()) 1617 info += tr("UUID: ") + var.toString() + QString("\n"); 1618 1619 var = ctx_item->data(peer_role_pri_dev_type); 1620 if (var.isValid()) 1621 info += tr("Primary Device Type: ") + var.toString() + 1622 QString("\n"); 1623 1624 var = ctx_item->data(peer_role_ssid); 1625 if (var.isValid()) 1626 info += tr("SSID: ") + var.toString() + QString("\n"); 1627 1628 var = ctx_item->data(peer_role_config_methods); 1629 if (var.isValid()) { 1630 int methods = var.toInt(); 1631 info += tr("Configuration Methods: "); 1632 if (methods & 0x0001) 1633 info += tr("[USBA]"); 1634 if (methods & 0x0002) 1635 info += tr("[Ethernet]"); 1636 if (methods & 0x0004) 1637 info += tr("[Label]"); 1638 if (methods & 0x0008) 1639 info += tr("[Display]"); 1640 if (methods & 0x0010) 1641 info += tr("[Ext. NFC Token]"); 1642 if (methods & 0x0020) 1643 info += tr("[Int. NFC Token]"); 1644 if (methods & 0x0040) 1645 info += tr("[NFC Interface]"); 1646 if (methods & 0x0080) 1647 info += tr("[Push Button]"); 1648 if (methods & 0x0100) 1649 info += tr("[Keypad]"); 1650 info += "\n"; 1651 } 1652 1653 var = ctx_item->data(peer_role_selected_method); 1654 if (var.isValid()) { 1655 enum selected_method method = 1656 (enum selected_method) var.toInt(); 1657 switch (method) { 1658 case SEL_METHOD_NONE: 1659 break; 1660 case SEL_METHOD_PIN_PEER_DISPLAY: 1661 info += tr("Selected Method: PIN on peer display\n"); 1662 break; 1663 case SEL_METHOD_PIN_LOCAL_DISPLAY: 1664 info += tr("Selected Method: PIN on local display\n"); 1665 break; 1666 } 1667 } 1668 1669 var = ctx_item->data(peer_role_selected_pin); 1670 if (var.isValid()) { 1671 info += tr("PIN to enter on peer: ") + var.toString() + "\n"; 1672 } 1673 1674 var = ctx_item->data(peer_role_dev_passwd_id); 1675 if (var.isValid()) { 1676 info += tr("Device Password ID: ") + var.toString(); 1677 switch (var.toInt()) { 1678 case 0: 1679 info += tr(" (Default PIN)"); 1680 break; 1681 case 1: 1682 info += tr(" (User-specified PIN)"); 1683 break; 1684 case 2: 1685 info += tr(" (Machine-specified PIN)"); 1686 break; 1687 case 3: 1688 info += tr(" (Rekey)"); 1689 break; 1690 case 4: 1691 info += tr(" (Push Button)"); 1692 break; 1693 case 5: 1694 info += tr(" (Registrar-specified)"); 1695 break; 1696 } 1697 info += "\n"; 1698 } 1699 1700 msg.setInformativeText(info); 1701 1702 var = ctx_item->data(peer_role_details); 1703 if (var.isValid()) 1704 msg.setDetailedText(var.toString()); 1705 1706 msg.exec(); 1707 } 1708 1709 1710 void Peers::connect_pbc() 1711 { 1712 if (ctx_item == NULL) 1713 return; 1714 1715 char cmd[100]; 1716 char reply[100]; 1717 size_t reply_len; 1718 1719 int peer_type = ctx_item->data(peer_role_type).toInt(); 1720 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { 1721 snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", 1722 ctx_item->data(peer_role_uuid).toString().toAscii(). 1723 constData()); 1724 } else if (peer_type == PEER_TYPE_P2P || 1725 peer_type == PEER_TYPE_P2P_CLIENT) { 1726 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc", 1727 ctx_item->data(peer_role_address).toString(). 1728 toAscii().constData()); 1729 } else { 1730 snprintf(cmd, sizeof(cmd), "WPS_PBC"); 1731 } 1732 reply_len = sizeof(reply) - 1; 1733 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1734 QMessageBox msg; 1735 msg.setIcon(QMessageBox::Warning); 1736 msg.setText(tr("Failed to start WPS PBC.")); 1737 msg.exec(); 1738 } 1739 } 1740 1741 1742 void Peers::learn_ap_config() 1743 { 1744 if (ctx_item == NULL) 1745 return; 1746 1747 QString uuid = ctx_item->data(peer_role_uuid).toString(); 1748 1749 StringQuery input(tr("AP PIN:")); 1750 input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); 1751 if (input.exec() != QDialog::Accepted) 1752 return; 1753 1754 char cmd[100]; 1755 char reply[100]; 1756 size_t reply_len; 1757 1758 snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", 1759 uuid.toAscii().constData(), 1760 input.get_string().toAscii().constData()); 1761 reply_len = sizeof(reply) - 1; 1762 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1763 QMessageBox msg; 1764 msg.setIcon(QMessageBox::Warning); 1765 msg.setText(tr("Failed to start learning AP configuration.")); 1766 msg.exec(); 1767 } 1768 } 1769 1770 1771 void Peers::ctx_hide_ap() 1772 { 1773 hide_ap = true; 1774 1775 if (model.rowCount() == 0) 1776 return; 1777 1778 do { 1779 QModelIndexList lst; 1780 lst = model.match(model.index(0, 0), 1781 peer_role_type, PEER_TYPE_AP); 1782 if (lst.size() == 0) { 1783 lst = model.match(model.index(0, 0), 1784 peer_role_type, PEER_TYPE_AP_WPS); 1785 if (lst.size() == 0) 1786 break; 1787 } 1788 1789 model.removeRow(lst[0].row()); 1790 } while (1); 1791 } 1792 1793 1794 void Peers::ctx_show_ap() 1795 { 1796 hide_ap = false; 1797 add_scan_results(); 1798 } 1799 1800 1801 void Peers::ctx_p2p_show_passphrase() 1802 { 1803 char reply[64]; 1804 size_t reply_len; 1805 1806 reply_len = sizeof(reply) - 1; 1807 if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 || 1808 memcmp(reply, "FAIL", 4) == 0) { 1809 QMessageBox msg; 1810 msg.setIcon(QMessageBox::Warning); 1811 msg.setText("Failed to get P2P group passphrase."); 1812 msg.exec(); 1813 } else { 1814 reply[reply_len] = '\0'; 1815 QMessageBox::information(this, tr("Passphrase"), 1816 tr("P2P group passphrase:\n") + 1817 reply); 1818 } 1819 } 1820 1821 1822 void Peers::ctx_p2p_start_persistent() 1823 { 1824 if (ctx_item == NULL) 1825 return; 1826 1827 char cmd[100]; 1828 char reply[100]; 1829 size_t reply_len; 1830 1831 snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d", 1832 ctx_item->data(peer_role_network_id).toInt()); 1833 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || 1834 memcmp(reply, "FAIL", 4) == 0) { 1835 QMessageBox msg; 1836 msg.setIcon(QMessageBox::Warning); 1837 msg.setText(tr("Failed to start persistent P2P Group.")); 1838 msg.exec(); 1839 } else if (ctx_item->data(peer_role_type).toInt() == 1840 PEER_TYPE_P2P_INVITATION) 1841 model.removeRow(ctx_item->row()); 1842 } 1843 1844 1845 void Peers::ctx_p2p_invite() 1846 { 1847 if (ctx_item == NULL) 1848 return; 1849 1850 char cmd[100]; 1851 char reply[100]; 1852 size_t reply_len; 1853 1854 snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d", 1855 ctx_item->data(peer_role_network_id).toInt()); 1856 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || 1857 memcmp(reply, "FAIL", 4) == 0) { 1858 QMessageBox msg; 1859 msg.setIcon(QMessageBox::Warning); 1860 msg.setText(tr("Failed to invite peer to start persistent " 1861 "P2P Group.")); 1862 msg.exec(); 1863 } 1864 } 1865 1866 1867 void Peers::ctx_p2p_delete() 1868 { 1869 if (ctx_item == NULL) 1870 return; 1871 model.removeRow(ctx_item->row()); 1872 } 1873 1874 1875 void Peers::enable_persistent(int id) 1876 { 1877 if (model.rowCount() == 0) 1878 return; 1879 1880 QModelIndexList lst = model.match(model.index(0, 0), 1881 peer_role_network_id, id); 1882 for (int i = 0; i < lst.size(); i++) { 1883 QStandardItem *item = model.itemFromIndex(lst[i]); 1884 int type = item->data(peer_role_type).toInt(); 1885 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || 1886 type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) 1887 item->setBackground(Qt::NoBrush); 1888 } 1889 } 1890