peers.cpp 45 KB

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