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