iwinfo.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /*
  2. * rpcd - UBUS RPC server
  3. *
  4. * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <sys/types.h>
  19. #include <ctype.h>
  20. #include <dirent.h>
  21. #include <libubus.h>
  22. #include <iwinfo.h>
  23. #include <iwinfo/utils.h>
  24. #include <net/ethernet.h>
  25. #ifdef linux
  26. #include <netinet/ether.h>
  27. #endif
  28. #include <rpcd/plugin.h>
  29. static struct blob_buf buf;
  30. static const struct iwinfo_ops *iw;
  31. static const char *ifname;
  32. enum {
  33. RPC_D_DEVICE,
  34. __RPC_D_MAX,
  35. };
  36. static const struct blobmsg_policy rpc_device_policy[__RPC_D_MAX] = {
  37. [RPC_D_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
  38. };
  39. enum {
  40. RPC_A_DEVICE,
  41. RPC_A_MACADDR,
  42. __RPC_A_MAX,
  43. };
  44. static const struct blobmsg_policy rpc_assoclist_policy[__RPC_A_MAX] = {
  45. [RPC_A_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
  46. [RPC_A_MACADDR] = { .name = "mac", .type = BLOBMSG_TYPE_STRING },
  47. };
  48. enum {
  49. RPC_U_SECTION,
  50. __RPC_U_MAX
  51. };
  52. static const struct blobmsg_policy rpc_uci_policy[__RPC_U_MAX] = {
  53. [RPC_U_SECTION] = { .name = "section", .type = BLOBMSG_TYPE_STRING },
  54. };
  55. static int
  56. __rpc_iwinfo_open(struct blob_attr *device)
  57. {
  58. if (!device)
  59. return UBUS_STATUS_INVALID_ARGUMENT;
  60. ifname = blobmsg_data(device);
  61. iw = iwinfo_backend(ifname);
  62. return iw ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND;
  63. }
  64. static int
  65. rpc_iwinfo_open(struct blob_attr *msg)
  66. {
  67. static struct blob_attr *tb[__RPC_D_MAX];
  68. blobmsg_parse(rpc_device_policy, __RPC_D_MAX, tb,
  69. blob_data(msg), blob_len(msg));
  70. return __rpc_iwinfo_open(tb[RPC_D_DEVICE]);
  71. }
  72. static void
  73. rpc_iwinfo_close(void)
  74. {
  75. iw = NULL;
  76. ifname = NULL;
  77. iwinfo_finish();
  78. }
  79. static void
  80. rpc_iwinfo_call_int(const char *name, int (*func)(const char *, int *),
  81. const char * const *map)
  82. {
  83. int rv;
  84. if (!func(ifname, &rv))
  85. {
  86. if (!map)
  87. blobmsg_add_u32(&buf, name, rv);
  88. else
  89. blobmsg_add_string(&buf, name, map[rv]);
  90. }
  91. }
  92. static void
  93. rpc_iwinfo_call_hardware_id(const char *name)
  94. {
  95. struct iwinfo_hardware_id ids;
  96. void *c;
  97. if (!iw->hardware_id(ifname, (char *)&ids))
  98. {
  99. c = blobmsg_open_array(&buf, name);
  100. blobmsg_add_u32(&buf, NULL, ids.vendor_id);
  101. blobmsg_add_u32(&buf, NULL, ids.device_id);
  102. blobmsg_add_u32(&buf, NULL, ids.subsystem_vendor_id);
  103. blobmsg_add_u32(&buf, NULL, ids.subsystem_device_id);
  104. blobmsg_close_array(&buf, c);
  105. }
  106. }
  107. static void
  108. rpc_iwinfo_lower(const char *src, char *dst, size_t len)
  109. {
  110. size_t i;
  111. for (i = 0; *src && i < len; i++)
  112. *dst++ = tolower(*src++);
  113. *dst = 0;
  114. }
  115. static void
  116. rpc_iwinfo_add_bit_array(const char *name, uint32_t bits,
  117. const char * const values[], size_t len,
  118. bool lower, uint32_t zero)
  119. {
  120. void *c;
  121. size_t i;
  122. char l[128];
  123. const char *v;
  124. if (!bits)
  125. bits = zero;
  126. c = blobmsg_open_array(&buf, name);
  127. for (i = 0; i < len; i++)
  128. if (bits & 1 << i)
  129. {
  130. v = values[i];
  131. if (lower)
  132. {
  133. rpc_iwinfo_lower(v, l, strlen(values[i]));
  134. v = l;
  135. }
  136. blobmsg_add_string(&buf, NULL, v);
  137. }
  138. blobmsg_close_array(&buf, c);
  139. }
  140. static void
  141. rpc_iwinfo_add_encryption(const char *name, struct iwinfo_crypto_entry *e)
  142. {
  143. int wpa_version;
  144. void *c, *d;
  145. c = blobmsg_open_table(&buf, name);
  146. blobmsg_add_u8(&buf, "enabled", e->enabled);
  147. if (e->enabled)
  148. {
  149. if (!e->wpa_version)
  150. {
  151. rpc_iwinfo_add_bit_array("wep", e->auth_algs,
  152. IWINFO_AUTH_NAMES,
  153. IWINFO_AUTH_COUNT,
  154. true, 0);
  155. }
  156. else
  157. {
  158. d = blobmsg_open_array(&buf, "wpa");
  159. for (wpa_version = 1; wpa_version <= 3; wpa_version++)
  160. if (e->wpa_version & (1 << (wpa_version - 1)))
  161. blobmsg_add_u32(&buf, NULL, wpa_version);
  162. blobmsg_close_array(&buf, d);
  163. rpc_iwinfo_add_bit_array("authentication",
  164. e->auth_suites,
  165. IWINFO_KMGMT_NAMES,
  166. IWINFO_KMGMT_COUNT,
  167. true, IWINFO_KMGMT_NONE);
  168. }
  169. rpc_iwinfo_add_bit_array("ciphers",
  170. e->pair_ciphers | e->group_ciphers,
  171. IWINFO_CIPHER_NAMES,
  172. IWINFO_CIPHER_COUNT,
  173. true, IWINFO_CIPHER_NONE);
  174. }
  175. blobmsg_close_table(&buf, c);
  176. }
  177. static void
  178. rpc_iwinfo_call_encryption(const char *name)
  179. {
  180. struct iwinfo_crypto_entry crypto = { 0 };
  181. if (!iw->encryption(ifname, (char *)&crypto))
  182. rpc_iwinfo_add_encryption(name, &crypto);
  183. }
  184. static void
  185. rpc_iwinfo_call_htmodes(const char *name)
  186. {
  187. int modes;
  188. if (iw->htmodelist(ifname, &modes))
  189. return;
  190. rpc_iwinfo_add_bit_array(name, modes & ~IWINFO_HTMODE_NOHT,
  191. IWINFO_HTMODE_NAMES, IWINFO_HTMODE_COUNT,
  192. false, 0);
  193. }
  194. static int
  195. rpc_iwinfo_call_hwmodes(const char *name)
  196. {
  197. int modes;
  198. if (iw->hwmodelist(ifname, &modes))
  199. return -1;
  200. rpc_iwinfo_add_bit_array(name, modes,
  201. IWINFO_80211_NAMES, IWINFO_80211_COUNT,
  202. false, 0);
  203. return modes;
  204. }
  205. static void rpc_iwinfo_call_hw_ht_mode(int hwmodelist)
  206. {
  207. char text[32];
  208. const char *hwmode_str;
  209. const char *htmode_str;
  210. int htmode;
  211. if (iwinfo_format_hwmodes(hwmodelist, text, sizeof(text)) > 0)
  212. blobmsg_add_string(&buf, "hwmodes_text", text);
  213. if (hwmodelist == IWINFO_80211_AD)
  214. {
  215. blobmsg_add_string(&buf, "hwmode", "ad");
  216. return;
  217. }
  218. if (iw->htmode(ifname, &htmode))
  219. return;
  220. htmode_str = iwinfo_htmode_name(htmode);
  221. if (htmode_str)
  222. {
  223. if (iwinfo_htmode_is_ht(htmode))
  224. hwmode_str = "n";
  225. else if (iwinfo_htmode_is_vht(htmode))
  226. hwmode_str = "ac";
  227. else if (iwinfo_htmode_is_he(htmode))
  228. hwmode_str = "ax";
  229. else
  230. hwmode_str = "a/g";
  231. } else
  232. htmode_str = hwmode_str = "unknown";
  233. blobmsg_add_string(&buf, "hwmode", hwmode_str);
  234. blobmsg_add_string(&buf, "htmode", htmode_str);
  235. }
  236. static void
  237. rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *))
  238. {
  239. char rv[IWINFO_BUFSIZE] = { 0 };
  240. if (!func(ifname, rv))
  241. blobmsg_add_string(&buf, name, rv);
  242. }
  243. static int
  244. rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj,
  245. struct ubus_request_data *req, const char *method,
  246. struct blob_attr *msg)
  247. {
  248. int rv, hwmodes;
  249. void *c;
  250. rv = rpc_iwinfo_open(msg);
  251. if (rv)
  252. return rv;
  253. blob_buf_init(&buf, 0);
  254. rpc_iwinfo_call_str("phy", iw->phyname);
  255. rpc_iwinfo_call_str("ssid", iw->ssid);
  256. rpc_iwinfo_call_str("bssid", iw->bssid);
  257. rpc_iwinfo_call_str("country", iw->country);
  258. rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES);
  259. rpc_iwinfo_call_int("channel", iw->channel, NULL);
  260. rpc_iwinfo_call_int("center_chan1", iw->center_chan1, NULL);
  261. rpc_iwinfo_call_int("center_chan2", iw->center_chan2, NULL);
  262. rpc_iwinfo_call_int("frequency", iw->frequency, NULL);
  263. rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL);
  264. rpc_iwinfo_call_int("txpower", iw->txpower, NULL);
  265. rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL);
  266. rpc_iwinfo_call_int("quality", iw->quality, NULL);
  267. rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL);
  268. rpc_iwinfo_call_int("signal", iw->signal, NULL);
  269. rpc_iwinfo_call_int("noise", iw->noise, NULL);
  270. rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL);
  271. rpc_iwinfo_call_encryption("encryption");
  272. rpc_iwinfo_call_htmodes("htmodes");
  273. hwmodes = rpc_iwinfo_call_hwmodes("hwmodes");
  274. if (hwmodes > 0)
  275. rpc_iwinfo_call_hw_ht_mode(hwmodes);
  276. c = blobmsg_open_table(&buf, "hardware");
  277. rpc_iwinfo_call_hardware_id("id");
  278. rpc_iwinfo_call_str("name", iw->hardware_name);
  279. blobmsg_close_table(&buf, c);
  280. ubus_send_reply(ctx, req, buf.head);
  281. rpc_iwinfo_close();
  282. return UBUS_STATUS_OK;
  283. }
  284. static int
  285. rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj,
  286. struct ubus_request_data *req, const char *method,
  287. struct blob_attr *msg)
  288. {
  289. int i, rv, len, band;
  290. void *c, *d, *t;
  291. char mac[18];
  292. char res[IWINFO_BUFSIZE];
  293. struct iwinfo_scanlist_entry *e;
  294. rv = rpc_iwinfo_open(msg);
  295. if (rv)
  296. return rv;
  297. blob_buf_init(&buf, 0);
  298. c = blobmsg_open_array(&buf, "results");
  299. if (!iw->scanlist(ifname, res, &len) && (len > 0))
  300. {
  301. for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry))
  302. {
  303. e = (struct iwinfo_scanlist_entry *)&res[i];
  304. d = blobmsg_open_table(&buf, NULL);
  305. if (e->ssid[0])
  306. blobmsg_add_string(&buf, "ssid", (const char *)e->ssid);
  307. snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
  308. e->mac[0], e->mac[1], e->mac[2],
  309. e->mac[3], e->mac[4], e->mac[5]);
  310. blobmsg_add_string(&buf, "bssid", mac);
  311. blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]);
  312. band = iwinfo_band2ghz(e->band);
  313. if (band > 0)
  314. blobmsg_add_u32(&buf, "band", band);
  315. blobmsg_add_u32(&buf, "channel", e->channel);
  316. blobmsg_add_u32(&buf, "mhz", e->mhz);
  317. blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100));
  318. blobmsg_add_u32(&buf, "quality", e->quality);
  319. blobmsg_add_u32(&buf, "quality_max", e->quality_max);
  320. if (e->ht_chan_info.primary_chan) {
  321. t = blobmsg_open_table(&buf, "ht_operation");
  322. blobmsg_add_u32(&buf, "primary_channel", e->ht_chan_info.primary_chan);
  323. blobmsg_add_string(&buf, "secondary_channel_offset", ht_secondary_offset[e->ht_chan_info.secondary_chan_off]);
  324. blobmsg_add_u32(&buf, "channel_width", ht_chan_width[e->ht_chan_info.chan_width]);
  325. blobmsg_close_table(&buf, t);
  326. }
  327. if (e->vht_chan_info.center_chan_1) {
  328. t = blobmsg_open_table(&buf, "vht_operation");
  329. blobmsg_add_u32(&buf, "channel_width", vht_chan_width[e->vht_chan_info.chan_width]);
  330. blobmsg_add_u32(&buf, "center_freq_1", e->vht_chan_info.center_chan_1);
  331. blobmsg_add_u32(&buf, "center_freq_2", e->vht_chan_info.center_chan_2);
  332. blobmsg_close_table(&buf, t);
  333. }
  334. rpc_iwinfo_add_encryption("encryption", &e->crypto);
  335. blobmsg_close_table(&buf, d);
  336. }
  337. }
  338. blobmsg_close_array(&buf, c);
  339. ubus_send_reply(ctx, req, buf.head);
  340. rpc_iwinfo_close();
  341. return UBUS_STATUS_OK;
  342. }
  343. static void
  344. rpc_iwinfo_add_rateinfo(struct iwinfo_rate_entry *r)
  345. {
  346. blobmsg_add_u8(&buf, "ht", r->is_ht);
  347. blobmsg_add_u8(&buf, "vht", r->is_vht);
  348. blobmsg_add_u8(&buf, "he", r->is_he);
  349. blobmsg_add_u32(&buf, "mhz", r->mhz);
  350. blobmsg_add_u32(&buf, "rate", r->rate);
  351. if (r->is_ht) {
  352. blobmsg_add_u32(&buf, "mcs", r->mcs);
  353. blobmsg_add_u8(&buf, "40mhz", r->is_40mhz);
  354. blobmsg_add_u8(&buf, "short_gi", r->is_short_gi);
  355. }
  356. else if (r->is_vht) {
  357. blobmsg_add_u32(&buf, "mcs", r->mcs);
  358. blobmsg_add_u32(&buf, "nss", r->nss);
  359. blobmsg_add_u8(&buf, "short_gi", r->is_short_gi);
  360. }
  361. else if (r->is_he) {
  362. blobmsg_add_u32(&buf, "mcs", r->mcs);
  363. blobmsg_add_u32(&buf, "nss", r->nss);
  364. blobmsg_add_u32(&buf, "he_gi", r->he_gi);
  365. blobmsg_add_u32(&buf, "he_dcm", r->he_dcm);
  366. }
  367. }
  368. static int
  369. rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj,
  370. struct ubus_request_data *req, const char *method,
  371. struct blob_attr *msg)
  372. {
  373. int i, rv, len;
  374. char mac[18];
  375. char res[IWINFO_BUFSIZE];
  376. struct iwinfo_assoclist_entry *a;
  377. struct ether_addr *macaddr = NULL;
  378. void *c = NULL, *d, *e;
  379. struct blob_attr *tb[__RPC_A_MAX];
  380. bool found = false;
  381. blobmsg_parse(rpc_assoclist_policy, __RPC_A_MAX, tb,
  382. blob_data(msg), blob_len(msg));
  383. rv = __rpc_iwinfo_open(tb[RPC_A_DEVICE]);
  384. if (rv)
  385. return rv;
  386. if (tb[RPC_A_MACADDR])
  387. macaddr = ether_aton(blobmsg_data(tb[RPC_A_MACADDR]));
  388. blob_buf_init(&buf, 0);
  389. if (!macaddr)
  390. c = blobmsg_open_array(&buf, "results");
  391. if (!iw->assoclist(ifname, res, &len) && (len > 0))
  392. {
  393. for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
  394. {
  395. a = (struct iwinfo_assoclist_entry *)&res[i];
  396. if (!macaddr)
  397. d = blobmsg_open_table(&buf, NULL);
  398. else if (memcmp(macaddr, a->mac, ETH_ALEN) != 0)
  399. continue;
  400. snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
  401. a->mac[0], a->mac[1], a->mac[2],
  402. a->mac[3], a->mac[4], a->mac[5]);
  403. blobmsg_add_string(&buf, "mac", mac);
  404. blobmsg_add_u32(&buf, "signal", a->signal);
  405. blobmsg_add_u32(&buf, "signal_avg", a->signal_avg);
  406. blobmsg_add_u32(&buf, "noise", a->noise);
  407. blobmsg_add_u32(&buf, "inactive", a->inactive);
  408. blobmsg_add_u32(&buf, "connected_time", a->connected_time);
  409. blobmsg_add_u32(&buf, "thr", a->thr);
  410. blobmsg_add_u8(&buf, "authorized", a->is_authorized);
  411. blobmsg_add_u8(&buf, "authenticated", a->is_authenticated);
  412. blobmsg_add_string(&buf, "preamble", a->is_preamble_short ? "short" : "long");
  413. blobmsg_add_u8(&buf, "wme", a->is_wme);
  414. blobmsg_add_u8(&buf, "mfp", a->is_mfp);
  415. blobmsg_add_u8(&buf, "tdls", a->is_tdls);
  416. blobmsg_add_u16(&buf, "mesh llid", a->llid);
  417. blobmsg_add_u16(&buf, "mesh plid", a->plid);
  418. blobmsg_add_string(&buf, "mesh plink", a->plink_state);
  419. blobmsg_add_string(&buf, "mesh local PS", a->local_ps);
  420. blobmsg_add_string(&buf, "mesh peer PS", a->peer_ps);
  421. blobmsg_add_string(&buf, "mesh non-peer PS", a->nonpeer_ps);
  422. e = blobmsg_open_table(&buf, "rx");
  423. blobmsg_add_u64(&buf, "drop_misc", a->rx_drop_misc);
  424. blobmsg_add_u32(&buf, "packets", a->rx_packets);
  425. blobmsg_add_u64(&buf, "bytes", a->rx_bytes);
  426. rpc_iwinfo_add_rateinfo(&a->rx_rate);
  427. blobmsg_close_table(&buf, e);
  428. e = blobmsg_open_table(&buf, "tx");
  429. blobmsg_add_u32(&buf, "failed", a->tx_failed);
  430. blobmsg_add_u32(&buf, "retries", a->tx_retries);
  431. blobmsg_add_u32(&buf, "packets", a->tx_packets);
  432. blobmsg_add_u64(&buf, "bytes", a->tx_bytes);
  433. rpc_iwinfo_add_rateinfo(&a->tx_rate);
  434. blobmsg_close_table(&buf, e);
  435. found = true;
  436. if (!macaddr)
  437. blobmsg_close_table(&buf, d);
  438. else
  439. break;
  440. }
  441. }
  442. if (!macaddr)
  443. blobmsg_close_array(&buf, c);
  444. else if (!found)
  445. return UBUS_STATUS_NOT_FOUND;
  446. ubus_send_reply(ctx, req, buf.head);
  447. rpc_iwinfo_close();
  448. return UBUS_STATUS_OK;
  449. }
  450. static int
  451. rpc_iwinfo_survey(struct ubus_context *ctx, struct ubus_object *obj,
  452. struct ubus_request_data *req, const char *method,
  453. struct blob_attr *msg)
  454. {
  455. char res[IWINFO_BUFSIZE];
  456. struct iwinfo_survey_entry *e;
  457. void *c, *d;
  458. int i, rv, len;
  459. blob_buf_init(&buf, 0);
  460. rv = rpc_iwinfo_open(msg);
  461. c = blobmsg_open_array(&buf, "results");
  462. if (rv || iw->survey(ifname, res, &len) || len < 0)
  463. return UBUS_STATUS_OK;
  464. for (i = 0; i < len; i += sizeof(struct iwinfo_survey_entry)) {
  465. e = (struct iwinfo_survey_entry *)&res[i];
  466. d = blobmsg_open_table(&buf, NULL);
  467. blobmsg_add_u32(&buf, "mhz", e->mhz);
  468. blobmsg_add_u32(&buf, "noise", e->noise);
  469. blobmsg_add_u64(&buf, "active_time", e->active_time);
  470. blobmsg_add_u64(&buf, "busy_time", e->busy_time);
  471. blobmsg_add_u64(&buf, "busy_time_ext", e->busy_time_ext);
  472. blobmsg_add_u64(&buf, "rx_time", e->rxtime);
  473. blobmsg_add_u64(&buf, "tx_time", e->txtime);
  474. blobmsg_close_table(&buf, d);
  475. }
  476. blobmsg_close_array(&buf, c);
  477. ubus_send_reply(ctx, req, buf.head);
  478. rpc_iwinfo_close();
  479. return UBUS_STATUS_OK;
  480. }
  481. static int
  482. rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj,
  483. struct ubus_request_data *req, const char *method,
  484. struct blob_attr *msg)
  485. {
  486. int i, rv, len, ch, band;
  487. char res[IWINFO_BUFSIZE];
  488. struct iwinfo_freqlist_entry *f;
  489. void *c, *d;
  490. rv = rpc_iwinfo_open(msg);
  491. if (rv)
  492. return rv;
  493. blob_buf_init(&buf, 0);
  494. c = blobmsg_open_array(&buf, "results");
  495. if (!iw->freqlist(ifname, res, &len) && (len > 0))
  496. {
  497. if (iw->channel(ifname, &ch))
  498. ch = -1;
  499. for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
  500. {
  501. f = (struct iwinfo_freqlist_entry *)&res[i];
  502. d = blobmsg_open_table(&buf, NULL);
  503. band = iwinfo_band2ghz(f->band);
  504. if (band > 0)
  505. blobmsg_add_u32(&buf, "band", band);
  506. blobmsg_add_u32(&buf, "channel", f->channel);
  507. blobmsg_add_u32(&buf, "mhz", f->mhz);
  508. blobmsg_add_u8(&buf, "restricted", f->restricted);
  509. rpc_iwinfo_add_bit_array("flags", f->flags,
  510. IWINFO_FREQ_FLAG_NAMES,
  511. IWINFO_FREQ_FLAG_COUNT,
  512. true, 0);
  513. if (ch > -1)
  514. blobmsg_add_u8(&buf, "active", f->channel == ch);
  515. blobmsg_close_table(&buf, d);
  516. }
  517. }
  518. blobmsg_close_array(&buf, c);
  519. ubus_send_reply(ctx, req, buf.head);
  520. rpc_iwinfo_close();
  521. return UBUS_STATUS_OK;
  522. }
  523. static int
  524. rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj,
  525. struct ubus_request_data *req, const char *method,
  526. struct blob_attr *msg)
  527. {
  528. int i, rv, len, pwr, off;
  529. char res[IWINFO_BUFSIZE];
  530. struct iwinfo_txpwrlist_entry *t;
  531. void *c, *d;
  532. rv = rpc_iwinfo_open(msg);
  533. if (rv)
  534. return rv;
  535. blob_buf_init(&buf, 0);
  536. c = blobmsg_open_array(&buf, "results");
  537. if (!iw->txpwrlist(ifname, res, &len) && (len > 0))
  538. {
  539. if (iw->txpower(ifname, &pwr))
  540. pwr = -1;
  541. if (iw->txpower_offset(ifname, &off))
  542. off = 0;
  543. for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
  544. {
  545. t = (struct iwinfo_txpwrlist_entry *)&res[i];
  546. d = blobmsg_open_table(&buf, NULL);
  547. blobmsg_add_u32(&buf, "dbm", t->dbm + off);
  548. blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off));
  549. if (pwr > -1)
  550. blobmsg_add_u8(&buf, "active", t->dbm == pwr);
  551. blobmsg_close_table(&buf, d);
  552. }
  553. }
  554. blobmsg_close_array(&buf, c);
  555. ubus_send_reply(ctx, req, buf.head);
  556. rpc_iwinfo_close();
  557. return UBUS_STATUS_OK;
  558. }
  559. static const char *
  560. rpc_iwinfo_lookup_country(char *buf, int len, int iso3166)
  561. {
  562. int i;
  563. static char ccode[5];
  564. struct iwinfo_country_entry *c;
  565. for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
  566. {
  567. c = (struct iwinfo_country_entry *)&buf[i];
  568. if (c->iso3166 == iso3166)
  569. {
  570. snprintf(ccode, sizeof(ccode), "%s", c->ccode);
  571. return ccode;
  572. }
  573. }
  574. return NULL;
  575. }
  576. static int
  577. rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj,
  578. struct ubus_request_data *req, const char *method,
  579. struct blob_attr *msg)
  580. {
  581. int rv, len;
  582. char cur[3];
  583. char iso3166[3];
  584. char res[IWINFO_BUFSIZE] = {0};
  585. const char *ccode;
  586. const struct iwinfo_iso3166_label *l;
  587. void *c, *d;
  588. rv = rpc_iwinfo_open(msg);
  589. if (rv)
  590. return rv;
  591. blob_buf_init(&buf, 0);
  592. c = blobmsg_open_array(&buf, "results");
  593. if (!iw->countrylist(ifname, res, &len) && (len > 0))
  594. {
  595. if (iw->country(ifname, cur))
  596. memset(cur, 0, sizeof(cur));
  597. for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
  598. {
  599. ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166);
  600. if (!ccode)
  601. continue;
  602. d = blobmsg_open_table(&buf, NULL);
  603. blobmsg_add_string(&buf, "code", ccode);
  604. blobmsg_add_string(&buf, "country", (const char *)l->name);
  605. snprintf(iso3166, sizeof(iso3166), "%c%c",
  606. (l->iso3166 / 256), (l->iso3166 % 256));
  607. blobmsg_add_string(&buf, "iso3166", iso3166);
  608. if (cur[0])
  609. blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2));
  610. blobmsg_close_table(&buf, d);
  611. }
  612. }
  613. blobmsg_close_array(&buf, c);
  614. ubus_send_reply(ctx, req, buf.head);
  615. rpc_iwinfo_close();
  616. return UBUS_STATUS_OK;
  617. }
  618. static int
  619. rpc_iwinfo_phyname(struct ubus_context *ctx, struct ubus_object *obj,
  620. struct ubus_request_data *req, const char *method,
  621. struct blob_attr *msg)
  622. {
  623. int i;
  624. bool found = false;
  625. char res[IWINFO_BUFSIZE];
  626. const struct iwinfo_ops *ops;
  627. struct blob_attr *tb[__RPC_U_MAX];
  628. const char *backends[] = {
  629. "nl80211",
  630. "madwifi",
  631. "wl"
  632. };
  633. blobmsg_parse(rpc_uci_policy, __RPC_U_MAX, tb,
  634. blob_data(msg), blob_len(msg));
  635. if (!tb[RPC_U_SECTION])
  636. return UBUS_STATUS_INVALID_ARGUMENT;
  637. for (i = 0; i < ARRAY_SIZE(backends); i++)
  638. {
  639. ops = iwinfo_backend_by_name(backends[i]);
  640. if (!ops || !ops->lookup_phy)
  641. continue;
  642. if (!ops->lookup_phy(blobmsg_get_string(tb[RPC_U_SECTION]), res))
  643. {
  644. found = true;
  645. break;
  646. }
  647. }
  648. if (found)
  649. {
  650. blob_buf_init(&buf, 0);
  651. blobmsg_add_string(&buf, "phyname", res);
  652. ubus_send_reply(ctx, req, buf.head);
  653. }
  654. rpc_iwinfo_close();
  655. return found ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND;
  656. }
  657. static int
  658. rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj,
  659. struct ubus_request_data *req, const char *method,
  660. struct blob_attr *msg)
  661. {
  662. void *c;
  663. struct dirent *e;
  664. DIR *d;
  665. d = opendir("/sys/class/net");
  666. if (!d)
  667. return UBUS_STATUS_UNKNOWN_ERROR;
  668. blob_buf_init(&buf, 0);
  669. c = blobmsg_open_array(&buf, "devices");
  670. while ((e = readdir(d)) != NULL)
  671. {
  672. if (e->d_type != DT_LNK)
  673. continue;
  674. if (iwinfo_type(e->d_name))
  675. blobmsg_add_string(&buf, NULL, e->d_name);
  676. }
  677. blobmsg_close_array(&buf, c);
  678. closedir(d);
  679. ubus_send_reply(ctx, req, buf.head);
  680. rpc_iwinfo_close();
  681. return UBUS_STATUS_OK;
  682. }
  683. static int
  684. rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
  685. {
  686. static const struct ubus_method iwinfo_methods[] = {
  687. UBUS_METHOD_NOARG("devices", rpc_iwinfo_devices),
  688. UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy),
  689. UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy),
  690. UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_assoclist_policy),
  691. UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy),
  692. UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy),
  693. UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy),
  694. UBUS_METHOD("survey", rpc_iwinfo_survey, rpc_device_policy),
  695. UBUS_METHOD("phyname", rpc_iwinfo_phyname, rpc_uci_policy),
  696. };
  697. static struct ubus_object_type iwinfo_type =
  698. UBUS_OBJECT_TYPE("rpcd-plugin-iwinfo", iwinfo_methods);
  699. static struct ubus_object obj = {
  700. .name = "iwinfo",
  701. .type = &iwinfo_type,
  702. .methods = iwinfo_methods,
  703. .n_methods = ARRAY_SIZE(iwinfo_methods),
  704. };
  705. return ubus_add_object(ctx, &obj);
  706. }
  707. struct rpc_plugin rpc_plugin = {
  708. .init = rpc_iwinfo_api_init
  709. };