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 19 #include <sys/types.h> 20 #include <ctype.h> 21 #include <dirent.h> 22 #include <libubus.h> 23 #include <iwinfo.h> 24 #include <iwinfo/utils.h> 25 #include <net/ethernet.h> 26 27 #ifdef linux 28 #include <netinet/ether.h> 29 #endif 30 31 #include <rpcd/plugin.h> 32 33 34 static struct blob_buf buf; 35 static const struct iwinfo_ops *iw; 36 static const char *ifname; 37 38 enum { 39 RPC_D_DEVICE, 40 __RPC_D_MAX, 41 }; 42 43 static const struct blobmsg_policy rpc_device_policy[__RPC_D_MAX] = { 44 [RPC_D_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, 45 }; 46 47 enum { 48 RPC_A_DEVICE, 49 RPC_A_MACADDR, 50 __RPC_A_MAX, 51 }; 52 53 static const struct blobmsg_policy rpc_assoclist_policy[__RPC_A_MAX] = { 54 [RPC_A_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, 55 [RPC_A_MACADDR] = { .name = "mac", .type = BLOBMSG_TYPE_STRING }, 56 }; 57 58 enum { 59 RPC_U_SECTION, 60 __RPC_U_MAX 61 }; 62 63 static const struct blobmsg_policy rpc_uci_policy[__RPC_U_MAX] = { 64 [RPC_U_SECTION] = { .name = "section", .type = BLOBMSG_TYPE_STRING }, 65 }; 66 67 static int 68 __rpc_iwinfo_open(struct blob_attr *device) 69 { 70 if (!device) 71 return UBUS_STATUS_INVALID_ARGUMENT; 72 73 ifname = blobmsg_data(device); 74 iw = iwinfo_backend(ifname); 75 76 return iw ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND; 77 } 78 79 static int 80 rpc_iwinfo_open(struct blob_attr *msg) 81 { 82 static struct blob_attr *tb[__RPC_D_MAX]; 83 84 blobmsg_parse(rpc_device_policy, __RPC_D_MAX, tb, 85 blob_data(msg), blob_len(msg)); 86 87 return __rpc_iwinfo_open(tb[RPC_D_DEVICE]); 88 } 89 90 static void 91 rpc_iwinfo_close(void) 92 { 93 iw = NULL; 94 ifname = NULL; 95 iwinfo_finish(); 96 } 97 98 static void 99 rpc_iwinfo_call_int(const char *name, int (*func)(const char *, int *), 100 const char * const *map) 101 { 102 int rv; 103 104 if (!func(ifname, &rv)) 105 { 106 if (!map) 107 blobmsg_add_u32(&buf, name, rv); 108 else 109 blobmsg_add_string(&buf, name, map[rv]); 110 } 111 } 112 113 static void 114 rpc_iwinfo_call_hardware_id(const char *name) 115 { 116 struct iwinfo_hardware_id ids; 117 void *c; 118 119 if (!iw->hardware_id(ifname, (char *)&ids)) 120 { 121 c = blobmsg_open_array(&buf, name); 122 123 blobmsg_add_u32(&buf, NULL, ids.vendor_id); 124 blobmsg_add_u32(&buf, NULL, ids.device_id); 125 blobmsg_add_u32(&buf, NULL, ids.subsystem_vendor_id); 126 blobmsg_add_u32(&buf, NULL, ids.subsystem_device_id); 127 128 blobmsg_close_array(&buf, c); 129 } 130 } 131 132 static void 133 rpc_iwinfo_lower(const char *src, char *dst, size_t len) 134 { 135 size_t i; 136 137 for (i = 0; *src && i < len; i++) 138 *dst++ = tolower(*src++); 139 140 *dst = 0; 141 } 142 143 static void 144 rpc_iwinfo_add_bit_array(const char *name, uint32_t bits, 145 const char * const values[], size_t len, 146 bool lower, uint32_t zero) 147 { 148 void *c; 149 size_t i; 150 char l[128]; 151 const char *v; 152 153 if (!bits) 154 bits = zero; 155 156 c = blobmsg_open_array(&buf, name); 157 158 for (i = 0; i < len; i++) 159 if (bits & 1 << i) 160 { 161 v = values[i]; 162 163 if (lower) 164 { 165 rpc_iwinfo_lower(v, l, strlen(values[i])); 166 v = l; 167 } 168 169 blobmsg_add_string(&buf, NULL, v); 170 } 171 172 blobmsg_close_array(&buf, c); 173 } 174 175 static void 176 rpc_iwinfo_add_encryption(const char *name, struct iwinfo_crypto_entry *e) 177 { 178 int wpa_version; 179 void *c, *d; 180 181 c = blobmsg_open_table(&buf, name); 182 183 blobmsg_add_u8(&buf, "enabled", e->enabled); 184 185 if (e->enabled) 186 { 187 if (!e->wpa_version) 188 { 189 rpc_iwinfo_add_bit_array("wep", e->auth_algs, 190 IWINFO_AUTH_NAMES, 191 IWINFO_AUTH_COUNT, 192 true, 0); 193 } 194 else 195 { 196 d = blobmsg_open_array(&buf, "wpa"); 197 198 for (wpa_version = 1; wpa_version <= 3; wpa_version++) 199 if (e->wpa_version & (1 << (wpa_version - 1))) 200 blobmsg_add_u32(&buf, NULL, wpa_version); 201 202 blobmsg_close_array(&buf, d); 203 204 rpc_iwinfo_add_bit_array("authentication", 205 e->auth_suites, 206 IWINFO_KMGMT_NAMES, 207 IWINFO_KMGMT_COUNT, 208 true, IWINFO_KMGMT_NONE); 209 } 210 211 212 rpc_iwinfo_add_bit_array("ciphers", 213 e->pair_ciphers | e->group_ciphers, 214 IWINFO_CIPHER_NAMES, 215 IWINFO_CIPHER_COUNT, 216 true, IWINFO_CIPHER_NONE); 217 } 218 219 blobmsg_close_table(&buf, c); 220 } 221 222 static void 223 rpc_iwinfo_call_encryption(const char *name) 224 { 225 struct iwinfo_crypto_entry crypto = { 0 }; 226 227 if (!iw->encryption(ifname, (char *)&crypto)) 228 rpc_iwinfo_add_encryption(name, &crypto); 229 } 230 231 static void 232 rpc_iwinfo_call_htmodes(const char *name) 233 { 234 int modes; 235 236 if (iw->htmodelist(ifname, &modes)) 237 return; 238 239 rpc_iwinfo_add_bit_array(name, modes & ~IWINFO_HTMODE_NOHT, 240 IWINFO_HTMODE_NAMES, IWINFO_HTMODE_COUNT, 241 false, 0); 242 } 243 244 static int 245 rpc_iwinfo_call_hwmodes(const char *name) 246 { 247 int modes; 248 249 if (iw->hwmodelist(ifname, &modes)) 250 return -1; 251 252 rpc_iwinfo_add_bit_array(name, modes, 253 IWINFO_80211_NAMES, IWINFO_80211_COUNT, 254 false, 0); 255 256 return modes; 257 } 258 259 static void rpc_iwinfo_call_hw_ht_mode(int hwmodelist) 260 { 261 char text[32]; 262 const char *hwmode_str; 263 const char *htmode_str; 264 int htmode; 265 266 if (iwinfo_format_hwmodes(hwmodelist, text, sizeof(text)) > 0) 267 blobmsg_add_string(&buf, "hwmodes_text", text); 268 269 if (hwmodelist == IWINFO_80211_AD) 270 { 271 blobmsg_add_string(&buf, "hwmode", "ad"); 272 return; 273 } 274 275 if (iw->htmode(ifname, &htmode)) 276 return; 277 278 htmode_str = iwinfo_htmode_name(htmode); 279 if (htmode_str) 280 { 281 if (iwinfo_htmode_is_ht(htmode)) 282 hwmode_str = "n"; 283 else if (iwinfo_htmode_is_vht(htmode)) 284 hwmode_str = "ac"; 285 else if (iwinfo_htmode_is_he(htmode)) 286 hwmode_str = "ax"; 287 else if (iwinfo_htmode_is_eht(htmode)) 288 hwmode_str = "be"; 289 else { 290 if (hwmodelist & IWINFO_80211_N) 291 hwmode_str = "n"; 292 else if (hwmodelist & IWINFO_80211_G) 293 hwmode_str = "g"; 294 else if (hwmodelist & IWINFO_80211_B) 295 hwmode_str = "b"; 296 else if (hwmodelist & IWINFO_80211_A) 297 hwmode_str = "a"; 298 else 299 hwmode_str = "unknown"; 300 } 301 } else 302 htmode_str = hwmode_str = "unknown"; 303 304 blobmsg_add_string(&buf, "hwmode", hwmode_str); 305 blobmsg_add_string(&buf, "htmode", htmode_str); 306 } 307 308 static void 309 rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *)) 310 { 311 char rv[IWINFO_BUFSIZE] = { 0 }; 312 313 if (!func(ifname, rv)) 314 blobmsg_add_string(&buf, name, rv); 315 } 316 317 static int 318 rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj, 319 struct ubus_request_data *req, const char *method, 320 struct blob_attr *msg) 321 { 322 int rv, hwmodes; 323 void *c; 324 325 rv = rpc_iwinfo_open(msg); 326 327 if (rv) 328 return rv; 329 330 blob_buf_init(&buf, 0); 331 332 rpc_iwinfo_call_str("phy", iw->phyname); 333 334 rpc_iwinfo_call_str("ssid", iw->ssid); 335 rpc_iwinfo_call_str("bssid", iw->bssid); 336 rpc_iwinfo_call_str("country", iw->country); 337 338 rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES); 339 rpc_iwinfo_call_int("channel", iw->channel, NULL); 340 rpc_iwinfo_call_int("center_chan1", iw->center_chan1, NULL); 341 rpc_iwinfo_call_int("center_chan2", iw->center_chan2, NULL); 342 343 rpc_iwinfo_call_int("frequency", iw->frequency, NULL); 344 rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL); 345 346 rpc_iwinfo_call_int("txpower", iw->txpower, NULL); 347 rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL); 348 349 rpc_iwinfo_call_int("quality", iw->quality, NULL); 350 rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL); 351 352 rpc_iwinfo_call_int("signal", iw->signal, NULL); 353 rpc_iwinfo_call_int("noise", iw->noise, NULL); 354 355 rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL); 356 357 rpc_iwinfo_call_encryption("encryption"); 358 rpc_iwinfo_call_htmodes("htmodes"); 359 hwmodes = rpc_iwinfo_call_hwmodes("hwmodes"); 360 361 if (hwmodes > 0) 362 rpc_iwinfo_call_hw_ht_mode(hwmodes); 363 364 c = blobmsg_open_table(&buf, "hardware"); 365 rpc_iwinfo_call_hardware_id("id"); 366 rpc_iwinfo_call_str("name", iw->hardware_name); 367 blobmsg_close_table(&buf, c); 368 369 ubus_send_reply(ctx, req, buf.head); 370 371 rpc_iwinfo_close(); 372 373 return UBUS_STATUS_OK; 374 } 375 376 static int 377 rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj, 378 struct ubus_request_data *req, const char *method, 379 struct blob_attr *msg) 380 { 381 int i, rv, len, band; 382 void *c, *d, *t; 383 char mac[18]; 384 char res[IWINFO_BUFSIZE]; 385 struct iwinfo_scanlist_entry *e; 386 387 rv = rpc_iwinfo_open(msg); 388 389 if (rv) 390 return rv; 391 392 blob_buf_init(&buf, 0); 393 394 c = blobmsg_open_array(&buf, "results"); 395 396 if (!iw->scanlist(ifname, res, &len) && (len > 0)) 397 { 398 for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry)) 399 { 400 e = (struct iwinfo_scanlist_entry *)&res[i]; 401 d = blobmsg_open_table(&buf, NULL); 402 403 if (e->ssid[0]) 404 blobmsg_add_string(&buf, "ssid", (const char *)e->ssid); 405 406 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", 407 e->mac[0], e->mac[1], e->mac[2], 408 e->mac[3], e->mac[4], e->mac[5]); 409 410 blobmsg_add_string(&buf, "bssid", mac); 411 412 blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]); 413 414 band = iwinfo_band2ghz(e->band); 415 if (band > 0) 416 blobmsg_add_u32(&buf, "band", band); 417 blobmsg_add_u32(&buf, "channel", e->channel); 418 blobmsg_add_u32(&buf, "mhz", e->mhz); 419 blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100)); 420 421 blobmsg_add_u32(&buf, "quality", e->quality); 422 blobmsg_add_u32(&buf, "quality_max", e->quality_max); 423 424 if (e->ht_chan_info.primary_chan) { 425 t = blobmsg_open_table(&buf, "ht_operation"); 426 blobmsg_add_u32(&buf, "primary_channel", e->ht_chan_info.primary_chan); 427 blobmsg_add_string(&buf, "secondary_channel_offset", ht_secondary_offset[e->ht_chan_info.secondary_chan_off]); 428 blobmsg_add_u32(&buf, "channel_width", ht_chan_width[e->ht_chan_info.chan_width]); 429 blobmsg_close_table(&buf, t); 430 } 431 432 if (e->vht_chan_info.center_chan_1) { 433 t = blobmsg_open_table(&buf, "vht_operation"); 434 blobmsg_add_u32(&buf, "channel_width", vht_chan_width[e->vht_chan_info.chan_width]); 435 blobmsg_add_u32(&buf, "center_freq_1", e->vht_chan_info.center_chan_1); 436 blobmsg_add_u32(&buf, "center_freq_2", e->vht_chan_info.center_chan_2); 437 blobmsg_close_table(&buf, t); 438 } 439 440 if (e->he_chan_info.center_chan_1) { 441 t = blobmsg_open_table(&buf, "he_operation"); 442 blobmsg_add_u32(&buf, "channel_width", eht_chan_width[e->he_chan_info.chan_width]); 443 blobmsg_add_u32(&buf, "center_freq_1", e->he_chan_info.center_chan_1); 444 blobmsg_add_u32(&buf, "center_freq_2", e->he_chan_info.center_chan_2); 445 blobmsg_close_table(&buf, t); 446 } 447 448 if (e->eht_chan_info.center_chan_1) { 449 t = blobmsg_open_table(&buf, "eht_operation"); 450 blobmsg_add_u32(&buf, "channel_width", eht_chan_width[e->eht_chan_info.chan_width]); 451 blobmsg_add_u32(&buf, "center_freq_1", e->eht_chan_info.center_chan_1); 452 blobmsg_add_u32(&buf, "center_freq_2", e->eht_chan_info.center_chan_2); 453 blobmsg_close_table(&buf, t); 454 } 455 456 rpc_iwinfo_add_encryption("encryption", &e->crypto); 457 458 blobmsg_close_table(&buf, d); 459 } 460 } 461 462 blobmsg_close_array(&buf, c); 463 464 ubus_send_reply(ctx, req, buf.head); 465 466 rpc_iwinfo_close(); 467 468 return UBUS_STATUS_OK; 469 } 470 471 static void 472 rpc_iwinfo_add_rateinfo(struct iwinfo_rate_entry *r) 473 { 474 blobmsg_add_u8(&buf, "ht", r->is_ht); 475 blobmsg_add_u8(&buf, "vht", r->is_vht); 476 blobmsg_add_u8(&buf, "he", r->is_he); 477 blobmsg_add_u8(&buf, "eht", r->is_eht); 478 blobmsg_add_u32(&buf, "mhz", r->mhz_hi * 256 + r->mhz); 479 blobmsg_add_u32(&buf, "rate", r->rate); 480 481 if (r->is_ht) { 482 blobmsg_add_u32(&buf, "mcs", r->mcs); 483 blobmsg_add_u8(&buf, "40mhz", r->is_40mhz); 484 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 485 } 486 else if (r->is_vht) { 487 blobmsg_add_u32(&buf, "mcs", r->mcs); 488 blobmsg_add_u32(&buf, "nss", r->nss); 489 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 490 } 491 else if (r->is_he) { 492 blobmsg_add_u32(&buf, "mcs", r->mcs); 493 blobmsg_add_u32(&buf, "nss", r->nss); 494 blobmsg_add_u32(&buf, "he_gi", r->he_gi); 495 blobmsg_add_u32(&buf, "he_dcm", r->he_dcm); 496 } 497 else if (r->is_eht) { 498 blobmsg_add_u32(&buf, "mcs", r->mcs); 499 blobmsg_add_u32(&buf, "nss", r->nss); 500 blobmsg_add_u32(&buf, "eht_gi", r->eht_gi); 501 } 502 } 503 504 static int 505 rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj, 506 struct ubus_request_data *req, const char *method, 507 struct blob_attr *msg) 508 { 509 int i, rv, len; 510 char mac[18]; 511 char res[IWINFO_BUFSIZE]; 512 struct iwinfo_assoclist_entry *a; 513 struct ether_addr *macaddr = NULL; 514 void *c = NULL, *d, *e; 515 struct blob_attr *tb[__RPC_A_MAX]; 516 bool found = false; 517 518 blobmsg_parse(rpc_assoclist_policy, __RPC_A_MAX, tb, 519 blob_data(msg), blob_len(msg)); 520 521 rv = __rpc_iwinfo_open(tb[RPC_A_DEVICE]); 522 if (rv) 523 return rv; 524 525 if (tb[RPC_A_MACADDR]) 526 macaddr = ether_aton(blobmsg_data(tb[RPC_A_MACADDR])); 527 528 blob_buf_init(&buf, 0); 529 530 if (!macaddr) 531 c = blobmsg_open_array(&buf, "results"); 532 533 if (!iw->assoclist(ifname, res, &len) && (len > 0)) 534 { 535 for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) 536 { 537 a = (struct iwinfo_assoclist_entry *)&res[i]; 538 539 if (!macaddr) 540 d = blobmsg_open_table(&buf, NULL); 541 else if (memcmp(macaddr, a->mac, ETH_ALEN) != 0) 542 continue; 543 544 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", 545 a->mac[0], a->mac[1], a->mac[2], 546 a->mac[3], a->mac[4], a->mac[5]); 547 548 blobmsg_add_string(&buf, "mac", mac); 549 blobmsg_add_u32(&buf, "signal", a->signal); 550 blobmsg_add_u32(&buf, "signal_avg", a->signal_avg); 551 blobmsg_add_u32(&buf, "noise", a->noise); 552 blobmsg_add_u32(&buf, "inactive", a->inactive); 553 blobmsg_add_u32(&buf, "connected_time", a->connected_time); 554 blobmsg_add_u32(&buf, "thr", a->thr); 555 blobmsg_add_u8(&buf, "authorized", a->is_authorized); 556 blobmsg_add_u8(&buf, "authenticated", a->is_authenticated); 557 blobmsg_add_string(&buf, "preamble", a->is_preamble_short ? "short" : "long"); 558 blobmsg_add_u8(&buf, "wme", a->is_wme); 559 blobmsg_add_u8(&buf, "mfp", a->is_mfp); 560 blobmsg_add_u8(&buf, "tdls", a->is_tdls); 561 562 blobmsg_add_u16(&buf, "mesh llid", a->llid); 563 blobmsg_add_u16(&buf, "mesh plid", a->plid); 564 blobmsg_add_string(&buf, "mesh plink", a->plink_state); 565 blobmsg_add_string(&buf, "mesh local PS", a->local_ps); 566 blobmsg_add_string(&buf, "mesh peer PS", a->peer_ps); 567 blobmsg_add_string(&buf, "mesh non-peer PS", a->nonpeer_ps); 568 569 e = blobmsg_open_table(&buf, "rx"); 570 blobmsg_add_u64(&buf, "drop_misc", a->rx_drop_misc); 571 blobmsg_add_u32(&buf, "packets", a->rx_packets); 572 blobmsg_add_u64(&buf, "bytes", a->rx_bytes); 573 rpc_iwinfo_add_rateinfo(&a->rx_rate); 574 blobmsg_close_table(&buf, e); 575 576 e = blobmsg_open_table(&buf, "tx"); 577 blobmsg_add_u32(&buf, "failed", a->tx_failed); 578 blobmsg_add_u32(&buf, "retries", a->tx_retries); 579 blobmsg_add_u32(&buf, "packets", a->tx_packets); 580 blobmsg_add_u64(&buf, "bytes", a->tx_bytes); 581 rpc_iwinfo_add_rateinfo(&a->tx_rate); 582 blobmsg_close_table(&buf, e); 583 584 found = true; 585 if (!macaddr) 586 blobmsg_close_table(&buf, d); 587 else 588 break; 589 } 590 } 591 592 if (!macaddr) 593 blobmsg_close_array(&buf, c); 594 else if (!found) 595 return UBUS_STATUS_NOT_FOUND; 596 597 ubus_send_reply(ctx, req, buf.head); 598 599 rpc_iwinfo_close(); 600 601 return UBUS_STATUS_OK; 602 } 603 604 static int 605 rpc_iwinfo_survey(struct ubus_context *ctx, struct ubus_object *obj, 606 struct ubus_request_data *req, const char *method, 607 struct blob_attr *msg) 608 { 609 char res[IWINFO_BUFSIZE]; 610 struct iwinfo_survey_entry *e; 611 void *c, *d; 612 int i, rv, len; 613 614 blob_buf_init(&buf, 0); 615 616 rv = rpc_iwinfo_open(msg); 617 618 c = blobmsg_open_array(&buf, "results"); 619 620 if (rv || iw->survey(ifname, res, &len) || len < 0) 621 return UBUS_STATUS_OK; 622 623 for (i = 0; i < len; i += sizeof(struct iwinfo_survey_entry)) { 624 e = (struct iwinfo_survey_entry *)&res[i]; 625 626 d = blobmsg_open_table(&buf, NULL); 627 blobmsg_add_u32(&buf, "mhz", e->mhz); 628 blobmsg_add_u32(&buf, "noise", e->noise); 629 blobmsg_add_u64(&buf, "active_time", e->active_time); 630 blobmsg_add_u64(&buf, "busy_time", e->busy_time); 631 blobmsg_add_u64(&buf, "busy_time_ext", e->busy_time_ext); 632 blobmsg_add_u64(&buf, "rx_time", e->rxtime); 633 blobmsg_add_u64(&buf, "tx_time", e->txtime); 634 blobmsg_close_table(&buf, d); 635 } 636 637 blobmsg_close_array(&buf, c); 638 ubus_send_reply(ctx, req, buf.head); 639 rpc_iwinfo_close(); 640 return UBUS_STATUS_OK; 641 } 642 643 static int 644 rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj, 645 struct ubus_request_data *req, const char *method, 646 struct blob_attr *msg) 647 { 648 int i, rv, len, ch, band; 649 char res[IWINFO_BUFSIZE]; 650 struct iwinfo_freqlist_entry *f; 651 void *c, *d; 652 653 rv = rpc_iwinfo_open(msg); 654 655 if (rv) 656 return rv; 657 658 blob_buf_init(&buf, 0); 659 660 c = blobmsg_open_array(&buf, "results"); 661 662 if (!iw->freqlist(ifname, res, &len) && (len > 0)) 663 { 664 if (iw->channel(ifname, &ch)) 665 ch = -1; 666 667 for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry)) 668 { 669 f = (struct iwinfo_freqlist_entry *)&res[i]; 670 d = blobmsg_open_table(&buf, NULL); 671 672 band = iwinfo_band2ghz(f->band); 673 if (band > 0) 674 blobmsg_add_u32(&buf, "band", band); 675 blobmsg_add_u32(&buf, "channel", f->channel); 676 blobmsg_add_u32(&buf, "mhz", f->mhz); 677 blobmsg_add_u8(&buf, "restricted", f->restricted); 678 679 rpc_iwinfo_add_bit_array("flags", f->flags, 680 IWINFO_FREQ_FLAG_NAMES, 681 IWINFO_FREQ_FLAG_COUNT, 682 true, 0); 683 684 if (ch > -1) 685 blobmsg_add_u8(&buf, "active", f->channel == ch); 686 687 blobmsg_close_table(&buf, d); 688 } 689 } 690 691 blobmsg_close_array(&buf, c); 692 693 ubus_send_reply(ctx, req, buf.head); 694 695 rpc_iwinfo_close(); 696 697 return UBUS_STATUS_OK; 698 } 699 700 static int 701 rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj, 702 struct ubus_request_data *req, const char *method, 703 struct blob_attr *msg) 704 { 705 int i, rv, len, pwr, off; 706 char res[IWINFO_BUFSIZE]; 707 struct iwinfo_txpwrlist_entry *t; 708 void *c, *d; 709 710 rv = rpc_iwinfo_open(msg); 711 712 if (rv) 713 return rv; 714 715 blob_buf_init(&buf, 0); 716 717 c = blobmsg_open_array(&buf, "results"); 718 719 if (!iw->txpwrlist(ifname, res, &len) && (len > 0)) 720 { 721 if (iw->txpower(ifname, &pwr)) 722 pwr = -1; 723 724 if (iw->txpower_offset(ifname, &off)) 725 off = 0; 726 727 for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry)) 728 { 729 t = (struct iwinfo_txpwrlist_entry *)&res[i]; 730 d = blobmsg_open_table(&buf, NULL); 731 732 blobmsg_add_u32(&buf, "dbm", t->dbm + off); 733 blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off)); 734 735 if (pwr > -1) 736 blobmsg_add_u8(&buf, "active", t->dbm == pwr); 737 738 blobmsg_close_table(&buf, d); 739 } 740 } 741 742 blobmsg_close_array(&buf, c); 743 744 ubus_send_reply(ctx, req, buf.head); 745 746 rpc_iwinfo_close(); 747 748 return UBUS_STATUS_OK; 749 } 750 751 static const char * 752 rpc_iwinfo_lookup_country(char *buf, int len, int iso3166) 753 { 754 int i; 755 static char ccode[5]; 756 struct iwinfo_country_entry *c; 757 758 for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry)) 759 { 760 c = (struct iwinfo_country_entry *)&buf[i]; 761 762 if (c->iso3166 == iso3166) 763 { 764 snprintf(ccode, sizeof(ccode), "%s", c->ccode); 765 return ccode; 766 } 767 } 768 769 return NULL; 770 } 771 772 static int 773 rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj, 774 struct ubus_request_data *req, const char *method, 775 struct blob_attr *msg) 776 { 777 int rv, len; 778 char cur[3]; 779 char iso3166[3]; 780 char res[IWINFO_BUFSIZE] = {0}; 781 const char *ccode; 782 const struct iwinfo_iso3166_label *l; 783 void *c, *d; 784 785 rv = rpc_iwinfo_open(msg); 786 787 if (rv) 788 return rv; 789 790 blob_buf_init(&buf, 0); 791 792 c = blobmsg_open_array(&buf, "results"); 793 794 if (!iw->countrylist(ifname, res, &len) && (len > 0)) 795 { 796 if (iw->country(ifname, cur)) 797 memset(cur, 0, sizeof(cur)); 798 799 for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++) 800 { 801 ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166); 802 803 if (!ccode) 804 continue; 805 806 d = blobmsg_open_table(&buf, NULL); 807 808 blobmsg_add_string(&buf, "code", ccode); 809 blobmsg_add_string(&buf, "country", (const char *)l->name); 810 811 snprintf(iso3166, sizeof(iso3166), "%c%c", 812 (l->iso3166 / 256), (l->iso3166 % 256)); 813 814 blobmsg_add_string(&buf, "iso3166", iso3166); 815 816 if (cur[0]) 817 blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2)); 818 819 blobmsg_close_table(&buf, d); 820 } 821 } 822 823 blobmsg_close_array(&buf, c); 824 825 ubus_send_reply(ctx, req, buf.head); 826 827 rpc_iwinfo_close(); 828 829 return UBUS_STATUS_OK; 830 } 831 832 static int 833 rpc_iwinfo_phyname(struct ubus_context *ctx, struct ubus_object *obj, 834 struct ubus_request_data *req, const char *method, 835 struct blob_attr *msg) 836 { 837 int i; 838 bool found = false; 839 char res[IWINFO_BUFSIZE]; 840 const struct iwinfo_ops *ops; 841 struct blob_attr *tb[__RPC_U_MAX]; 842 const char *backends[] = { 843 "nl80211", 844 "madwifi", 845 "wl" 846 }; 847 848 blobmsg_parse(rpc_uci_policy, __RPC_U_MAX, tb, 849 blob_data(msg), blob_len(msg)); 850 851 if (!tb[RPC_U_SECTION]) 852 return UBUS_STATUS_INVALID_ARGUMENT; 853 854 for (i = 0; i < ARRAY_SIZE(backends); i++) 855 { 856 ops = iwinfo_backend_by_name(backends[i]); 857 858 if (!ops || !ops->lookup_phy) 859 continue; 860 861 if (!ops->lookup_phy(blobmsg_get_string(tb[RPC_U_SECTION]), res)) 862 { 863 found = true; 864 break; 865 } 866 } 867 868 if (found) 869 { 870 blob_buf_init(&buf, 0); 871 blobmsg_add_string(&buf, "phyname", res); 872 873 ubus_send_reply(ctx, req, buf.head); 874 } 875 876 rpc_iwinfo_close(); 877 878 return found ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND; 879 } 880 881 static int 882 rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj, 883 struct ubus_request_data *req, const char *method, 884 struct blob_attr *msg) 885 { 886 void *c; 887 struct dirent *e; 888 DIR *d; 889 890 d = opendir("/sys/class/net"); 891 892 if (!d) 893 return UBUS_STATUS_UNKNOWN_ERROR; 894 895 blob_buf_init(&buf, 0); 896 897 c = blobmsg_open_array(&buf, "devices"); 898 899 while ((e = readdir(d)) != NULL) 900 { 901 if (e->d_type != DT_LNK) 902 continue; 903 904 if (iwinfo_type(e->d_name)) 905 blobmsg_add_string(&buf, NULL, e->d_name); 906 } 907 908 blobmsg_close_array(&buf, c); 909 910 closedir(d); 911 912 ubus_send_reply(ctx, req, buf.head); 913 914 rpc_iwinfo_close(); 915 916 return UBUS_STATUS_OK; 917 } 918 919 920 static int 921 rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 922 { 923 static const struct ubus_method iwinfo_methods[] = { 924 UBUS_METHOD_NOARG("devices", rpc_iwinfo_devices), 925 UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy), 926 UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy), 927 UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_assoclist_policy), 928 UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy), 929 UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy), 930 UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy), 931 UBUS_METHOD("survey", rpc_iwinfo_survey, rpc_device_policy), 932 UBUS_METHOD("phyname", rpc_iwinfo_phyname, rpc_uci_policy), 933 }; 934 935 static struct ubus_object_type iwinfo_type = 936 UBUS_OBJECT_TYPE("rpcd-plugin-iwinfo", iwinfo_methods); 937 938 static struct ubus_object obj = { 939 .name = "iwinfo", 940 .type = &iwinfo_type, 941 .methods = iwinfo_methods, 942 .n_methods = ARRAY_SIZE(iwinfo_methods), 943 }; 944 945 return ubus_add_object(ctx, &obj); 946 } 947 948 struct rpc_plugin rpc_plugin = { 949 .init = rpc_iwinfo_api_init 950 }; 951
This page was automatically generated by LXR 0.3.1. • OpenWrt