peers.cpp 22 KB

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