iwinfo.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  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 if (iwinfo_htmode_is_eht(htmode))
  230. hwmode_str = "be";
  231. else {
  232. if (hwmodelist & IWINFO_80211_N)
  233. hwmode_str = "n";
  234. else if (hwmodelist & IWINFO_80211_G)
  235. hwmode_str = "g";
  236. else if (hwmodelist & IWINFO_80211_B)
  237. hwmode_str = "b";
  238. else if (hwmodelist & IWINFO_80211_A)
  239. hwmode_str = "a";
  240. else
  241. hwmode_str = "unknown";
  242. }
  243. } else
  244. htmode_str = hwmode_str = "unknown";
  245. blobmsg_add_string(&buf, "hwmode", hwmode_str);
  246. blobmsg_add_string(&buf, "htmode", htmode_str);
  247. }
  248. static void
  249. rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *))
  250. {
  251. char rv[IWINFO_BUFSIZE] = { 0 };
  252. if (!func(ifname, rv))
  253. blobmsg_add_string(&buf, name, rv);
  254. }
  255. static int
  256. rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj,
  257. struct ubus_request_data *req, const char *method,
  258. struct blob_attr *msg)
  259. {
  260. int rv, hwmodes;
  261. void *c;
  262. rv = rpc_iwinfo_open(msg);
  263. if (rv)
  264. return rv;
  265. blob_buf_init(&buf, 0);
  266. rpc_iwinfo_call_str("phy", iw->phyname);
  267. rpc_iwinfo_call_str("ssid", iw->ssid);
  268. rpc_iwinfo_call_str("bssid", iw->bssid);
  269. rpc_iwinfo_call_str("country", iw->country);
  270. rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES);
  271. rpc_iwinfo_call_int("channel", iw->channel, NULL);
  272. rpc_iwinfo_call_int("center_chan1", iw->center_chan1, NULL);
  273. rpc_iwinfo_call_int("center_chan2", iw->center_chan2, NULL);
  274. rpc_iwinfo_call_int("frequency", iw->frequency, NULL);
  275. rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL);
  276. rpc_iwinfo_call_int("txpower", iw->txpower, NULL);
  277. rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL);
  278. rpc_iwinfo_call_int("quality", iw->quality, NULL);
  279. rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL);
  280. rpc_iwinfo_call_int("signal", iw->signal, NULL);
  281. rpc_iwinfo_call_int("noise", iw->noise, NULL);
  282. rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL);
  283. rpc_iwinfo_call_encryption("encryption");
  284. rpc_iwinfo_call_htmodes("htmodes");
  285. hwmodes = rpc_iwinfo_call_hwmodes("hwmodes");
  286. if (hwmodes > 0)
  287. rpc_iwinfo_call_hw_ht_mode(hwmodes);
  288. c = blobmsg_open_table(&buf, "hardware");
  289. rpc_iwinfo_call_hardware_id("id");
  290. rpc_iwinfo_call_str("name", iw->hardware_name);
  291. blobmsg_close_table(&buf, c);
  292. ubus_send_reply(ctx, req, buf.head);
  293. rpc_iwinfo_close();
  294. return UBUS_STATUS_OK;
  295. }
  296. static int
  297. rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj,
  298. struct ubus_request_data *req, const char *method,
  299. struct blob_attr *msg)
  300. {
  301. int i, rv, len, band;
  302. void *c, *d, *t;
  303. char mac[18];
  304. char res[IWINFO_BUFSIZE];
  305. struct iwinfo_scanlist_entry *e;
  306. rv = rpc_iwinfo_open(msg);
  307. if (rv)
  308. return rv;
  309. blob_buf_init(&buf, 0);
  310. c = blobmsg_open_array(&buf, "results");
  311. if (!iw->scanlist(ifname, res, &len) && (len > 0))
  312. {
  313. for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry))
  314. {
  315. e = (struct iwinfo_scanlist_entry *)&res[i];
  316. d = blobmsg_open_table(&buf, NULL);
  317. if (e->ssid[0])
  318. blobmsg_add_string(&buf, "ssid", (const char *)e->ssid);
  319. snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
  320. e->mac[0], e->mac[1], e->mac[2],
  321. e->mac[3], e->mac[4], e->mac[5]);
  322. blobmsg_add_string(&buf, "bssid", mac);
  323. blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]);
  324. band = iwinfo_band2ghz(e->band);
  325. if (band > 0)
  326. blobmsg_add_u32(&buf, "band", band);
  327. blobmsg_add_u32(&buf, "channel", e->channel);
  328. blobmsg_add_u32(&buf, "mhz", e->mhz);
  329. blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100));
  330. blobmsg_add_u32(&buf, "quality", e->quality);
  331. blobmsg_add_u32(&buf, "quality_max", e->quality_max);
  332. if (e->ht_chan_info.primary_chan) {
  333. t = blobmsg_open_table(&buf, "ht_operation");
  334. blobmsg_add_u32(&buf, "primary_channel", e->ht_chan_info.primary_chan);
  335. blobmsg_add_string(&buf, "secondary_channel_offset", ht_secondary_offset[e->ht_chan_info.secondary_chan_off]);
  336. blobmsg_add_u32(&buf, "channel_width", ht_chan_width[e->ht_chan_info.chan_width]);
  337. blobmsg_close_table(&buf, t);
  338. }
  339. if (e->vht_chan_info.center_chan_1) {
  340. t = blobmsg_open_table(&buf, "vht_operation");
  341. blobmsg_add_u32(&buf, "channel_width", vht_chan_width[e->vht_chan_info.chan_width]);
  342. blobmsg_add_u32(&buf, "center_freq_1", e->vht_chan_info.center_chan_1);
  343. blobmsg_add_u32(&buf, "center_freq_2", e->vht_chan_info.center_chan_2);
  344. blobmsg_close_table(&buf, t);
  345. }
  346. rpc_iwinfo_add_encryption("encryption", &e->crypto);
  347. blobmsg_close_table(&buf, d);
  348. }
  349. }
  350. blobmsg_close_array(&buf, c);
  351. ubus_send_reply(ctx, req, buf.head);
  352. rpc_iwinfo_close();
  353. return UBUS_STATUS_OK;
  354. }
  355. static void
  356. rpc_iwinfo_add_rateinfo(struct iwinfo_rate_entry *r)
  357. {
  358. blobmsg_add_u8(&buf, "ht", r->is_ht);
  359. blobmsg_add_u8(&buf, "vht", r->is_vht);
  360. blobmsg_add_u8(&buf, "he", r->is_he);
  361. blobmsg_add_u8(&buf, "eht", r->is_eht);
  362. blobmsg_add_u32(&buf, "mhz", r->mhz_hi * 256 + r->mhz);
  363. blobmsg_add_u32(&buf, "rate", r->rate);
  364. if (r->is_ht) {
  365. blobmsg_add_u32(&buf, "mcs", r->mcs);
  366. blobmsg_add_u8(&buf, "40mhz", r->is_40mhz);
  367. blobmsg_add_u8(&buf, "short_gi", r->is_short_gi);
  368. }
  369. else if (r->is_vht) {
  370. blobmsg_add_u32(&buf, "mcs", r->mcs);
  371. blobmsg_add_u32(&buf, "nss", r->nss);
  372. blobmsg_add_u8(&buf, "short_gi", r->is_short_gi);
  373. }
  374. else if (r->is_he) {
  375. blobmsg_add_u32(&buf, "mcs", r->mcs);
  376. blobmsg_add_u32(&buf, "nss", r->nss);
  377. blobmsg_add_u32(&buf, "he_gi", r->he_gi);
  378. blobmsg_add_u32(&buf, "he_dcm", r->he_dcm);
  379. }
  380. else if (r->is_eht) {
  381. blobmsg_add_u32(&buf, "mcs", r->mcs);
  382. blobmsg_add_u32(&buf, "nss", r->nss);
  383. blobmsg_add_u32(&buf, "eht_gi", r->eht_gi);
  384. }
  385. }
  386. static int
  387. rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj,
  388. struct ubus_request_data *req, const char *method,
  389. struct blob_attr *msg)
  390. {
  391. int i, rv, len;
  392. char mac[18];
  393. char res[IWINFO_BUFSIZE];
  394. struct iwinfo_assoclist_entry *a;
  395. struct ether_addr *macaddr = NULL;
  396. void *c = NULL, *d, *e;
  397. struct blob_attr *tb[__RPC_A_MAX];
  398. bool found = false;
  399. blobmsg_parse(rpc_assoclist_policy, __RPC_A_MAX, tb,
  400. blob_data(msg), blob_len(msg));
  401. rv = __rpc_iwinfo_open(tb[RPC_A_DEVICE]);
  402. if (rv)
  403. return rv;
  404. if (tb[RPC_A_MACADDR])
  405. macaddr = ether_aton(blobmsg_data(tb[RPC_A_MACADDR]));
  406. blob_buf_init(&buf, 0);
  407. if (!macaddr)
  408. c = blobmsg_open_array(&buf, "results");
  409. if (!iw->assoclist(ifname, res, &len) && (len > 0))
  410. {
  411. for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
  412. {
  413. a = (struct iwinfo_assoclist_entry *)&res[i];
  414. if (!macaddr)
  415. d = blobmsg_open_table(&buf, NULL);
  416. else if (memcmp(macaddr, a->mac, ETH_ALEN) != 0)
  417. continue;
  418. snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
  419. a->mac[0], a->mac[1], a->mac[2],
  420. a->mac[3], a->mac[4], a->mac[5]);
  421. blobmsg_add_string(&buf, "mac", mac);
  422. blobmsg_add_u32(&buf, "signal", a->signal);
  423. blobmsg_add_u32(&buf, "signal_avg", a->signal_avg);
  424. blobmsg_add_u32(&buf, "noise", a->noise);
  425. blobmsg_add_u32(&buf, "inactive", a->inactive);
  426. blobmsg_add_u32(&buf, "connected_time", a->connected_time);
  427. blobmsg_add_u32(&buf, "thr", a->thr);
  428. blobmsg_add_u8(&buf, "authorized", a->is_authorized);
  429. blobmsg_add_u8(&buf, "authenticated", a->is_authenticated);
  430. blobmsg_add_string(&buf, "preamble", a->is_preamble_short ? "short" : "long");
  431. blobmsg_add_u8(&buf, "wme", a->is_wme);
  432. blobmsg_add_u8(&buf, "mfp", a->is_mfp);
  433. blobmsg_add_u8(&buf, "tdls", a->is_tdls);
  434. blobmsg_add_u16(&buf, "mesh llid", a->llid);
  435. blobmsg_add_u16(&buf, "mesh plid", a->plid);
  436. blobmsg_add_string(&buf, "mesh plink", a->plink_state);
  437. blobmsg_add_string(&buf, "mesh local PS", a->local_ps);
  438. blobmsg_add_string(&buf, "mesh peer PS", a->peer_ps);
  439. blobmsg_add_string(&buf, "mesh non-peer PS", a->nonpeer_ps);
  440. e = blobmsg_open_table(&buf, "rx");
  441. blobmsg_add_u64(&buf, "drop_misc", a->rx_drop_misc);
  442. blobmsg_add_u32(&buf, "packets", a->rx_packets);
  443. blobmsg_add_u64(&buf, "bytes", a->rx_bytes);
  444. rpc_iwinfo_add_rateinfo(&a->rx_rate);
  445. blobmsg_close_table(&buf, e);
  446. e = blobmsg_open_table(&buf, "tx");
  447. blobmsg_add_u32(&buf, "failed", a->tx_failed);
  448. blobmsg_add_u32(&buf, "retries", a->tx_retries);
  449. blobmsg_add_u32(&buf, "packets", a->tx_packets);
  450. blobmsg_add_u64(&buf, "bytes", a->tx_bytes);
  451. rpc_iwinfo_add_rateinfo(&a->tx_rate);
  452. blobmsg_close_table(&buf, e);
  453. found = true;
  454. if (!macaddr)
  455. blobmsg_close_table(&buf, d);
  456. else
  457. break;
  458. }
  459. }
  460. if (!macaddr)
  461. blobmsg_close_array(&buf, c);
  462. else if (!found)
  463. return UBUS_STATUS_NOT_FOUND;
  464. ubus_send_reply(ctx, req, buf.head);
  465. rpc_iwinfo_close();
  466. return UBUS_STATUS_OK;
  467. }
  468. static int
  469. rpc_iwinfo_survey(struct ubus_context *ctx, struct ubus_object *obj,
  470. struct ubus_request_data *req, const char *method,
  471. struct blob_attr *msg)
  472. {
  473. char res[IWINFO_BUFSIZE];
  474. struct iwinfo_survey_entry *e;
  475. void *c, *d;
  476. int i, rv, len;
  477. blob_buf_init(&buf, 0);
  478. rv = rpc_iwinfo_open(msg);
  479. c = blobmsg_open_array(&buf, "results");
  480. if (rv || iw->survey(ifname, res, &len) || len < 0)
  481. return UBUS_STATUS_OK;
  482. for (i = 0; i < len; i += sizeof(struct iwinfo_survey_entry)) {
  483. e = (struct iwinfo_survey_entry *)&res[i];
  484. d = blobmsg_open_table(&buf, NULL);
  485. blobmsg_add_u32(&buf, "mhz", e->mhz);
  486. blobmsg_add_u32(&buf, "noise", e->noise);
  487. blobmsg_add_u64(&buf, "active_time", e->active_time);
  488. blobmsg_add_u64(&buf, "busy_time", e->busy_time);
  489. blobmsg_add_u64(&buf, "busy_time_ext", e->busy_time_ext);
  490. blobmsg_add_u64(&buf, "rx_time", e->rxtime);
  491. blobmsg_add_u64(&buf, "tx_time", e->txtime);
  492. blobmsg_close_table(&buf, d);
  493. }
  494. blobmsg_close_array(&buf, c);
  495. ubus_send_reply(ctx, req, buf.head);
  496. rpc_iwinfo_close();
  497. return UBUS_STATUS_OK;
  498. }
  499. static int
  500. rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj,
  501. struct ubus_request_data *req, const char *method,
  502. struct blob_attr *msg)
  503. {
  504. int i, rv, len, ch, band;
  505. char res[IWINFO_BUFSIZE];
  506. struct iwinfo_freqlist_entry *f;
  507. void *c, *d;
  508. rv = rpc_iwinfo_open(msg);
  509. if (rv)
  510. return rv;
  511. blob_buf_init(&buf, 0);
  512. c = blobmsg_open_array(&buf, "results");
  513. if (!iw->freqlist(ifname, res, &len) && (len > 0))
  514. {
  515. if (iw->channel(ifname, &ch))
  516. ch = -1;
  517. for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
  518. {
  519. f = (struct iwinfo_freqlist_entry *)&res[i];
  520. d = blobmsg_open_table(&buf, NULL);
  521. band = iwinfo_band2ghz(f->band);
  522. if (band > 0)
  523. blobmsg_add_u32(&buf, "band", band);
  524. blobmsg_add_u32(&buf, "channel", f->channel);
  525. blobmsg_add_u32(&buf, "mhz", f->mhz);
  526. blobmsg_add_u8(&buf, "restricted", f->restricted);
  527. rpc_iwinfo_add_bit_array("flags", f->flags,
  528. IWINFO_FREQ_FLAG_NAMES,
  529. IWINFO_FREQ_FLAG_COUNT,
  530. true, 0);
  531. if (ch > -1)
  532. blobmsg_add_u8(&buf, "active", f->channel == ch);
  533. blobmsg_close_table(&buf, d);
  534. }
  535. }
  536. blobmsg_close_array(&buf, c);
  537. ubus_send_reply(ctx, req, buf.head);
  538. rpc_iwinfo_close();
  539. return UBUS_STATUS_OK;
  540. }
  541. static int
  542. rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj,
  543. struct ubus_request_data *req, const char *method,
  544. struct blob_attr *msg)
  545. {
  546. int i, rv, len, pwr, off;
  547. char res[IWINFO_BUFSIZE];
  548. struct iwinfo_txpwrlist_entry *t;
  549. void *c, *d;
  550. rv = rpc_iwinfo_open(msg);
  551. if (rv)
  552. return rv;
  553. blob_buf_init(&buf, 0);
  554. c = blobmsg_open_array(&buf, "results");
  555. if (!iw->txpwrlist(ifname, res, &len) && (len > 0))
  556. {
  557. if (iw->txpower(ifname, &pwr))
  558. pwr = -1;
  559. if (iw->txpower_offset(ifname, &off))
  560. off = 0;
  561. for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
  562. {
  563. t = (struct iwinfo_txpwrlist_entry *)&res[i];
  564. d = blobmsg_open_table(&buf, NULL);
  565. blobmsg_add_u32(&buf, "dbm", t->dbm + off);
  566. blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off));
  567. if (pwr > -1)
  568. blobmsg_add_u8(&buf, "active", t->dbm == pwr);
  569. blobmsg_close_table(&buf, d);
  570. }
  571. }
  572. blobmsg_close_array(&buf, c);
  573. ubus_send_reply(ctx, req, buf.head);
  574. rpc_iwinfo_close();
  575. return UBUS_STATUS_OK;
  576. }
  577. static const char *
  578. rpc_iwinfo_lookup_country(char *buf, int len, int iso3166)
  579. {
  580. int i;
  581. static char ccode[5];
  582. struct iwinfo_country_entry *c;
  583. for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
  584. {
  585. c = (struct iwinfo_country_entry *)&buf[i];
  586. if (c->iso3166 == iso3166)
  587. {
  588. snprintf(ccode, sizeof(ccode), "%s", c->ccode);
  589. return ccode;
  590. }
  591. }
  592. return NULL;
  593. }
  594. static int
  595. rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj,
  596. struct ubus_request_data *req, const char *method,
  597. struct blob_attr *msg)
  598. {
  599. int rv, len;
  600. char cur[3];
  601. char iso3166[3];
  602. char res[IWINFO_BUFSIZE] = {0};
  603. const char *ccode;
  604. const struct iwinfo_iso3166_label *l;
  605. void *c, *d;
  606. rv = rpc_iwinfo_open(msg);
  607. if (rv)
  608. return rv;
  609. blob_buf_init(&buf, 0);
  610. c = blobmsg_open_array(&buf, "results");
  611. if (!iw->countrylist(ifname, res, &len) && (len > 0))
  612. {
  613. if (iw->country(ifname, cur))
  614. memset(cur, 0, sizeof(cur));
  615. for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
  616. {
  617. ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166);
  618. if (!ccode)
  619. continue;
  620. d = blobmsg_open_table(&buf, NULL);
  621. blobmsg_add_string(&buf, "code", ccode);
  622. blobmsg_add_string(&buf, "country", (const char *)l->name);
  623. snprintf(iso3166, sizeof(iso3166), "%c%c",
  624. (l->iso3166 / 256), (l->iso3166 % 256));
  625. blobmsg_add_string(&buf, "iso3166", iso3166);
  626. if (cur[0])
  627. blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2));
  628. blobmsg_close_table(&buf, d);
  629. }
  630. }
  631. blobmsg_close_array(&buf, c);
  632. ubus_send_reply(ctx, req, buf.head);
  633. rpc_iwinfo_close();
  634. return UBUS_STATUS_OK;
  635. }
  636. static int
  637. rpc_iwinfo_phyname(struct ubus_context *ctx, struct ubus_object *obj,
  638. struct ubus_request_data *req, const char *method,
  639. struct blob_attr *msg)
  640. {
  641. int i;
  642. bool found = false;
  643. char res[IWINFO_BUFSIZE];
  644. const struct iwinfo_ops *ops;
  645. struct blob_attr *tb[__RPC_U_MAX];
  646. const char *backends[] = {
  647. "nl80211",
  648. "madwifi",
  649. "wl"
  650. };
  651. blobmsg_parse(rpc_uci_policy, __RPC_U_MAX, tb,
  652. blob_data(msg), blob_len(msg));
  653. if (!tb[RPC_U_SECTION])
  654. return UBUS_STATUS_INVALID_ARGUMENT;
  655. for (i = 0; i < ARRAY_SIZE(backends); i++)
  656. {
  657. ops = iwinfo_backend_by_name(backends[i]);
  658. if (!ops || !ops->lookup_phy)
  659. continue;
  660. if (!ops->lookup_phy(blobmsg_get_string(tb[RPC_U_SECTION]), res))
  661. {
  662. found = true;
  663. break;
  664. }
  665. }
  666. if (found)
  667. {
  668. blob_buf_init(&buf, 0);
  669. blobmsg_add_string(&buf, "phyname", res);
  670. ubus_send_reply(ctx, req, buf.head);
  671. }
  672. rpc_iwinfo_close();
  673. return found ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND;
  674. }
  675. static int
  676. rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj,
  677. struct ubus_request_data *req, const char *method,
  678. struct blob_attr *msg)
  679. {
  680. void *c;
  681. struct dirent *e;
  682. DIR *d;
  683. d = opendir("/sys/class/net");
  684. if (!d)
  685. return UBUS_STATUS_UNKNOWN_ERROR;
  686. blob_buf_init(&buf, 0);
  687. c = blobmsg_open_array(&buf, "devices");
  688. while ((e = readdir(d)) != NULL)
  689. {
  690. if (e->d_type != DT_LNK)
  691. continue;
  692. if (iwinfo_type(e->d_name))
  693. blobmsg_add_string(&buf, NULL, e->d_name);
  694. }
  695. blobmsg_close_array(&buf, c);
  696. closedir(d);
  697. ubus_send_reply(ctx, req, buf.head);
  698. rpc_iwinfo_close();
  699. return UBUS_STATUS_OK;
  700. }
  701. static int
  702. rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
  703. {
  704. static const struct ubus_method iwinfo_methods[] = {
  705. UBUS_METHOD_NOARG("devices", rpc_iwinfo_devices),
  706. UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy),
  707. UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy),
  708. UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_assoclist_policy),
  709. UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy),
  710. UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy),
  711. UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy),
  712. UBUS_METHOD("survey", rpc_iwinfo_survey, rpc_device_policy),
  713. UBUS_METHOD("phyname", rpc_iwinfo_phyname, rpc_uci_policy),
  714. };
  715. static struct ubus_object_type iwinfo_type =
  716. UBUS_OBJECT_TYPE("rpcd-plugin-iwinfo", iwinfo_methods);
  717. static struct ubus_object obj = {
  718. .name = "iwinfo",
  719. .type = &iwinfo_type,
  720. .methods = iwinfo_methods,
  721. .n_methods = ARRAY_SIZE(iwinfo_methods),
  722. };
  723. return ubus_add_object(ctx, &obj);
  724. }
  725. struct rpc_plugin rpc_plugin = {
  726. .init = rpc_iwinfo_api_init
  727. };