gfawifimon.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <regex>
  6. #include <poll.h>
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include <limits.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <asm/types.h>
  13. #include <sys/socket.h>
  14. #include <net/if.h>
  15. #include "gfanetmon.h"
  16. /////////////////////////////////////////////////////////////////////////////
  17. #define TRACE(...) printf(__VA_ARGS__), fflush(stdout)
  18. #define _KILO 1000
  19. #define _MEGA (_KILO * 1000)
  20. #define _GIGA (_MEGA * 1000)
  21. #define _WPA_SUPP_CONF_PATH "/etc/wpa_supplicant/wpa_supplicant.conf"
  22. #define _UNUSED(arg) (void)arg
  23. #ifndef _countof
  24. #define _countof(a) (sizeof((a)) / sizeof(*(a)))
  25. #endif // _countof
  26. /////////////////////////////////////////////////////////////////////////////
  27. // Scan state and meta-information, used to decode events...
  28. typedef struct iwscan_state
  29. {
  30. int ap_num; // Access Point number 1->N
  31. int val_index; // Value in table 0->(N-1)
  32. }iwscan_state;
  33. static inline char *iw_saether_ntop(const struct sockaddr *sap, char* bufp)
  34. {
  35. iw_ether_ntop((const struct ether_addr*)sap->sa_data, bufp);
  36. return bufp;
  37. }
  38. static const char * iw_ie_cypher_name[] =
  39. {
  40. "none",
  41. "WEP-40",
  42. "TKIP",
  43. "WRAP",
  44. "CCMP",
  45. "WEP-104"
  46. };
  47. #define IW_IE_CYPHER_NUM _countof(iw_ie_cypher_name)
  48. static const char * iw_ie_cypher_name_wpa[] =
  49. {
  50. "none",
  51. "WEP-40",
  52. "WPA",
  53. "WRAP",
  54. "WPA2",
  55. "WEP-104"
  56. };
  57. #define IW_IE_CYPHER_WPA_NUM _countof(iw_ie_cypher_name_wpa)
  58. static bool _FindString(const std::vector<std::string> &arr, const char *pszFind)
  59. {
  60. for(std::string s : arr)
  61. {
  62. if(!s.compare(pszFind))
  63. return true;
  64. }
  65. return false;
  66. }
  67. static bool _PushIfNotExists(std::vector<std::string> &arr, const char *pszNew)
  68. {
  69. if(!_FindString(arr, pszNew))
  70. {
  71. arr.push_back(std::string(pszNew));
  72. return true;
  73. }
  74. return false;
  75. }
  76. static int _GetConnectionInfo(int nIwFd, const char *pszIfName, struct wireless_info *info)
  77. {
  78. struct iwreq wrq;
  79. memset((char*) info, 0, sizeof(struct wireless_info));
  80. /* Get basic information */
  81. if(::iw_get_basic_config(nIwFd, pszIfName, &(info->b)) < 0)
  82. {
  83. /* If no wireless name : no wireless extensions */
  84. /* But let's check if the interface exists at all */
  85. struct ifreq ifr;
  86. strncpy(ifr.ifr_name, pszIfName, IFNAMSIZ);
  87. if(::ioctl(nIwFd, SIOCGIFFLAGS, &ifr) < 0)
  88. return -ENODEV;
  89. else
  90. return -ENOTSUP;
  91. }
  92. /* Get ranges */
  93. if(::iw_get_range_info(nIwFd, pszIfName, &(info->range)) >= 0)
  94. info->has_range = 1;
  95. /* Get AP address */
  96. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWAP, &wrq) >= 0)
  97. {
  98. info->has_ap_addr = 1;
  99. memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
  100. }
  101. /* Get bit rate */
  102. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWRATE, &wrq) >= 0)
  103. {
  104. info->has_bitrate = 1;
  105. memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
  106. }
  107. /* Get Power Management settings */
  108. wrq.u.power.flags = 0;
  109. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWPOWER, &wrq) >= 0)
  110. {
  111. info->has_power = 1;
  112. memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
  113. }
  114. /* Get stats */
  115. if(::iw_get_stats(nIwFd, pszIfName, &(info->stats), &info->range, info->has_range) >= 0)
  116. {
  117. info->has_stats = 1;
  118. }
  119. //#ifndef WE_ESSENTIAL
  120. /* Get NickName */
  121. wrq.u.essid.pointer = (caddr_t) info->nickname;
  122. wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
  123. wrq.u.essid.flags = 0;
  124. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWNICKN, &wrq) >= 0)
  125. if(wrq.u.data.length > 1)
  126. info->has_nickname = 1;
  127. if((info->has_range) && (info->range.we_version_compiled > 9))
  128. {
  129. /* Get Transmit Power */
  130. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWTXPOW, &wrq) >= 0)
  131. {
  132. info->has_txpower = 1;
  133. memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
  134. }
  135. }
  136. /* Get sensitivity */
  137. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWSENS, &wrq) >= 0)
  138. {
  139. info->has_sens = 1;
  140. memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
  141. }
  142. if((info->has_range) && (info->range.we_version_compiled > 10))
  143. {
  144. /* Get retry limit/lifetime */
  145. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWRETRY, &wrq) >= 0)
  146. {
  147. info->has_retry = 1;
  148. memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
  149. }
  150. }
  151. /* Get RTS threshold */
  152. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWRTS, &wrq) >= 0)
  153. {
  154. info->has_rts = 1;
  155. memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
  156. }
  157. /* Get fragmentation threshold */
  158. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWFRAG, &wrq) >= 0)
  159. {
  160. info->has_frag = 1;
  161. memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
  162. }
  163. //#endif /* WE_ESSENTIAL */
  164. return 0;
  165. }
  166. /////////////////////////////////////////////////////////////////////////////
  167. /////////////////////////////////////////////////////////////////////////////
  168. /////////////////////////////////////////////////////////////////////////////
  169. CWpaSupplicantConfig::CWpaSupplicantConfig(void)
  170. {
  171. }
  172. CWpaSupplicantConfig::~CWpaSupplicantConfig(void)
  173. {
  174. }
  175. bool CWpaSupplicantConfig::WriteConfig(const char *pszEssID, const char *pszPassphrase, const char *pszGoupCiphers, const char *pszPairwCiphers)
  176. {
  177. std::string sKey;
  178. if(WpaKeyFromPassphrase(pszEssID, pszPassphrase, sKey))
  179. {
  180. FILE *fp = fopen(_WPA_SUPP_CONF_PATH, "w");
  181. if(fp)
  182. {
  183. fprintf(fp, "ctrl_interface=/var/run/wpa_supplicant\n");
  184. fprintf(fp, "ap_scan=1\n");
  185. fprintf(fp, "\n");
  186. fprintf(fp, "network={\n");
  187. fprintf(fp, " ssid=\"%s\"\n", pszEssID);
  188. fprintf(fp, " scan_ssid=1\n");
  189. fprintf(fp, " proto=RSN\n");
  190. fprintf(fp, " key_mgmt=WPA-PSK\n");
  191. fprintf(fp, " pairwise=%s\n", pszPairwCiphers);
  192. fprintf(fp, " group=%s\n", pszGoupCiphers);
  193. fprintf(fp, " psk=%s\n", sKey.c_str());
  194. fprintf(fp, "}\n");
  195. fclose(fp);
  196. return true;
  197. }
  198. }
  199. return false;
  200. }
  201. bool CWpaSupplicantConfig::WpaKeyFromPassphrase(const char *pszEssID, const char *pszPassphrase, std::string &key)
  202. {
  203. bool bSuccess = false;
  204. if(pszEssID && *pszEssID && pszPassphrase && *pszPassphrase)
  205. {
  206. // int ls = strlen(pszEssID);
  207. int lp = strlen(pszPassphrase);
  208. if(lp >= 8 && lp <= 63)
  209. {
  210. int c;
  211. std::string ret;
  212. char cmd[256];
  213. sprintf(cmd, "wpa_passphrase \"%s\" \"%s\"", pszEssID, pszPassphrase);
  214. static const std::string srex = "\\s*psk\\=([0-9a-fA-F]{64})";
  215. static std::regex rex(srex, std::regex_constants::ECMAScript | std::regex_constants::optimize);
  216. FILE *fp = popen(cmd, "r");
  217. if(fp)
  218. {
  219. std::cmatch res;
  220. while((c = fgetc(fp)) != EOF)
  221. {
  222. ret += (char)c;
  223. }
  224. pclose(fp);
  225. if(regex_search(ret.c_str(), res, rex) && (res.size() == 2) && (res[1].length() == 64))
  226. {
  227. key = res[1].str();
  228. bSuccess = true;
  229. }
  230. }
  231. }
  232. }
  233. return bSuccess;
  234. }
  235. /////////////////////////////////////////////////////////////////////////////
  236. /////////////////////////////////////////////////////////////////////////////
  237. /////////////////////////////////////////////////////////////////////////////
  238. class CDynBuf
  239. {
  240. public:
  241. CDynBuf(size_t nCbInc = 1024) : m_pBuf(nullptr), m_nCbBuf(0), m_nCbInc(nCbInc ? nCbInc : 1024) {
  242. Realloc();
  243. }
  244. virtual ~CDynBuf(void) {
  245. Free();
  246. }
  247. public:
  248. bool Realloc(size_t nCbInc = 0) {
  249. if(!nCbInc)
  250. nCbInc = m_nCbInc;
  251. if((m_pBuf = realloc(m_pBuf, m_nCbBuf + nCbInc))) {
  252. m_nCbBuf += nCbInc;
  253. return true;
  254. }
  255. return false;
  256. }
  257. void Free(void) {
  258. if(m_pBuf) {
  259. free(m_pBuf);
  260. m_pBuf = nullptr;
  261. }
  262. m_nCbBuf = 0;
  263. }
  264. size_t Size(void) const {
  265. return m_nCbBuf;
  266. }
  267. public:
  268. operator void* (void) {
  269. return m_pBuf;
  270. }
  271. operator const void* (void) const {
  272. return m_pBuf;
  273. }
  274. private:
  275. void *m_pBuf;
  276. size_t m_nCbBuf;
  277. size_t m_nCbInc;
  278. };
  279. /////////////////////////////////////////////////////////////////////////////
  280. /////////////////////////////////////////////////////////////////////////////
  281. /////////////////////////////////////////////////////////////////////////////
  282. CGfaWifiScanResults::CGfaWifiScanResults(void)
  283. {
  284. Clear();
  285. }
  286. CGfaWifiScanResults::~CGfaWifiScanResults(void)
  287. {
  288. }
  289. uint32_t CGfaWifiScanResults::CompactTrailingZeros(uint32_t v) const
  290. {
  291. if(v > 0)
  292. {
  293. while(!(v % 10))
  294. v /= 10;
  295. }
  296. return v;
  297. }
  298. uint32_t CGfaWifiScanResults::PercentFromDbm(int nDbm)
  299. {
  300. if(nDbm < -100)
  301. return 0;
  302. else if(nDbm > -50)
  303. return 100;
  304. else
  305. return 2 * nDbm + 200;
  306. }
  307. uint32_t CGfaWifiScanResults::BarsFromPercent(uint32_t nPerc)
  308. {
  309. if(nPerc > 100)
  310. nPerc = 100;
  311. return nPerc * 7 / 100;
  312. }
  313. std::string CGfaWifiScanResults::ConcatStrings(std::vector<std::string> &arr)
  314. {
  315. std::string s;
  316. size_t cnt = arr.size();
  317. if(cnt > 0)
  318. {
  319. s = arr[0];
  320. for(size_t i = 1; i < arr.size(); ++i)
  321. {
  322. s += " ";
  323. s += arr[i];
  324. }
  325. }
  326. return s;
  327. }
  328. std::string CGfaWifiScanResults::GetBitrateStr(int index) const
  329. {
  330. uint32_t br = GetBitrate(index);
  331. if(br > 0)
  332. {
  333. char buf[64];
  334. uint32_t i, f;
  335. if(br >= _GIGA)
  336. {
  337. i = br / _GIGA;
  338. f = CompactTrailingZeros(br % _GIGA);
  339. sprintf(buf, "%u.%u Gb/s", i, f);
  340. }
  341. else if(br >= _MEGA)
  342. {
  343. i = br / _MEGA;
  344. f = CompactTrailingZeros(br % _MEGA);
  345. sprintf(buf, "%u.%u Mb/s", i, f);
  346. }
  347. else if(br >= _KILO)
  348. {
  349. i = br / _KILO;
  350. f = CompactTrailingZeros(br % _KILO);
  351. sprintf(buf, "%u.%u Kb/s", i, f);
  352. }
  353. else
  354. {
  355. sprintf(buf, "%u b/s", br);
  356. }
  357. return buf;
  358. }
  359. return "n/a";
  360. }
  361. std::string CGfaWifiScanResults::GetFreqStr(void) const
  362. {
  363. double fq = GetFreqHz();
  364. if(fq > 0.0)
  365. {
  366. char buf[64];
  367. if(fq >= _GIGA)
  368. {
  369. sprintf(buf, "%.3f GHz", fq / 1000000000.0);
  370. }
  371. else if(fq >= _MEGA)
  372. {
  373. sprintf(buf, "%.3f MHz", fq / 1000000.0);
  374. }
  375. else if(fq >= _KILO)
  376. {
  377. sprintf(buf, "%.3f kHz", fq / 1000.0);
  378. }
  379. else
  380. {
  381. sprintf(buf, "%.3f Hz", fq);
  382. }
  383. return buf;
  384. }
  385. return "n/a";
  386. }
  387. void CGfaWifiScanResults::SetQualityPercAndBars(const iwqual *qual, const iwrange *range, int has_range)
  388. {
  389. qualPerc = qualBars = 0;
  390. if(has_range && ((qual->level != 0) || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
  391. {
  392. // Deal with quality : always a relative value
  393. if(!(qual->updated & IW_QUAL_QUAL_INVALID))
  394. {
  395. qualPerc = (uint32_t)qual->qual * 100 / (uint32_t)range->max_qual.qual;
  396. }
  397. // Check if the statistics are in RCPI (IEEE 802.11k)
  398. if(qual->updated & IW_QUAL_RCPI)
  399. {
  400. // Deal with signal level in RCPI
  401. // RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm
  402. if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
  403. {
  404. double rcpilevel = ((double)qual->level / 2.0) - 110.0;
  405. qualPerc = PercentFromDbm((int)rcpilevel);
  406. }
  407. }
  408. else
  409. {
  410. // Check if the statistics are in dBm
  411. if((qual->updated & IW_QUAL_DBM) || (qual->level > range->max_qual.level))
  412. {
  413. // Deal with signal level in dBm (absolute power measurement)
  414. if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
  415. {
  416. int dblevel = qual->level;
  417. // Implement a range for dBm [-192; 63]
  418. if(qual->level >= 64)
  419. dblevel -= 0x100;
  420. qualPerc = PercentFromDbm(dblevel);
  421. }
  422. }
  423. else
  424. {
  425. // Deal with signal level as relative value (0 -> max)
  426. if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
  427. {
  428. qualPerc = (uint32_t)qual->level * 100 / (uint32_t)range->max_qual.level;
  429. }
  430. }
  431. }
  432. qualBars = BarsFromPercent(qualPerc);
  433. }
  434. }
  435. static const char* iw_print_value_name(unsigned int value, const char *names[], const unsigned int num_names)
  436. {
  437. if(value >= num_names)
  438. return "";
  439. else
  440. return names[value];
  441. }
  442. void CGfaWifiScanResults::SetWPAStrings(unsigned char *iebuf, int buflen)
  443. {
  444. int ielen = iebuf[1] + 2;
  445. int offset = 2; // Skip the IE id, and the length.
  446. unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
  447. unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
  448. unsigned char *wpa_oui;
  449. int i;
  450. // uint16_t ver = 0;
  451. uint16_t cnt = 0;
  452. if(ielen > buflen)
  453. ielen = buflen;
  454. switch(iebuf[0])
  455. {
  456. case 0x30: /* WPA2 */
  457. /* Check if we have enough data */
  458. if(ielen < 4)
  459. {
  460. // iw_print_ie_unknown(iebuf, buflen);
  461. return;
  462. }
  463. wpa_oui = wpa2_oui;
  464. break;
  465. case 0xdd: /* WPA or else */
  466. wpa_oui = wpa1_oui;
  467. /* Not all IEs that start with 0xdd are WPA.
  468. * So check that the OUI is valid. Note : offset==2 */
  469. if((ielen < 8) || (memcmp(&iebuf[offset], wpa_oui, 3) != 0) || (iebuf[offset + 3] != 0x01))
  470. return;
  471. /* Skip the OUI type */
  472. offset += 4;
  473. break;
  474. default:
  475. return;
  476. }
  477. /* Pick version number (little endian) */
  478. // ver = iebuf[offset] | (iebuf[offset + 1] << 8);
  479. offset += 2;
  480. if(iebuf[0] == 0xdd)
  481. {
  482. }
  483. if(iebuf[0] == 0x30)
  484. {
  485. // m_groupCiphers.clear();
  486. // m_pairwCiphers.clear();
  487. }
  488. // From here, everything is technically optional.
  489. // Check if we are done
  490. if(ielen < (offset + 4))
  491. {
  492. _PushIfNotExists(m_groupCiphers, "TKIP");
  493. _PushIfNotExists(m_pairwCiphers, "TKIP");
  494. return;
  495. }
  496. /* Next we have our group cipher. */
  497. if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
  498. {
  499. // m_groupCiphers.push_back(std::string("Proprietary");
  500. }
  501. else
  502. {
  503. std::string s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name, IW_IE_CYPHER_NUM);
  504. _PushIfNotExists(m_groupCiphers, s.c_str());
  505. s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name_wpa, IW_IE_CYPHER_WPA_NUM);
  506. _PushIfNotExists(m_groupCiphersWPA, s.c_str());
  507. }
  508. offset += 4;
  509. /* Check if we are done */
  510. if(ielen < (offset + 2))
  511. {
  512. /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
  513. _PushIfNotExists(m_pairwCiphers, "TKIP");
  514. return;
  515. }
  516. /* Otherwise, we have some number of pairwise ciphers. */
  517. cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
  518. offset += 2;
  519. if(ielen < (offset + 4 * cnt))
  520. return;
  521. for(i = 0; i < cnt; i++)
  522. {
  523. if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
  524. {
  525. // m_pairwCiphers.push_back(std::string("Proprietary");
  526. }
  527. else
  528. {
  529. std::string s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name, IW_IE_CYPHER_NUM);
  530. _PushIfNotExists(m_pairwCiphers, s.c_str());
  531. s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name_wpa, IW_IE_CYPHER_WPA_NUM);
  532. _PushIfNotExists(m_pairwCiphersWPA, s.c_str());
  533. }
  534. offset += 4;
  535. }
  536. }
  537. void CGfaWifiScanResults::Clear(void)
  538. {
  539. nwID = 0;
  540. channel = -1;
  541. mode = 0;
  542. encFlags = 0;
  543. qualPerc = 0;
  544. qualBars = 0;
  545. freqHz = 0.0;
  546. m_bConnected = false;
  547. memset(&ap_addr, 0, sizeof(ap_addr));
  548. memset(essid, 0, sizeof(essid));
  549. memset(qualStr, 0, sizeof(qualStr));
  550. name.clear();
  551. itfName.clear();
  552. m_bitRates.clear();
  553. m_groupCiphers.clear();
  554. m_pairwCiphers.clear();
  555. m_groupCiphersWPA.clear();
  556. m_pairwCiphersWPA.clear();
  557. }
  558. bool CGfaWifiScanResults::FromWirelessInfo(const char *pszIfName, const struct wireless_info &wli)
  559. {
  560. Clear();
  561. if(!wli.has_stats)
  562. return true;
  563. SetConnected(true);
  564. ::iw_print_stats(qualStr, sizeof(qualStr) - 1, &wli.stats.qual, &wli.range, wli.has_range);
  565. SetQualityPercAndBars(&wli.stats.qual, &wli.range, wli.has_range);
  566. if(pszIfName && *pszIfName)
  567. itfName = pszIfName;
  568. if(wli.has_ap_addr)
  569. memcpy(&ap_addr, &wli.ap_addr, sizeof(ap_addr));
  570. if(wli.b.has_nwid)
  571. nwID = wli.b.nwid.value;
  572. if(wli.b.has_freq)
  573. {
  574. freqHz = wli.b.freq;
  575. if(wli.has_range)
  576. channel = iw_freq_to_channel(freqHz, &wli.range);
  577. }
  578. if(wli.b.has_mode)
  579. mode = wli.b.mode;
  580. if(wli.b.name[0])
  581. name = wli.b.name;
  582. if(wli.b.essid_len && wli.b.essid[0])
  583. memcpy(essid, wli.b.essid, (wli.b.essid_len <= IW_ESSID_MAX_SIZE) ? wli.b.essid_len : IW_ESSID_MAX_SIZE);
  584. if(wli.has_bitrate)
  585. AddBitrate(wli.bitrate.value);
  586. return true;
  587. }
  588. /////////////////////////////////////////////////////////////////////////////
  589. /////////////////////////////////////////////////////////////////////////////
  590. /////////////////////////////////////////////////////////////////////////////
  591. CGfaWifiMon::CGfaWifiMon(void) : m_nIwFd(-1)
  592. {
  593. }
  594. CGfaWifiMon::~CGfaWifiMon(void)
  595. {
  596. IwSocketClose();
  597. }
  598. bool CGfaWifiMon::IwSocketOpen(void)
  599. {
  600. if(m_nIwFd >= 0)
  601. IwSocketClose();
  602. if((m_nIwFd = ::iw_sockets_open()) < 0)
  603. {
  604. TRACE("IwSocketOpen: Socket error '%s'!\n", strerror(errno));
  605. }
  606. return (m_nIwFd >= 0);
  607. }
  608. void CGfaWifiMon::IwSocketClose(void)
  609. {
  610. if(m_nIwFd >= 0)
  611. {
  612. ::iw_sockets_close(m_nIwFd);
  613. m_nIwFd = -1;
  614. }
  615. }
  616. int CGfaWifiMon::IwEnum(void)
  617. {
  618. char *args[] = {(char*)this};
  619. m_scres.clear();
  620. ::iw_enum_devices(m_nIwFd, &CGfaWifiMon::IwScan, args, 1);
  621. return 0;
  622. }
  623. void CGfaWifiMon::ProcessConnectedEssid(int nIwFd, const char *pszIfName, std::string &sEssid)
  624. {
  625. struct iwreq wrq;
  626. char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID */
  627. memset(essid, 0, sizeof(essid));
  628. sEssid.clear();
  629. wrq.u.essid.pointer = (caddr_t) essid;
  630. wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
  631. wrq.u.essid.flags = 0;
  632. if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWESSID, &wrq) < 0)
  633. return;
  634. sEssid = essid;
  635. if(sEssid.length() > 0)
  636. {
  637. for(CGfaWifiScanResults &scr : m_scres)
  638. {
  639. if( !scr.GetItfName().compare(pszIfName) &&
  640. !scr.GetESSID().compare(sEssid))
  641. {
  642. scr.m_bConnected = true;
  643. }
  644. }
  645. }
  646. }
  647. bool CGfaWifiMon::GetConnectionInfo(const char *pszIfName, CGfaWifiScanResults &wsr)
  648. {
  649. int nIwFd;
  650. if((nIwFd = ::iw_sockets_open()) >= 0)
  651. {
  652. struct wireless_info wli;
  653. int ret = _GetConnectionInfo(nIwFd, pszIfName, &wli);
  654. ::iw_sockets_close(nIwFd);
  655. if(ret == 0)
  656. {
  657. return wsr.FromWirelessInfo(pszIfName, wli);
  658. }
  659. }
  660. wsr.Clear();
  661. return false;
  662. }
  663. int CGfaWifiMon::IwScan(int nIwFd, char *pszIfName, char *args[], int count)
  664. {
  665. _UNUSED(nIwFd);
  666. if(count != 1)
  667. return -1;
  668. CGfaWifiMon *pThis = (CGfaWifiMon*)args[0];
  669. return pThis->IwScan(pszIfName);
  670. }
  671. int CGfaWifiMon::IwScan(const char *pszIfName)
  672. {
  673. CDynBuf dbuf(IW_SCAN_MAX_DATA);
  674. struct iwreq wrq;
  675. struct iw_scan_req scanopt; // Options for 'set'
  676. struct iw_range range;
  677. struct timeval tv; // Select timeout
  678. int nRet = 0;
  679. int timeout = 15000000; // 15s
  680. memset(&wrq, 0, sizeof(wrq));
  681. memset(&scanopt, 0, sizeof(scanopt));
  682. memset(&range, 0, sizeof(range));
  683. int has_range = (::iw_get_range_info(m_nIwFd, pszIfName, &range) >= 0);
  684. // Check if the interface could support scanning.
  685. if((!has_range) || (range.we_version_compiled < 14))
  686. {
  687. TRACE("%-8.16s: Interface doesn't support scanning.\n", pszIfName);
  688. return -1;
  689. }
  690. // Init timeout value -> 250ms between set and first get
  691. tv.tv_sec = 0;
  692. tv.tv_usec = 250000;
  693. // Initiate Scanning
  694. if(::iw_set_ext(m_nIwFd, pszIfName, SIOCSIWSCAN, &wrq) < 0)
  695. {
  696. if((errno != EPERM) /*|| (scanflags != 0)*/)
  697. {
  698. TRACE("%-8.16s Interface doesn't support scanning : %s\n", pszIfName, strerror(errno));
  699. return -1;
  700. }
  701. // If we don't have the permission to initiate the scan, we may
  702. // still have permission to read left-over results.
  703. // But, don't wait !!!
  704. tv.tv_usec = 0;
  705. }
  706. timeout -= tv.tv_usec;
  707. while(true)
  708. {
  709. bool bContinueOuter = false, bBreakOuter = false;
  710. fd_set rfds; // File descriptors for select
  711. int last_fd; // Last fd
  712. int ret;
  713. // Guess what ? We must re-generate rfds each time
  714. FD_ZERO(&rfds);
  715. last_fd = -1;
  716. // In here, add the rtnetlink fd in the list
  717. // Wait until something happens
  718. ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
  719. // Check if there was an error
  720. if(ret < 0)
  721. {
  722. if((errno == EAGAIN) || (errno == EINTR) || (errno == ECHILD))
  723. continue;
  724. TRACE("Unhandled signal - exiting...\n");
  725. return -1;
  726. }
  727. // Check if there was a timeout
  728. if(ret == 0)
  729. {
  730. do
  731. {
  732. wrq.u.data.pointer = dbuf;
  733. wrq.u.data.length = (unsigned short)dbuf.Size();
  734. wrq.u.data.flags = 0;
  735. if(::iw_get_ext(m_nIwFd, pszIfName, SIOCGIWSCAN, &wrq) < 0)
  736. {
  737. // Check if buffer was too small (WE-17 only)
  738. if((errno == E2BIG) && (range.we_version_compiled > 16))
  739. {
  740. // Some driver may return very large scan results, either
  741. // because there are many cells, or because they have many
  742. // large elements in cells (like IWEVCUSTOM). Most will
  743. // only need the regular sized buffer. We now use a dynamic
  744. // allocation of the buffer to satisfy everybody. Of course,
  745. // as we don't know in advance the size of the array, we try
  746. // various increasing sizes.
  747. // Check if the driver gave us any hints.
  748. if(wrq.u.data.length > dbuf.Size())
  749. {
  750. if(dbuf.Realloc((size_t)wrq.u.data.length - dbuf.Size()))
  751. continue;
  752. else
  753. {
  754. TRACE("Realloc failed: %s\n", strerror(errno));
  755. return -1;
  756. }
  757. }
  758. else
  759. {
  760. if(dbuf.Realloc())
  761. continue;
  762. else
  763. {
  764. TRACE("Realloc failed: %s\n", strerror(errno));
  765. return -1;
  766. }
  767. }
  768. }
  769. else if(errno == EAGAIN) // Check if results not available yet
  770. {
  771. tv.tv_sec = 0;
  772. tv.tv_usec = 100000; // Restart timer for only 100ms
  773. if(timeout > 0)
  774. {
  775. timeout -= tv.tv_usec;
  776. bContinueOuter = true; // Try again later
  777. }
  778. else
  779. {
  780. TRACE("Timeout scanning WLAN!\n");
  781. return -1;
  782. }
  783. }
  784. else
  785. {
  786. TRACE("%-8.16s Failed to read scan data : %s\n", pszIfName, strerror(errno));
  787. return -2;
  788. }
  789. }
  790. else
  791. {
  792. bBreakOuter = true;
  793. break; // We have the results, go to process them
  794. }
  795. }
  796. while(false);
  797. if(bContinueOuter)
  798. {
  799. bContinueOuter = false;
  800. continue;
  801. }
  802. if(bBreakOuter)
  803. break;
  804. }
  805. }
  806. if(wrq.u.data.length)
  807. {
  808. struct iw_event iwe;
  809. struct stream_descr stream;
  810. struct iwscan_state state = { .ap_num = -1, .val_index = 0 };
  811. int ret;
  812. ::iw_init_event_stream(&stream, (char*)(void*)dbuf, wrq.u.data.length);
  813. do
  814. {
  815. // Extract an event and store it
  816. if((ret = ::iw_extract_event_stream(&stream, &iwe, range.we_version_compiled)) > 0)
  817. {
  818. HandleScanToken(pszIfName, &stream, &iwe, &state, &range, has_range);
  819. }
  820. }
  821. while(ret > 0);
  822. }
  823. std::string sConnectedEssid;
  824. ProcessConnectedEssid(m_nIwFd, pszIfName, sConnectedEssid);
  825. return nRet;
  826. }
  827. void CGfaWifiMon::HandleScanToken( const char *pszIfName,
  828. struct stream_descr *stream,// Stream of events
  829. struct iw_event *event, // Extracted token
  830. struct iwscan_state *state,
  831. struct iw_range *iw_range, // Range info
  832. int has_range)
  833. {
  834. _UNUSED(stream);
  835. char buffer[128];
  836. CGfaWifiScanResults *pscr = nullptr;
  837. if((state->ap_num >= 0) && ((int)m_scres.size() > state->ap_num))
  838. pscr = &m_scres[state->ap_num];
  839. switch(event->cmd)
  840. {
  841. case SIOCGIWAP:
  842. if((int)m_scres.size() <= ++state->ap_num)
  843. {
  844. m_scres.emplace_back();
  845. CGfaWifiScanResults &scr = m_scres.back();
  846. if(pszIfName && *pszIfName)
  847. scr.itfName = pszIfName;
  848. memcpy(&scr.ap_addr, &event->u.ap_addr, sizeof(scr.ap_addr));
  849. TRACE("Cell %02d - Address: %s\n", state->ap_num, iw_saether_ntop(&event->u.ap_addr, buffer));
  850. }
  851. break;
  852. case SIOCGIWNWID:
  853. if(pscr)
  854. {
  855. if(event->u.nwid.disabled)
  856. {
  857. pscr->nwID = 0;
  858. TRACE(" NWID:off/any\n");
  859. }
  860. else
  861. {
  862. pscr->nwID = event->u.nwid.value;
  863. TRACE(" NWID:%X\n", event->u.nwid.value);
  864. }
  865. }
  866. break;
  867. case SIOCGIWFREQ:
  868. if(pscr)
  869. {
  870. pscr->freqHz = ::iw_freq2float(&(event->u.freq));
  871. if(has_range)
  872. pscr->channel = iw_freq_to_channel(pscr->freqHz, iw_range);
  873. }
  874. break;
  875. case SIOCGIWMODE:
  876. if(pscr)
  877. {
  878. if(event->u.mode >= IW_NUM_OPER_MODE)
  879. event->u.mode = IW_NUM_OPER_MODE;
  880. TRACE(" Mode: %s\n", iw_operation_mode[event->u.mode]);
  881. pscr->mode = event->u.mode;
  882. }
  883. break;
  884. case SIOCGIWNAME:
  885. if(pscr)
  886. {
  887. pscr->name = event->u.name;
  888. TRACE(" Protocol:%-1.16s\n", pscr->name.c_str());
  889. }
  890. break;
  891. case SIOCGIWESSID:
  892. if(pscr)
  893. {
  894. if((event->u.essid.pointer) && (event->u.essid.length))
  895. memcpy(pscr->essid, event->u.essid.pointer, (event->u.essid.length <= IW_ESSID_MAX_SIZE) ? event->u.essid.length : IW_ESSID_MAX_SIZE);
  896. if(event->u.essid.flags)
  897. {
  898. // Does it have an ESSID index?
  899. if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
  900. TRACE(" ESSID: \"%s\" [%d]\n", pscr->essid, (event->u.essid.flags & IW_ENCODE_INDEX));
  901. else
  902. TRACE(" ESSID: \"%s\"\n", pscr->essid);
  903. }
  904. else
  905. TRACE(" ESSID: off/any/hidden\n");
  906. }
  907. break;
  908. case SIOCGIWENCODE:
  909. if(pscr)
  910. {
  911. if(event->u.data.flags & IW_ENCODE_DISABLED)
  912. TRACE(" Encryption off\n");
  913. else
  914. TRACE(" Encryption on\n");
  915. pscr->encFlags = event->u.data.flags & IW_ENCODE_FLAGS;
  916. }
  917. break;
  918. case SIOCGIWRATE:
  919. if(pscr)
  920. {
  921. pscr->AddBitrate(event->u.nwid.value);
  922. }
  923. break;
  924. case SIOCGIWMODUL:
  925. if(pscr)
  926. {
  927. }
  928. break;
  929. case IWEVQUAL:
  930. if(pscr)
  931. {
  932. ::iw_print_stats(pscr->qualStr, sizeof(pscr->qualStr) - 1, &event->u.qual, iw_range, has_range);
  933. pscr->SetQualityPercAndBars(&event->u.qual, iw_range, has_range);
  934. }
  935. break;
  936. case IWEVGENIE:
  937. if(pscr)
  938. {
  939. int offset = 0;
  940. unsigned char *buffer = (unsigned char*)event->u.data.pointer;
  941. int buflen = event->u.data.length;
  942. /* Loop on each IE, each IE is minimum 2 bytes */
  943. while(offset <= (buflen - 2))
  944. {
  945. /* Check IE type */
  946. switch(buffer[offset])
  947. {
  948. case 0xdd: /* WPA1 (and other) */
  949. case 0x30: /* WPA2 */
  950. pscr->SetWPAStrings(buffer + offset, buflen);
  951. break;
  952. default:
  953. break;
  954. }
  955. /* Skip over this IE to the next one in the list. */
  956. offset += buffer[offset + 1] + 2;
  957. }
  958. }
  959. break;
  960. case IWEVCUSTOM:
  961. if(pscr)
  962. {
  963. }
  964. break;
  965. default:
  966. TRACE("Unknown Wireless Token 0x%04X\n", event->cmd);
  967. break;
  968. }
  969. }
  970. bool CGfaWifiMon::SetWpaSuppConfig(int cellidx, const char *pszPassphrase)
  971. {
  972. if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
  973. {
  974. std::string ssid = GetESSID(cellidx);
  975. std::string sgroup = GetWPAGroupCiphers(cellidx);
  976. std::string spairw = GetWPAPairwiseCiphers(cellidx);
  977. return CWpaSupplicantConfig::WriteConfig(ssid.c_str(), pszPassphrase, sgroup.c_str(), spairw.c_str());
  978. }
  979. return false;
  980. }