peers.cpp 45 KB

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