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 Peers(QWidget * parent,const char *,bool,Qt::WindowFlags)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 setWpaGui(WpaGui * _wpagui)99 void Peers::setWpaGui(WpaGui *_wpagui) 100 { 101 wpagui = _wpagui; 102 update_peers(); 103 } 104 105 ~Peers()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 languageChange()116 void Peers::languageChange() 117 { 118 retranslateUi(this); 119 } 120 121 ItemType(int type)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 context_menu(const QPoint & pos)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 enter_pin()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 ctx_refresh()344 void Peers::ctx_refresh() 345 { 346 update_peers(); 347 } 348 349 ctx_p2p_start()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 ctx_p2p_stop()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 ctx_p2p_listen()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 ctx_p2p_start_group()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 add_station(QString info)404 void Peers::add_station(QString info) 405 { 406 QStringList lines = info.split(QRegularExpression("\\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 add_stations()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 res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); 480 if (res < 0 || (size_t) res >= sizeof(cmd)) 481 break; 482 res = wpagui->ctrlRequest(cmd, reply, &reply_len); 483 } while (res >= 0); 484 } 485 486 add_single_station(const char * addr)487 void Peers::add_single_station(const char *addr) 488 { 489 char reply[2048]; 490 size_t reply_len; 491 char cmd[30]; 492 493 reply_len = sizeof(reply) - 1; 494 snprintf(cmd, sizeof(cmd), "STA %s", addr); 495 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 496 return; 497 498 reply[reply_len] = '\0'; 499 QString info(reply); 500 char *txt = reply; 501 while (*txt != '\0' && *txt != '\n') 502 txt++; 503 *txt++ = '\0'; 504 if (strncmp(reply, "FAIL", 4) == 0 || 505 strncmp(reply, "UNKNOWN", 7) == 0) 506 return; 507 508 add_station(info); 509 } 510 511 add_p2p_group_client(QStandardItem *,QString params)512 void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params) 513 { 514 /* 515 * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0 516 * dev_type=1-0050f204-1 dev_name='Wireless Client' 517 * config_methods=0x8c 518 */ 519 520 QStringList items = 521 params.split(QRegularExpression(" (?=[^']*('[^']*'[^']*)*$)")); 522 QString addr = ""; 523 QString name = ""; 524 int config_methods = 0; 525 QString dev_type; 526 527 for (int i = 0; i < items.size(); i++) { 528 QString str = items.at(i); 529 int pos = str.indexOf('=') + 1; 530 if (str.startsWith("dev_name='")) 531 name = str.section('\'', 1, -2); 532 else if (str.startsWith("config_methods=")) 533 config_methods = 534 str.section('=', 1).toInt(0, 0); 535 else if (str.startsWith("dev=")) 536 addr = str.mid(pos); 537 else if (str.startsWith("dev_type=") && dev_type.isEmpty()) 538 dev_type = str.mid(pos); 539 } 540 541 QStandardItem *item = find_addr(addr); 542 if (item) 543 return; 544 545 item = new QStandardItem(*default_icon, name); 546 if (item) { 547 /* TODO: indicate somehow the relationship to the group owner 548 * (parent) */ 549 item->setData(addr, peer_role_address); 550 item->setData(config_methods, peer_role_config_methods); 551 item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type); 552 if (!dev_type.isEmpty()) 553 item->setData(dev_type, peer_role_pri_dev_type); 554 item->setData(items.join(QString("\n")), peer_role_details); 555 item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT)); 556 model.appendRow(item); 557 } 558 } 559 560 remove_bss(int id)561 void Peers::remove_bss(int id) 562 { 563 if (model.rowCount() == 0) 564 return; 565 566 QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, 567 id); 568 if (lst.size() == 0) 569 return; 570 model.removeRow(lst[0].row()); 571 } 572 573 add_bss(const char * cmd)574 bool Peers::add_bss(const char *cmd) 575 { 576 char reply[2048]; 577 size_t reply_len; 578 579 if (hide_ap) 580 return false; 581 582 reply_len = sizeof(reply) - 1; 583 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 584 return false; 585 reply[reply_len] = '\0'; 586 587 QString bss(reply); 588 if (bss.isEmpty() || bss.startsWith("FAIL")) 589 return false; 590 591 QString ssid, bssid, flags, wps_name, pri_dev_type; 592 int id = -1; 593 594 QStringList lines = bss.split(QRegularExpression("\\n")); 595 for (QStringList::Iterator it = lines.begin(); 596 it != lines.end(); it++) { 597 int pos = (*it).indexOf('=') + 1; 598 if (pos < 1) 599 continue; 600 601 if ((*it).startsWith("bssid=")) 602 bssid = (*it).mid(pos); 603 else if ((*it).startsWith("id=")) 604 id = (*it).mid(pos).toInt(); 605 else if ((*it).startsWith("flags=")) 606 flags = (*it).mid(pos); 607 else if ((*it).startsWith("ssid=")) 608 ssid = (*it).mid(pos); 609 else if ((*it).startsWith("wps_device_name=")) 610 wps_name = (*it).mid(pos); 611 else if ((*it).startsWith("wps_primary_device_type=")) 612 pri_dev_type = (*it).mid(pos); 613 } 614 615 QString name = wps_name; 616 if (name.isEmpty()) 617 name = ssid + "\n" + bssid; 618 619 QStandardItem *item = new QStandardItem(*ap_icon, name); 620 if (item) { 621 item->setData(bssid, peer_role_address); 622 if (id >= 0) 623 item->setData(id, peer_role_bss_id); 624 int type; 625 if (flags.contains("[WPS")) 626 type = PEER_TYPE_AP_WPS; 627 else 628 type = PEER_TYPE_AP; 629 item->setData(type, peer_role_type); 630 631 for (int i = 0; i < lines.size(); i++) { 632 if (lines[i].length() > 60) { 633 lines[i].remove(60, lines[i].length()); 634 lines[i] += ".."; 635 } 636 } 637 item->setToolTip(ItemType(type)); 638 item->setData(lines.join("\n"), peer_role_details); 639 if (!pri_dev_type.isEmpty()) 640 item->setData(pri_dev_type, 641 peer_role_pri_dev_type); 642 if (!ssid.isEmpty()) 643 item->setData(ssid, peer_role_ssid); 644 model.appendRow(item); 645 646 lines = bss.split(QRegularExpression("\\n")); 647 for (QStringList::Iterator it = lines.begin(); 648 it != lines.end(); it++) { 649 if ((*it).startsWith("p2p_group_client:")) 650 add_p2p_group_client(item, 651 (*it).mid(18)); 652 } 653 } 654 655 return true; 656 } 657 658 add_scan_results()659 void Peers::add_scan_results() 660 { 661 int index; 662 char cmd[20]; 663 664 index = 0; 665 while (wpagui) { 666 snprintf(cmd, sizeof(cmd), "BSS %d", index++); 667 if (index > 1000) 668 break; 669 670 if (!add_bss(cmd)) 671 break; 672 } 673 } 674 675 add_persistent(int id,const char * ssid,const char * bssid)676 void Peers::add_persistent(int id, const char *ssid, const char *bssid) 677 { 678 char cmd[100]; 679 char reply[100]; 680 size_t reply_len; 681 int mode; 682 683 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id); 684 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 685 return; 686 reply[reply_len] = '\0'; 687 mode = atoi(reply); 688 689 QString name = ssid; 690 name = '[' + name + ']'; 691 692 QStandardItem *item = new QStandardItem(*group_icon, name); 693 if (!item) 694 return; 695 696 int type; 697 if (mode == 3) 698 type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO; 699 else 700 type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT; 701 item->setData(type, peer_role_type); 702 item->setToolTip(ItemType(type)); 703 item->setData(ssid, peer_role_ssid); 704 if (bssid && strcmp(bssid, "any") == 0) 705 bssid = NULL; 706 if (bssid) 707 item->setData(bssid, peer_role_address); 708 item->setData(id, peer_role_network_id); 709 item->setBackground(Qt::BDiagPattern); 710 711 model.appendRow(item); 712 } 713 714 add_persistent_groups()715 void Peers::add_persistent_groups() 716 { 717 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; 718 size_t len; 719 720 len = sizeof(buf) - 1; 721 if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 722 return; 723 724 buf[len] = '\0'; 725 start = strchr(buf, '\n'); 726 if (start == NULL) 727 return; 728 start++; 729 730 while (*start) { 731 bool last = false; 732 end = strchr(start, '\n'); 733 if (end == NULL) { 734 last = true; 735 end = start; 736 while (end[0] && end[1]) 737 end++; 738 } 739 *end = '\0'; 740 741 id = start; 742 ssid = strchr(id, '\t'); 743 if (ssid == NULL) 744 break; 745 *ssid++ = '\0'; 746 bssid = strchr(ssid, '\t'); 747 if (bssid == NULL) 748 break; 749 *bssid++ = '\0'; 750 flags = strchr(bssid, '\t'); 751 if (flags == NULL) 752 break; 753 *flags++ = '\0'; 754 755 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) 756 add_persistent(atoi(id), ssid, bssid); 757 758 if (last) 759 break; 760 start = end + 1; 761 } 762 } 763 764 update_peers()765 void Peers::update_peers() 766 { 767 model.clear(); 768 if (wpagui == NULL) 769 return; 770 771 char reply[20]; 772 size_t replylen = sizeof(reply) - 1; 773 wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); 774 775 add_stations(); 776 add_scan_results(); 777 add_persistent_groups(); 778 } 779 780 find_addr(QString addr)781 QStandardItem * Peers::find_addr(QString addr) 782 { 783 if (model.rowCount() == 0) 784 return NULL; 785 786 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, 787 addr); 788 if (lst.size() == 0) 789 return NULL; 790 return model.itemFromIndex(lst[0]); 791 } 792 793 find_addr_type(QString addr,int type)794 QStandardItem * Peers::find_addr_type(QString addr, int type) 795 { 796 if (model.rowCount() == 0) 797 return NULL; 798 799 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, 800 addr); 801 for (int i = 0; i < lst.size(); i++) { 802 QStandardItem *item = model.itemFromIndex(lst[i]); 803 if (item->data(peer_role_type).toInt() == type) 804 return item; 805 } 806 return NULL; 807 } 808 809 find_uuid(QString uuid)810 QStandardItem * Peers::find_uuid(QString uuid) 811 { 812 if (model.rowCount() == 0) 813 return NULL; 814 815 QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, 816 uuid); 817 if (lst.size() == 0) 818 return NULL; 819 return model.itemFromIndex(lst[0]); 820 } 821 822 event_notify(WpaMsg msg)823 void Peers::event_notify(WpaMsg msg) 824 { 825 QString text = msg.getMsg(); 826 827 if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { 828 /* 829 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 830 * 02:2a:c4:18:5b:f3 831 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] 832 */ 833 QStringList items = text.split(' '); 834 QString uuid = items[1]; 835 QString addr = items[2]; 836 QString name = ""; 837 838 QStandardItem *item = find_addr(addr); 839 if (item) 840 return; 841 842 int pos = text.indexOf('['); 843 if (pos >= 0) { 844 int pos2 = text.lastIndexOf(']'); 845 if (pos2 >= pos) { 846 items = text.mid(pos + 1, pos2 - pos - 1). 847 split('|'); 848 name = items[0]; 849 items.append(addr); 850 } 851 } 852 853 item = new QStandardItem(*laptop_icon, name); 854 if (item) { 855 item->setData(addr, peer_role_address); 856 item->setData(PEER_TYPE_WPS_PIN_NEEDED, 857 peer_role_type); 858 item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); 859 item->setData(items.join("\n"), peer_role_details); 860 item->setData(items[5], peer_role_pri_dev_type); 861 model.appendRow(item); 862 } 863 return; 864 } 865 866 if (text.startsWith(AP_STA_CONNECTED)) { 867 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ 868 QStringList items = text.split(' '); 869 QString addr = items[1]; 870 QStandardItem *item = find_addr(addr); 871 if (item == NULL || item->data(peer_role_type).toInt() != 872 PEER_TYPE_ASSOCIATED_STATION) 873 add_single_station(addr.toLocal8Bit().constData()); 874 return; 875 } 876 877 if (text.startsWith(AP_STA_DISCONNECTED)) { 878 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ 879 QStringList items = text.split(' '); 880 QString addr = items[1]; 881 882 if (model.rowCount() == 0) 883 return; 884 885 QModelIndexList lst = model.match(model.index(0, 0), 886 peer_role_address, addr, -1); 887 for (int i = 0; i < lst.size(); i++) { 888 QStandardItem *item = model.itemFromIndex(lst[i]); 889 if (item && item->data(peer_role_type).toInt() == 890 PEER_TYPE_ASSOCIATED_STATION) { 891 model.removeRow(lst[i].row()); 892 break; 893 } 894 } 895 return; 896 } 897 898 if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) { 899 /* 900 * P2P-DEVICE-FOUND 02:b5:64:63:30:63 901 * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1 902 * name='Wireless Client' config_methods=0x84 dev_capab=0x21 903 * group_capab=0x0 904 */ 905 QStringList items = 906 text.split(QRegularExpression(" (?=[^']*('[^']*'[^']*)*$)")); 907 QString addr = items[1]; 908 QString name = ""; 909 QString pri_dev_type; 910 int config_methods = 0; 911 for (int i = 0; i < items.size(); i++) { 912 QString str = items.at(i); 913 if (str.startsWith("name='")) 914 name = str.section('\'', 1, -2); 915 else if (str.startsWith("config_methods=")) 916 config_methods = 917 str.section('=', 1).toInt(0, 0); 918 else if (str.startsWith("pri_dev_type=")) 919 pri_dev_type = str.section('=', 1); 920 } 921 922 QStandardItem *item = find_addr(addr); 923 if (item) { 924 int type = item->data(peer_role_type).toInt(); 925 if (type == PEER_TYPE_P2P) 926 return; 927 } 928 929 item = new QStandardItem(*default_icon, name); 930 if (item) { 931 item->setData(addr, peer_role_address); 932 item->setData(config_methods, 933 peer_role_config_methods); 934 item->setData(PEER_TYPE_P2P, peer_role_type); 935 if (!pri_dev_type.isEmpty()) 936 item->setData(pri_dev_type, 937 peer_role_pri_dev_type); 938 item->setData(items.join(QString("\n")), 939 peer_role_details); 940 item->setToolTip(ItemType(PEER_TYPE_P2P)); 941 model.appendRow(item); 942 } 943 944 item = find_addr_type(addr, 945 PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT); 946 if (item) 947 item->setBackground(Qt::NoBrush); 948 } 949 950 if (text.startsWith(P2P_EVENT_GROUP_STARTED)) { 951 /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F" 952 * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7 953 * [PERSISTENT] */ 954 QStringList items = text.split(' '); 955 if (items.size() < 4) 956 return; 957 958 int pos = text.indexOf(" ssid=\""); 959 if (pos < 0) 960 return; 961 QString ssid = text.mid(pos + 7); 962 pos = ssid.indexOf(" passphrase=\""); 963 if (pos < 0) 964 pos = ssid.indexOf(" psk="); 965 if (pos >= 0) 966 ssid.truncate(pos); 967 pos = ssid.lastIndexOf('"'); 968 if (pos >= 0) 969 ssid.truncate(pos); 970 971 QStandardItem *item = new QStandardItem(*group_icon, ssid); 972 if (item) { 973 item->setData(PEER_TYPE_P2P_GROUP, peer_role_type); 974 item->setData(items[1], peer_role_ifname); 975 QString details; 976 if (items[2] == "GO") { 977 details = tr("P2P GO for interface ") + 978 items[1]; 979 } else { 980 details = tr("P2P client for interface ") + 981 items[1]; 982 } 983 if (text.contains(" [PERSISTENT]")) 984 details += "\nPersistent group"; 985 item->setData(details, peer_role_details); 986 item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP)); 987 model.appendRow(item); 988 } 989 } 990 991 if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) { 992 /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */ 993 QStringList items = text.split(' '); 994 if (items.size() < 2) 995 return; 996 997 if (model.rowCount() == 0) 998 return; 999 1000 QModelIndexList lst = model.match(model.index(0, 0), 1001 peer_role_ifname, items[1]); 1002 for (int i = 0; i < lst.size(); i++) 1003 model.removeRow(lst[i].row()); 1004 return; 1005 } 1006 1007 if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) { 1008 /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */ 1009 QStringList items = text.split(' '); 1010 if (items.size() < 3) 1011 return; 1012 QString addr = items[1]; 1013 QString pin = items[2]; 1014 1015 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); 1016 if (item == NULL) 1017 return; 1018 item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, 1019 peer_role_selected_method); 1020 item->setData(pin, peer_role_selected_pin); 1021 QVariant var = item->data(peer_role_requested_method); 1022 if (var.isValid() && 1023 var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) { 1024 ctx_item = item; 1025 ctx_p2p_display_pin_pd(); 1026 } 1027 return; 1028 } 1029 1030 if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) { 1031 /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */ 1032 QStringList items = text.split(' '); 1033 if (items.size() < 2) 1034 return; 1035 QString addr = items[1]; 1036 1037 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); 1038 if (item == NULL) 1039 return; 1040 item->setData(SEL_METHOD_PIN_PEER_DISPLAY, 1041 peer_role_selected_method); 1042 QVariant var = item->data(peer_role_requested_method); 1043 if (var.isValid() && 1044 var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) { 1045 ctx_item = item; 1046 ctx_p2p_connect(); 1047 } 1048 return; 1049 } 1050 1051 if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) { 1052 /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */ 1053 QStringList items = text.split(' '); 1054 if (items.size() < 3) 1055 return; 1056 if (!items[1].startsWith("sa=") || 1057 !items[2].startsWith("persistent=")) 1058 return; 1059 QString addr = items[1].mid(3); 1060 int id = items[2].mid(11).toInt(); 1061 1062 char cmd[100]; 1063 char reply[100]; 1064 size_t reply_len; 1065 1066 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id); 1067 reply_len = sizeof(reply) - 1; 1068 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) 1069 return; 1070 reply[reply_len] = '\0'; 1071 QString name; 1072 char *pos = strrchr(reply, '"'); 1073 if (pos && reply[0] == '"') { 1074 *pos = '\0'; 1075 name = reply + 1; 1076 } else 1077 name = reply; 1078 1079 QStandardItem *item; 1080 item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION); 1081 if (item) 1082 model.removeRow(item->row()); 1083 1084 item = new QStandardItem(*invitation_icon, name); 1085 if (!item) 1086 return; 1087 item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type); 1088 item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION)); 1089 item->setData(addr, peer_role_address); 1090 item->setData(id, peer_role_network_id); 1091 1092 model.appendRow(item); 1093 1094 enable_persistent(id); 1095 1096 return; 1097 } 1098 1099 if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) { 1100 /* P2P-INVITATION-RESULT status=1 */ 1101 /* TODO */ 1102 return; 1103 } 1104 1105 if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { 1106 /* 1107 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 1108 * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 1109 * |Very friendly name|Company|Long description of the model| 1110 * WAP|http://w1.fi/|http://w1.fi/hostapd/ 1111 */ 1112 QStringList items = text.split(' '); 1113 if (items.size() < 5) 1114 return; 1115 QString uuid = items[1]; 1116 QString addr = items[2]; 1117 QString pri_dev_type = items[3].mid(13); 1118 int wps_state = items[4].mid(10).toInt(); 1119 1120 int pos = text.indexOf('|'); 1121 if (pos < 0) 1122 return; 1123 items = text.mid(pos + 1).split('|'); 1124 if (items.size() < 1) 1125 return; 1126 1127 QStandardItem *item = find_uuid(uuid); 1128 if (item) 1129 return; 1130 1131 item = new QStandardItem(*ap_icon, items[0]); 1132 if (item) { 1133 item->setData(uuid, peer_role_uuid); 1134 item->setData(addr, peer_role_address); 1135 int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: 1136 PEER_TYPE_WPS_ER_AP_UNCONFIGURED; 1137 item->setData(type, peer_role_type); 1138 item->setToolTip(ItemType(type)); 1139 item->setData(pri_dev_type, peer_role_pri_dev_type); 1140 item->setData(items.join(QString("\n")), 1141 peer_role_details); 1142 model.appendRow(item); 1143 } 1144 1145 return; 1146 } 1147 1148 if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { 1149 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ 1150 QStringList items = text.split(' '); 1151 if (items.size() < 2) 1152 return; 1153 if (model.rowCount() == 0) 1154 return; 1155 1156 QModelIndexList lst = model.match(model.index(0, 0), 1157 peer_role_uuid, items[1]); 1158 for (int i = 0; i < lst.size(); i++) { 1159 QStandardItem *item = model.itemFromIndex(lst[i]); 1160 if (item && 1161 (item->data(peer_role_type).toInt() == 1162 PEER_TYPE_WPS_ER_AP || 1163 item->data(peer_role_type).toInt() == 1164 PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) 1165 model.removeRow(lst[i].row()); 1166 } 1167 return; 1168 } 1169 1170 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { 1171 /* 1172 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 1173 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 1174 * pri_dev_type=1-0050F204-1 1175 * |Wireless Client|Company|cmodel|123|12345| 1176 */ 1177 QStringList items = text.split(' '); 1178 if (items.size() < 3) 1179 return; 1180 QString uuid = items[1]; 1181 QString addr = items[2]; 1182 QString pri_dev_type = items[6].mid(13); 1183 int config_methods = -1; 1184 int dev_passwd_id = -1; 1185 1186 for (int i = 3; i < items.size(); i++) { 1187 int pos = items[i].indexOf('=') + 1; 1188 if (pos < 1) 1189 continue; 1190 QString val = items[i].mid(pos); 1191 if (items[i].startsWith("config_methods=")) { 1192 config_methods = val.toInt(0, 0); 1193 } else if (items[i].startsWith("dev_passwd_id=")) { 1194 dev_passwd_id = val.toInt(); 1195 } 1196 } 1197 1198 int pos = text.indexOf('|'); 1199 if (pos < 0) 1200 return; 1201 items = text.mid(pos + 1).split('|'); 1202 if (items.size() < 1) 1203 return; 1204 QString name = items[0]; 1205 if (name.length() == 0) 1206 name = addr; 1207 1208 remove_enrollee_uuid(uuid); 1209 1210 QStandardItem *item; 1211 item = new QStandardItem(*laptop_icon, name); 1212 if (item) { 1213 item->setData(uuid, peer_role_uuid); 1214 item->setData(addr, peer_role_address); 1215 item->setData(PEER_TYPE_WPS_ER_ENROLLEE, 1216 peer_role_type); 1217 item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); 1218 item->setData(items.join(QString("\n")), 1219 peer_role_details); 1220 item->setData(pri_dev_type, peer_role_pri_dev_type); 1221 if (config_methods >= 0) 1222 item->setData(config_methods, 1223 peer_role_config_methods); 1224 if (dev_passwd_id >= 0) 1225 item->setData(dev_passwd_id, 1226 peer_role_dev_passwd_id); 1227 model.appendRow(item); 1228 } 1229 1230 return; 1231 } 1232 1233 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { 1234 /* 1235 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 1236 * 02:66:a0:ee:17:27 1237 */ 1238 QStringList items = text.split(' '); 1239 if (items.size() < 2) 1240 return; 1241 remove_enrollee_uuid(items[1]); 1242 return; 1243 } 1244 1245 if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { 1246 /* TODO: need to time out this somehow or remove on successful 1247 * WPS run, etc. */ 1248 /* 1249 * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 1250 * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 1251 * [Wireless Client] 1252 * (MAC addr, UUID-E, pri dev type, config methods, 1253 * dev passwd id, request type, [dev name]) 1254 */ 1255 QStringList items = text.split(' '); 1256 if (items.size() < 7) 1257 return; 1258 QString addr = items[1]; 1259 QString uuid = items[2]; 1260 QString pri_dev_type = items[3]; 1261 int config_methods = items[4].toInt(0, 0); 1262 int dev_passwd_id = items[5].toInt(); 1263 QString name; 1264 1265 QStandardItem *item = find_addr(addr); 1266 if (item) { 1267 int type = item->data(peer_role_type).toInt(); 1268 if (type == PEER_TYPE_ASSOCIATED_STATION) 1269 return; /* already associated */ 1270 } 1271 1272 int pos = text.indexOf('['); 1273 if (pos >= 0) { 1274 int pos2 = text.lastIndexOf(']'); 1275 if (pos2 >= pos) { 1276 QStringList items2 = 1277 text.mid(pos + 1, pos2 - pos - 1). 1278 split('|'); 1279 name = items2[0]; 1280 } 1281 } 1282 if (name.isEmpty()) 1283 name = addr; 1284 1285 item = find_uuid(uuid); 1286 if (item) { 1287 QVariant var = item->data(peer_role_config_methods); 1288 QVariant var2 = item->data(peer_role_dev_passwd_id); 1289 if ((var.isValid() && config_methods != var.toInt()) || 1290 (var2.isValid() && dev_passwd_id != var2.toInt())) 1291 remove_enrollee_uuid(uuid); 1292 else 1293 return; 1294 } 1295 1296 item = new QStandardItem(*laptop_icon, name); 1297 if (item) { 1298 item->setData(uuid, peer_role_uuid); 1299 item->setData(addr, peer_role_address); 1300 item->setData(PEER_TYPE_WPS_ENROLLEE, 1301 peer_role_type); 1302 item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); 1303 item->setData(items.join(QString("\n")), 1304 peer_role_details); 1305 item->setData(pri_dev_type, peer_role_pri_dev_type); 1306 item->setData(config_methods, 1307 peer_role_config_methods); 1308 item->setData(dev_passwd_id, peer_role_dev_passwd_id); 1309 model.appendRow(item); 1310 } 1311 1312 return; 1313 } 1314 1315 if (text.startsWith(WPA_EVENT_BSS_ADDED)) { 1316 /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ 1317 QStringList items = text.split(' '); 1318 if (items.size() < 2) 1319 return; 1320 char cmd[20]; 1321 snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); 1322 add_bss(cmd); 1323 return; 1324 } 1325 1326 if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { 1327 /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ 1328 QStringList items = text.split(' '); 1329 if (items.size() < 2) 1330 return; 1331 remove_bss(items[1].toInt()); 1332 return; 1333 } 1334 } 1335 1336 ctx_p2p_connect()1337 void Peers::ctx_p2p_connect() 1338 { 1339 if (ctx_item == NULL) 1340 return; 1341 QString addr = ctx_item->data(peer_role_address).toString(); 1342 QString arg; 1343 int config_methods = 1344 ctx_item->data(peer_role_config_methods).toInt(); 1345 enum selected_method method = SEL_METHOD_NONE; 1346 QVariant var = ctx_item->data(peer_role_selected_method); 1347 if (var.isValid()) 1348 method = (enum selected_method) var.toInt(); 1349 if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) { 1350 arg = ctx_item->data(peer_role_selected_pin).toString(); 1351 char cmd[100]; 1352 char reply[100]; 1353 size_t reply_len; 1354 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", 1355 addr.toLocal8Bit().constData(), 1356 arg.toLocal8Bit().constData()); 1357 reply_len = sizeof(reply) - 1; 1358 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1359 QMessageBox msg; 1360 msg.setIcon(QMessageBox::Warning); 1361 msg.setText("Failed to initiate P2P connect."); 1362 msg.exec(); 1363 return; 1364 } 1365 QMessageBox::information(this, 1366 tr("PIN for ") + ctx_item->text(), 1367 tr("Enter the following PIN on the\n" 1368 "peer device: ") + arg); 1369 } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) { 1370 StringQuery input(tr("PIN from peer display:")); 1371 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1372 if (input.exec() != QDialog::Accepted) 1373 return; 1374 arg = input.get_string(); 1375 } else if (config_methods == 0x0080 /* PBC */) { 1376 arg = "pbc"; 1377 } else { 1378 StringQuery input(tr("PIN:")); 1379 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1380 if (input.exec() != QDialog::Accepted) 1381 return; 1382 arg = input.get_string(); 1383 } 1384 1385 char cmd[100]; 1386 char reply[100]; 1387 size_t reply_len; 1388 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", 1389 addr.toLocal8Bit().constData(), 1390 arg.toLocal8Bit().constData()); 1391 reply_len = sizeof(reply) - 1; 1392 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1393 QMessageBox msg; 1394 msg.setIcon(QMessageBox::Warning); 1395 msg.setText("Failed to initiate P2P connect."); 1396 msg.exec(); 1397 } 1398 } 1399 1400 ctx_p2p_req_pin()1401 void Peers::ctx_p2p_req_pin() 1402 { 1403 if (ctx_item == NULL) 1404 return; 1405 QString addr = ctx_item->data(peer_role_address).toString(); 1406 ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY, 1407 peer_role_requested_method); 1408 1409 char cmd[100]; 1410 char reply[100]; 1411 size_t reply_len; 1412 snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display", 1413 addr.toLocal8Bit().constData()); 1414 reply_len = sizeof(reply) - 1; 1415 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1416 QMessageBox msg; 1417 msg.setIcon(QMessageBox::Warning); 1418 msg.setText(tr("Failed to request PIN from peer.")); 1419 msg.exec(); 1420 } 1421 } 1422 1423 ctx_p2p_show_pin()1424 void Peers::ctx_p2p_show_pin() 1425 { 1426 if (ctx_item == NULL) 1427 return; 1428 QString addr = ctx_item->data(peer_role_address).toString(); 1429 ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, 1430 peer_role_requested_method); 1431 1432 char cmd[100]; 1433 char reply[100]; 1434 size_t reply_len; 1435 snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad", 1436 addr.toLocal8Bit().constData()); 1437 reply_len = sizeof(reply) - 1; 1438 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1439 QMessageBox msg; 1440 msg.setIcon(QMessageBox::Warning); 1441 msg.setText(tr("Failed to request peer to enter PIN.")); 1442 msg.exec(); 1443 } 1444 } 1445 1446 ctx_p2p_display_pin()1447 void Peers::ctx_p2p_display_pin() 1448 { 1449 if (ctx_item == NULL) 1450 return; 1451 QString addr = ctx_item->data(peer_role_address).toString(); 1452 1453 char cmd[100]; 1454 char reply[100]; 1455 size_t reply_len; 1456 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin", 1457 addr.toLocal8Bit().constData()); 1458 reply_len = sizeof(reply) - 1; 1459 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1460 QMessageBox msg; 1461 msg.setIcon(QMessageBox::Warning); 1462 msg.setText("Failed to initiate P2P connect."); 1463 msg.exec(); 1464 return; 1465 } 1466 reply[reply_len] = '\0'; 1467 QMessageBox::information(this, 1468 tr("PIN for ") + ctx_item->text(), 1469 tr("Enter the following PIN on the\n" 1470 "peer device: ") + reply); 1471 } 1472 1473 ctx_p2p_display_pin_pd()1474 void Peers::ctx_p2p_display_pin_pd() 1475 { 1476 if (ctx_item == NULL) 1477 return; 1478 QString addr = ctx_item->data(peer_role_address).toString(); 1479 QString arg = ctx_item->data(peer_role_selected_pin).toString(); 1480 1481 char cmd[100]; 1482 char reply[100]; 1483 size_t reply_len; 1484 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", 1485 addr.toLocal8Bit().constData(), 1486 arg.toLocal8Bit().constData()); 1487 reply_len = sizeof(reply) - 1; 1488 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1489 QMessageBox msg; 1490 msg.setIcon(QMessageBox::Warning); 1491 msg.setText("Failed to initiate P2P connect."); 1492 msg.exec(); 1493 return; 1494 } 1495 reply[reply_len] = '\0'; 1496 QMessageBox::information(this, 1497 tr("PIN for ") + ctx_item->text(), 1498 tr("Enter the following PIN on the\n" 1499 "peer device: ") + arg); 1500 } 1501 1502 ctx_p2p_enter_pin()1503 void Peers::ctx_p2p_enter_pin() 1504 { 1505 if (ctx_item == NULL) 1506 return; 1507 QString addr = ctx_item->data(peer_role_address).toString(); 1508 QString arg; 1509 1510 StringQuery input(tr("PIN from peer:")); 1511 input.setWindowTitle(tr("PIN for ") + ctx_item->text()); 1512 if (input.exec() != QDialog::Accepted) 1513 return; 1514 arg = input.get_string(); 1515 1516 char cmd[100]; 1517 char reply[100]; 1518 size_t reply_len; 1519 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad", 1520 addr.toLocal8Bit().constData(), 1521 arg.toLocal8Bit().constData()); 1522 reply_len = sizeof(reply) - 1; 1523 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1524 QMessageBox msg; 1525 msg.setIcon(QMessageBox::Warning); 1526 msg.setText("Failed to initiate P2P connect."); 1527 msg.exec(); 1528 } 1529 } 1530 1531 ctx_p2p_remove_group()1532 void Peers::ctx_p2p_remove_group() 1533 { 1534 if (ctx_item == NULL) 1535 return; 1536 char cmd[100]; 1537 char reply[100]; 1538 size_t reply_len; 1539 snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", 1540 ctx_item->data(peer_role_ifname).toString().toLocal8Bit(). 1541 constData()); 1542 reply_len = sizeof(reply) - 1; 1543 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1544 QMessageBox msg; 1545 msg.setIcon(QMessageBox::Warning); 1546 msg.setText("Failed to remove P2P Group."); 1547 msg.exec(); 1548 } 1549 } 1550 1551 closeEvent(QCloseEvent *)1552 void Peers::closeEvent(QCloseEvent *) 1553 { 1554 if (wpagui) { 1555 char reply[20]; 1556 size_t replylen = sizeof(reply) - 1; 1557 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); 1558 } 1559 } 1560 1561 done(int r)1562 void Peers::done(int r) 1563 { 1564 QDialog::done(r); 1565 close(); 1566 } 1567 1568 remove_enrollee_uuid(QString uuid)1569 void Peers::remove_enrollee_uuid(QString uuid) 1570 { 1571 if (model.rowCount() == 0) 1572 return; 1573 1574 QModelIndexList lst = model.match(model.index(0, 0), 1575 peer_role_uuid, uuid); 1576 for (int i = 0; i < lst.size(); i++) { 1577 QStandardItem *item = model.itemFromIndex(lst[i]); 1578 if (item == NULL) 1579 continue; 1580 int type = item->data(peer_role_type).toInt(); 1581 if (type == PEER_TYPE_WPS_ER_ENROLLEE || 1582 type == PEER_TYPE_WPS_ENROLLEE) 1583 model.removeRow(lst[i].row()); 1584 } 1585 } 1586 1587 properties()1588 void Peers::properties() 1589 { 1590 if (ctx_item == NULL) 1591 return; 1592 1593 QMessageBox msg(this); 1594 msg.setStandardButtons(QMessageBox::Ok); 1595 msg.setDefaultButton(QMessageBox::Ok); 1596 msg.setEscapeButton(QMessageBox::Ok); 1597 msg.setWindowTitle(tr("Peer Properties")); 1598 1599 int type = ctx_item->data(peer_role_type).toInt(); 1600 QString title = Peers::ItemType(type); 1601 1602 msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); 1603 1604 QVariant var; 1605 QString info; 1606 1607 var = ctx_item->data(peer_role_address); 1608 if (var.isValid()) 1609 info += tr("Address: ") + var.toString() + QString("\n"); 1610 1611 var = ctx_item->data(peer_role_uuid); 1612 if (var.isValid()) 1613 info += tr("UUID: ") + var.toString() + QString("\n"); 1614 1615 var = ctx_item->data(peer_role_pri_dev_type); 1616 if (var.isValid()) 1617 info += tr("Primary Device Type: ") + var.toString() + 1618 QString("\n"); 1619 1620 var = ctx_item->data(peer_role_ssid); 1621 if (var.isValid()) 1622 info += tr("SSID: ") + var.toString() + QString("\n"); 1623 1624 var = ctx_item->data(peer_role_config_methods); 1625 if (var.isValid()) { 1626 int methods = var.toInt(); 1627 info += tr("Configuration Methods: "); 1628 if (methods & 0x0001) 1629 info += tr("[USBA]"); 1630 if (methods & 0x0002) 1631 info += tr("[Ethernet]"); 1632 if (methods & 0x0004) 1633 info += tr("[Label]"); 1634 if (methods & 0x0008) 1635 info += tr("[Display]"); 1636 if (methods & 0x0010) 1637 info += tr("[Ext. NFC Token]"); 1638 if (methods & 0x0020) 1639 info += tr("[Int. NFC Token]"); 1640 if (methods & 0x0040) 1641 info += tr("[NFC Interface]"); 1642 if (methods & 0x0080) 1643 info += tr("[Push Button]"); 1644 if (methods & 0x0100) 1645 info += tr("[Keypad]"); 1646 info += "\n"; 1647 } 1648 1649 var = ctx_item->data(peer_role_selected_method); 1650 if (var.isValid()) { 1651 enum selected_method method = 1652 (enum selected_method) var.toInt(); 1653 switch (method) { 1654 case SEL_METHOD_NONE: 1655 break; 1656 case SEL_METHOD_PIN_PEER_DISPLAY: 1657 info += tr("Selected Method: PIN on peer display\n"); 1658 break; 1659 case SEL_METHOD_PIN_LOCAL_DISPLAY: 1660 info += tr("Selected Method: PIN on local display\n"); 1661 break; 1662 } 1663 } 1664 1665 var = ctx_item->data(peer_role_selected_pin); 1666 if (var.isValid()) { 1667 info += tr("PIN to enter on peer: ") + var.toString() + "\n"; 1668 } 1669 1670 var = ctx_item->data(peer_role_dev_passwd_id); 1671 if (var.isValid()) { 1672 info += tr("Device Password ID: ") + var.toString(); 1673 switch (var.toInt()) { 1674 case 0: 1675 info += tr(" (Default PIN)"); 1676 break; 1677 case 1: 1678 info += tr(" (User-specified PIN)"); 1679 break; 1680 case 2: 1681 info += tr(" (Machine-specified PIN)"); 1682 break; 1683 case 3: 1684 info += tr(" (Rekey)"); 1685 break; 1686 case 4: 1687 info += tr(" (Push Button)"); 1688 break; 1689 case 5: 1690 info += tr(" (Registrar-specified)"); 1691 break; 1692 } 1693 info += "\n"; 1694 } 1695 1696 msg.setInformativeText(info); 1697 1698 var = ctx_item->data(peer_role_details); 1699 if (var.isValid()) 1700 msg.setDetailedText(var.toString()); 1701 1702 msg.exec(); 1703 } 1704 1705 connect_pbc()1706 void Peers::connect_pbc() 1707 { 1708 if (ctx_item == NULL) 1709 return; 1710 1711 char cmd[100]; 1712 char reply[100]; 1713 size_t reply_len; 1714 1715 int peer_type = ctx_item->data(peer_role_type).toInt(); 1716 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { 1717 snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", 1718 ctx_item->data(peer_role_uuid).toString().toLocal8Bit(). 1719 constData()); 1720 } else if (peer_type == PEER_TYPE_P2P || 1721 peer_type == PEER_TYPE_P2P_CLIENT) { 1722 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc", 1723 ctx_item->data(peer_role_address).toString(). 1724 toLocal8Bit().constData()); 1725 } else { 1726 snprintf(cmd, sizeof(cmd), "WPS_PBC"); 1727 } 1728 reply_len = sizeof(reply) - 1; 1729 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1730 QMessageBox msg; 1731 msg.setIcon(QMessageBox::Warning); 1732 msg.setText(tr("Failed to start WPS PBC.")); 1733 msg.exec(); 1734 } 1735 } 1736 1737 learn_ap_config()1738 void Peers::learn_ap_config() 1739 { 1740 if (ctx_item == NULL) 1741 return; 1742 1743 QString uuid = ctx_item->data(peer_role_uuid).toString(); 1744 1745 StringQuery input(tr("AP PIN:")); 1746 input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); 1747 if (input.exec() != QDialog::Accepted) 1748 return; 1749 1750 char cmd[100]; 1751 char reply[100]; 1752 size_t reply_len; 1753 1754 snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", 1755 uuid.toLocal8Bit().constData(), 1756 input.get_string().toLocal8Bit().constData()); 1757 reply_len = sizeof(reply) - 1; 1758 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { 1759 QMessageBox msg; 1760 msg.setIcon(QMessageBox::Warning); 1761 msg.setText(tr("Failed to start learning AP configuration.")); 1762 msg.exec(); 1763 } 1764 } 1765 1766 ctx_hide_ap()1767 void Peers::ctx_hide_ap() 1768 { 1769 hide_ap = true; 1770 1771 if (model.rowCount() == 0) 1772 return; 1773 1774 do { 1775 QModelIndexList lst; 1776 lst = model.match(model.index(0, 0), 1777 peer_role_type, PEER_TYPE_AP); 1778 if (lst.size() == 0) { 1779 lst = model.match(model.index(0, 0), 1780 peer_role_type, PEER_TYPE_AP_WPS); 1781 if (lst.size() == 0) 1782 break; 1783 } 1784 1785 model.removeRow(lst[0].row()); 1786 } while (1); 1787 } 1788 1789 ctx_show_ap()1790 void Peers::ctx_show_ap() 1791 { 1792 hide_ap = false; 1793 add_scan_results(); 1794 } 1795 1796 ctx_p2p_show_passphrase()1797 void Peers::ctx_p2p_show_passphrase() 1798 { 1799 char reply[64]; 1800 size_t reply_len; 1801 1802 reply_len = sizeof(reply) - 1; 1803 if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 || 1804 memcmp(reply, "FAIL", 4) == 0) { 1805 QMessageBox msg; 1806 msg.setIcon(QMessageBox::Warning); 1807 msg.setText("Failed to get P2P group passphrase."); 1808 msg.exec(); 1809 } else { 1810 reply[reply_len] = '\0'; 1811 QMessageBox::information(this, tr("Passphrase"), 1812 tr("P2P group passphrase:\n") + 1813 reply); 1814 } 1815 } 1816 1817 ctx_p2p_start_persistent()1818 void Peers::ctx_p2p_start_persistent() 1819 { 1820 if (ctx_item == NULL) 1821 return; 1822 1823 char cmd[100]; 1824 char reply[100]; 1825 size_t reply_len; 1826 1827 snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d", 1828 ctx_item->data(peer_role_network_id).toInt()); 1829 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || 1830 memcmp(reply, "FAIL", 4) == 0) { 1831 QMessageBox msg; 1832 msg.setIcon(QMessageBox::Warning); 1833 msg.setText(tr("Failed to start persistent P2P Group.")); 1834 msg.exec(); 1835 } else if (ctx_item->data(peer_role_type).toInt() == 1836 PEER_TYPE_P2P_INVITATION) 1837 model.removeRow(ctx_item->row()); 1838 } 1839 1840 ctx_p2p_invite()1841 void Peers::ctx_p2p_invite() 1842 { 1843 if (ctx_item == NULL) 1844 return; 1845 1846 char cmd[100]; 1847 char reply[100]; 1848 size_t reply_len; 1849 1850 snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d", 1851 ctx_item->data(peer_role_network_id).toInt()); 1852 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || 1853 memcmp(reply, "FAIL", 4) == 0) { 1854 QMessageBox msg; 1855 msg.setIcon(QMessageBox::Warning); 1856 msg.setText(tr("Failed to invite peer to start persistent " 1857 "P2P Group.")); 1858 msg.exec(); 1859 } 1860 } 1861 1862 ctx_p2p_delete()1863 void Peers::ctx_p2p_delete() 1864 { 1865 if (ctx_item == NULL) 1866 return; 1867 model.removeRow(ctx_item->row()); 1868 } 1869 1870 enable_persistent(int id)1871 void Peers::enable_persistent(int id) 1872 { 1873 if (model.rowCount() == 0) 1874 return; 1875 1876 QModelIndexList lst = model.match(model.index(0, 0), 1877 peer_role_network_id, id); 1878 for (int i = 0; i < lst.size(); i++) { 1879 QStandardItem *item = model.itemFromIndex(lst[i]); 1880 int type = item->data(peer_role_type).toInt(); 1881 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || 1882 type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) 1883 item->setBackground(Qt::NoBrush); 1884 } 1885 } 1886