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 288 hwmode_str = "a/g"; 289 } else 290 htmode_str = hwmode_str = "unknown"; 291 292 blobmsg_add_string(&buf, "hwmode", hwmode_str); 293 blobmsg_add_string(&buf, "htmode", htmode_str); 294 } 295 296 static void 297 rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *)) 298 { 299 char rv[IWINFO_BUFSIZE] = { 0 }; 300 301 if (!func(ifname, rv)) 302 blobmsg_add_string(&buf, name, rv); 303 } 304 305 static int 306 rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj, 307 struct ubus_request_data *req, const char *method, 308 struct blob_attr *msg) 309 { 310 int rv, hwmodes; 311 void *c; 312 313 rv = rpc_iwinfo_open(msg); 314 315 if (rv) 316 return rv; 317 318 blob_buf_init(&buf, 0); 319 320 rpc_iwinfo_call_str("phy", iw->phyname); 321 322 rpc_iwinfo_call_str("ssid", iw->ssid); 323 rpc_iwinfo_call_str("bssid", iw->bssid); 324 rpc_iwinfo_call_str("country", iw->country); 325 326 rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES); 327 rpc_iwinfo_call_int("channel", iw->channel, NULL); 328 rpc_iwinfo_call_int("center_chan1", iw->center_chan1, NULL); 329 rpc_iwinfo_call_int("center_chan2", iw->center_chan2, NULL); 330 331 rpc_iwinfo_call_int("frequency", iw->frequency, NULL); 332 rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL); 333 334 rpc_iwinfo_call_int("txpower", iw->txpower, NULL); 335 rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL); 336 337 rpc_iwinfo_call_int("quality", iw->quality, NULL); 338 rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL); 339 340 rpc_iwinfo_call_int("signal", iw->signal, NULL); 341 rpc_iwinfo_call_int("noise", iw->noise, NULL); 342 343 rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL); 344 345 rpc_iwinfo_call_encryption("encryption"); 346 rpc_iwinfo_call_htmodes("htmodes"); 347 hwmodes = rpc_iwinfo_call_hwmodes("hwmodes"); 348 349 if (hwmodes > 0) 350 rpc_iwinfo_call_hw_ht_mode(hwmodes); 351 352 c = blobmsg_open_table(&buf, "hardware"); 353 rpc_iwinfo_call_hardware_id("id"); 354 rpc_iwinfo_call_str("name", iw->hardware_name); 355 blobmsg_close_table(&buf, c); 356 357 ubus_send_reply(ctx, req, buf.head); 358 359 rpc_iwinfo_close(); 360 361 return UBUS_STATUS_OK; 362 } 363 364 static int 365 rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj, 366 struct ubus_request_data *req, const char *method, 367 struct blob_attr *msg) 368 { 369 int i, rv, len, band; 370 void *c, *d, *t; 371 char mac[18]; 372 char res[IWINFO_BUFSIZE]; 373 struct iwinfo_scanlist_entry *e; 374 375 rv = rpc_iwinfo_open(msg); 376 377 if (rv) 378 return rv; 379 380 blob_buf_init(&buf, 0); 381 382 c = blobmsg_open_array(&buf, "results"); 383 384 if (!iw->scanlist(ifname, res, &len) && (len > 0)) 385 { 386 for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry)) 387 { 388 e = (struct iwinfo_scanlist_entry *)&res[i]; 389 d = blobmsg_open_table(&buf, NULL); 390 391 if (e->ssid[0]) 392 blobmsg_add_string(&buf, "ssid", (const char *)e->ssid); 393 394 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", 395 e->mac[0], e->mac[1], e->mac[2], 396 e->mac[3], e->mac[4], e->mac[5]); 397 398 blobmsg_add_string(&buf, "bssid", mac); 399 400 blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]); 401 402 band = iwinfo_band2ghz(e->band); 403 if (band > 0) 404 blobmsg_add_u32(&buf, "band", band); 405 blobmsg_add_u32(&buf, "channel", e->channel); 406 blobmsg_add_u32(&buf, "mhz", e->mhz); 407 blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100)); 408 409 blobmsg_add_u32(&buf, "quality", e->quality); 410 blobmsg_add_u32(&buf, "quality_max", e->quality_max); 411 412 if (e->ht_chan_info.primary_chan) { 413 t = blobmsg_open_table(&buf, "ht_operation"); 414 blobmsg_add_u32(&buf, "primary_channel", e->ht_chan_info.primary_chan); 415 blobmsg_add_string(&buf, "secondary_channel_offset", ht_secondary_offset[e->ht_chan_info.secondary_chan_off]); 416 blobmsg_add_u32(&buf, "channel_width", ht_chan_width[e->ht_chan_info.chan_width]); 417 blobmsg_close_table(&buf, t); 418 } 419 420 if (e->vht_chan_info.center_chan_1) { 421 t = blobmsg_open_table(&buf, "vht_operation"); 422 blobmsg_add_u32(&buf, "channel_width", vht_chan_width[e->vht_chan_info.chan_width]); 423 blobmsg_add_u32(&buf, "center_freq_1", e->vht_chan_info.center_chan_1); 424 blobmsg_add_u32(&buf, "center_freq_2", e->vht_chan_info.center_chan_2); 425 blobmsg_close_table(&buf, t); 426 } 427 428 rpc_iwinfo_add_encryption("encryption", &e->crypto); 429 430 blobmsg_close_table(&buf, d); 431 } 432 } 433 434 blobmsg_close_array(&buf, c); 435 436 ubus_send_reply(ctx, req, buf.head); 437 438 rpc_iwinfo_close(); 439 440 return UBUS_STATUS_OK; 441 } 442 443 static void 444 rpc_iwinfo_add_rateinfo(struct iwinfo_rate_entry *r) 445 { 446 blobmsg_add_u8(&buf, "ht", r->is_ht); 447 blobmsg_add_u8(&buf, "vht", r->is_vht); 448 blobmsg_add_u8(&buf, "he", r->is_he); 449 blobmsg_add_u32(&buf, "mhz", r->mhz); 450 blobmsg_add_u32(&buf, "rate", r->rate); 451 452 if (r->is_ht) { 453 blobmsg_add_u32(&buf, "mcs", r->mcs); 454 blobmsg_add_u8(&buf, "40mhz", r->is_40mhz); 455 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 456 } 457 else if (r->is_vht) { 458 blobmsg_add_u32(&buf, "mcs", r->mcs); 459 blobmsg_add_u32(&buf, "nss", r->nss); 460 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 461 } 462 else if (r->is_he) { 463 blobmsg_add_u32(&buf, "mcs", r->mcs); 464 blobmsg_add_u32(&buf, "nss", r->nss); 465 blobmsg_add_u32(&buf, "he_gi", r->he_gi); 466 blobmsg_add_u32(&buf, "he_dcm", r->he_dcm); 467 } 468 } 469 470 static int 471 rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj, 472 struct ubus_request_data *req, const char *method, 473 struct blob_attr *msg) 474 { 475 int i, rv, len; 476 char mac[18]; 477 char res[IWINFO_BUFSIZE]; 478 struct iwinfo_assoclist_entry *a; 479 struct ether_addr *macaddr = NULL; 480 void *c = NULL, *d, *e; 481 struct blob_attr *tb[__RPC_A_MAX]; 482 bool found = false; 483 484 blobmsg_parse(rpc_assoclist_policy, __RPC_A_MAX, tb, 485 blob_data(msg), blob_len(msg)); 486 487 rv = __rpc_iwinfo_open(tb[RPC_A_DEVICE]); 488 if (rv) 489 return rv; 490 491 if (tb[RPC_A_MACADDR]) 492 macaddr = ether_aton(blobmsg_data(tb[RPC_A_MACADDR])); 493 494 blob_buf_init(&buf, 0); 495 496 if (!macaddr) 497 c = blobmsg_open_array(&buf, "results"); 498 499 if (!iw->assoclist(ifname, res, &len) && (len > 0)) 500 { 501 for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) 502 { 503 a = (struct iwinfo_assoclist_entry *)&res[i]; 504 505 if (!macaddr) 506 d = blobmsg_open_table(&buf, NULL); 507 else if (memcmp(macaddr, a->mac, ETH_ALEN) != 0) 508 continue; 509 510 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", 511 a->mac[0], a->mac[1], a->mac[2], 512 a->mac[3], a->mac[4], a->mac[5]); 513 514 blobmsg_add_string(&buf, "mac", mac); 515 blobmsg_add_u32(&buf, "signal", a->signal); 516 blobmsg_add_u32(&buf, "signal_avg", a->signal_avg); 517 blobmsg_add_u32(&buf, "noise", a->noise); 518 blobmsg_add_u32(&buf, "inactive", a->inactive); 519 blobmsg_add_u32(&buf, "connected_time", a->connected_time); 520 blobmsg_add_u32(&buf, "thr", a->thr); 521 blobmsg_add_u8(&buf, "authorized", a->is_authorized); 522 blobmsg_add_u8(&buf, "authenticated", a->is_authenticated); 523 blobmsg_add_string(&buf, "preamble", a->is_preamble_short ? "short" : "long"); 524 blobmsg_add_u8(&buf, "wme", a->is_wme); 525 blobmsg_add_u8(&buf, "mfp", a->is_mfp); 526 blobmsg_add_u8(&buf, "tdls", a->is_tdls); 527 528 blobmsg_add_u16(&buf, "mesh llid", a->llid); 529 blobmsg_add_u16(&buf, "mesh plid", a->plid); 530 blobmsg_add_string(&buf, "mesh plink", a->plink_state); 531 blobmsg_add_string(&buf, "mesh local PS", a->local_ps); 532 blobmsg_add_string(&buf, "mesh peer PS", a->peer_ps); 533 blobmsg_add_string(&buf, "mesh non-peer PS", a->nonpeer_ps); 534 535 e = blobmsg_open_table(&buf, "rx"); 536 blobmsg_add_u64(&buf, "drop_misc", a->rx_drop_misc); 537 blobmsg_add_u32(&buf, "packets", a->rx_packets); 538 blobmsg_add_u32(&buf, "bytes", a->rx_bytes); 539 rpc_iwinfo_add_rateinfo(&a->rx_rate); 540 blobmsg_close_table(&buf, e); 541 542 e = blobmsg_open_table(&buf, "tx"); 543 blobmsg_add_u32(&buf, "failed", a->tx_failed); 544 blobmsg_add_u32(&buf, "retries", a->tx_retries); 545 blobmsg_add_u32(&buf, "packets", a->tx_packets); 546 blobmsg_add_u32(&buf, "bytes", a->tx_bytes); 547 rpc_iwinfo_add_rateinfo(&a->tx_rate); 548 blobmsg_close_table(&buf, e); 549 550 found = true; 551 if (!macaddr) 552 blobmsg_close_table(&buf, d); 553 else 554 break; 555 } 556 } 557 558 if (!macaddr) 559 blobmsg_close_array(&buf, c); 560 else if (!found) 561 return UBUS_STATUS_NOT_FOUND; 562 563 ubus_send_reply(ctx, req, buf.head); 564 565 rpc_iwinfo_close(); 566 567 return UBUS_STATUS_OK; 568 } 569 570 static int 571 rpc_iwinfo_survey(struct ubus_context *ctx, struct ubus_object *obj, 572 struct ubus_request_data *req, const char *method, 573 struct blob_attr *msg) 574 { 575 char res[IWINFO_BUFSIZE]; 576 struct iwinfo_survey_entry *e; 577 void *c, *d; 578 int i, rv, len; 579 580 blob_buf_init(&buf, 0); 581 582 rv = rpc_iwinfo_open(msg); 583 584 c = blobmsg_open_array(&buf, "results"); 585 586 if (rv || iw->survey(ifname, res, &len) || len < 0) 587 return UBUS_STATUS_OK; 588 589 for (i = 0; i < len; i += sizeof(struct iwinfo_survey_entry)) { 590 e = (struct iwinfo_survey_entry *)&res[i]; 591 592 d = blobmsg_open_table(&buf, NULL); 593 blobmsg_add_u32(&buf, "mhz", e->mhz); 594 blobmsg_add_u32(&buf, "noise", e->noise); 595 blobmsg_add_u64(&buf, "active_time", e->active_time); 596 blobmsg_add_u64(&buf, "busy_time", e->busy_time); 597 blobmsg_add_u64(&buf, "busy_time_ext", e->busy_time_ext); 598 blobmsg_add_u64(&buf, "rx_time", e->rxtime); 599 blobmsg_add_u64(&buf, "tx_time", e->txtime); 600 blobmsg_close_table(&buf, d); 601 } 602 603 blobmsg_close_array(&buf, c); 604 ubus_send_reply(ctx, req, buf.head); 605 rpc_iwinfo_close(); 606 return UBUS_STATUS_OK; 607 } 608 609 static int 610 rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj, 611 struct ubus_request_data *req, const char *method, 612 struct blob_attr *msg) 613 { 614 int i, rv, len, ch, band; 615 char res[IWINFO_BUFSIZE]; 616 struct iwinfo_freqlist_entry *f; 617 void *c, *d; 618 619 rv = rpc_iwinfo_open(msg); 620 621 if (rv) 622 return rv; 623 624 blob_buf_init(&buf, 0); 625 626 c = blobmsg_open_array(&buf, "results"); 627 628 if (!iw->freqlist(ifname, res, &len) && (len > 0)) 629 { 630 if (iw->channel(ifname, &ch)) 631 ch = -1; 632 633 for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry)) 634 { 635 f = (struct iwinfo_freqlist_entry *)&res[i]; 636 d = blobmsg_open_table(&buf, NULL); 637 638 band = iwinfo_band2ghz(f->band); 639 if (band > 0) 640 blobmsg_add_u32(&buf, "band", band); 641 blobmsg_add_u32(&buf, "channel", f->channel); 642 blobmsg_add_u32(&buf, "mhz", f->mhz); 643 blobmsg_add_u8(&buf, "restricted", f->restricted); 644 645 rpc_iwinfo_add_bit_array("flags", f->flags, 646 IWINFO_FREQ_FLAG_NAMES, 647 IWINFO_FREQ_FLAG_COUNT, 648 true, 0); 649 650 if (ch > -1) 651 blobmsg_add_u8(&buf, "active", f->channel == ch); 652 653 blobmsg_close_table(&buf, d); 654 } 655 } 656 657 blobmsg_close_array(&buf, c); 658 659 ubus_send_reply(ctx, req, buf.head); 660 661 rpc_iwinfo_close(); 662 663 return UBUS_STATUS_OK; 664 } 665 666 static int 667 rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj, 668 struct ubus_request_data *req, const char *method, 669 struct blob_attr *msg) 670 { 671 int i, rv, len, pwr, off; 672 char res[IWINFO_BUFSIZE]; 673 struct iwinfo_txpwrlist_entry *t; 674 void *c, *d; 675 676 rv = rpc_iwinfo_open(msg); 677 678 if (rv) 679 return rv; 680 681 blob_buf_init(&buf, 0); 682 683 c = blobmsg_open_array(&buf, "results"); 684 685 if (!iw->txpwrlist(ifname, res, &len) && (len > 0)) 686 { 687 if (iw->txpower(ifname, &pwr)) 688 pwr = -1; 689 690 if (iw->txpower_offset(ifname, &off)) 691 off = 0; 692 693 for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry)) 694 { 695 t = (struct iwinfo_txpwrlist_entry *)&res[i]; 696 d = blobmsg_open_table(&buf, NULL); 697 698 blobmsg_add_u32(&buf, "dbm", t->dbm + off); 699 blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off)); 700 701 if (pwr > -1) 702 blobmsg_add_u8(&buf, "active", t->dbm == pwr); 703 704 blobmsg_close_table(&buf, d); 705 } 706 } 707 708 blobmsg_close_array(&buf, c); 709 710 ubus_send_reply(ctx, req, buf.head); 711 712 rpc_iwinfo_close(); 713 714 return UBUS_STATUS_OK; 715 } 716 717 static const char * 718 rpc_iwinfo_lookup_country(char *buf, int len, int iso3166) 719 { 720 int i; 721 static char ccode[5]; 722 struct iwinfo_country_entry *c; 723 724 for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry)) 725 { 726 c = (struct iwinfo_country_entry *)&buf[i]; 727 728 if (c->iso3166 == iso3166) 729 { 730 snprintf(ccode, sizeof(ccode), "%s", c->ccode); 731 return ccode; 732 } 733 } 734 735 return NULL; 736 } 737 738 static int 739 rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj, 740 struct ubus_request_data *req, const char *method, 741 struct blob_attr *msg) 742 { 743 int rv, len; 744 char cur[3]; 745 char iso3166[3]; 746 char res[IWINFO_BUFSIZE] = {0}; 747 const char *ccode; 748 const struct iwinfo_iso3166_label *l; 749 void *c, *d; 750 751 rv = rpc_iwinfo_open(msg); 752 753 if (rv) 754 return rv; 755 756 blob_buf_init(&buf, 0); 757 758 c = blobmsg_open_array(&buf, "results"); 759 760 if (!iw->countrylist(ifname, res, &len) && (len > 0)) 761 { 762 if (iw->country(ifname, cur)) 763 memset(cur, 0, sizeof(cur)); 764 765 for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++) 766 { 767 ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166); 768 769 if (!ccode) 770 continue; 771 772 d = blobmsg_open_table(&buf, NULL); 773 774 blobmsg_add_string(&buf, "code", ccode); 775 blobmsg_add_string(&buf, "country", (const char *)l->name); 776 777 snprintf(iso3166, sizeof(iso3166), "%c%c", 778 (l->iso3166 / 256), (l->iso3166 % 256)); 779 780 blobmsg_add_string(&buf, "iso3166", iso3166); 781 782 if (cur[0]) 783 blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2)); 784 785 blobmsg_close_table(&buf, d); 786 } 787 } 788 789 blobmsg_close_array(&buf, c); 790 791 ubus_send_reply(ctx, req, buf.head); 792 793 rpc_iwinfo_close(); 794 795 return UBUS_STATUS_OK; 796 } 797 798 static int 799 rpc_iwinfo_phyname(struct ubus_context *ctx, struct ubus_object *obj, 800 struct ubus_request_data *req, const char *method, 801 struct blob_attr *msg) 802 { 803 int i; 804 bool found = false; 805 char res[IWINFO_BUFSIZE]; 806 const struct iwinfo_ops *ops; 807 struct blob_attr *tb[__RPC_U_MAX]; 808 const char *backends[] = { 809 "nl80211", 810 "madwifi", 811 "wl" 812 }; 813 814 blobmsg_parse(rpc_uci_policy, __RPC_U_MAX, tb, 815 blob_data(msg), blob_len(msg)); 816 817 if (!tb[RPC_U_SECTION]) 818 return UBUS_STATUS_INVALID_ARGUMENT; 819 820 for (i = 0; i < ARRAY_SIZE(backends); i++) 821 { 822 ops = iwinfo_backend_by_name(backends[i]); 823 824 if (!ops || !ops->lookup_phy) 825 continue; 826 827 if (!ops->lookup_phy(blobmsg_get_string(tb[RPC_U_SECTION]), res)) 828 { 829 found = true; 830 break; 831 } 832 } 833 834 if (found) 835 { 836 blob_buf_init(&buf, 0); 837 blobmsg_add_string(&buf, "phyname", res); 838 839 ubus_send_reply(ctx, req, buf.head); 840 } 841 842 rpc_iwinfo_close(); 843 844 return found ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND; 845 } 846 847 static int 848 rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj, 849 struct ubus_request_data *req, const char *method, 850 struct blob_attr *msg) 851 { 852 void *c; 853 struct dirent *e; 854 DIR *d; 855 856 d = opendir("/sys/class/net"); 857 858 if (!d) 859 return UBUS_STATUS_UNKNOWN_ERROR; 860 861 blob_buf_init(&buf, 0); 862 863 c = blobmsg_open_array(&buf, "devices"); 864 865 while ((e = readdir(d)) != NULL) 866 { 867 if (e->d_type != DT_LNK) 868 continue; 869 870 if (iwinfo_type(e->d_name)) 871 blobmsg_add_string(&buf, NULL, e->d_name); 872 } 873 874 blobmsg_close_array(&buf, c); 875 876 closedir(d); 877 878 ubus_send_reply(ctx, req, buf.head); 879 880 rpc_iwinfo_close(); 881 882 return UBUS_STATUS_OK; 883 } 884 885 886 static int 887 rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 888 { 889 static const struct ubus_method iwinfo_methods[] = { 890 UBUS_METHOD_NOARG("devices", rpc_iwinfo_devices), 891 UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy), 892 UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy), 893 UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_assoclist_policy), 894 UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy), 895 UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy), 896 UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy), 897 UBUS_METHOD("survey", rpc_iwinfo_survey, rpc_device_policy), 898 UBUS_METHOD("phyname", rpc_iwinfo_phyname, rpc_uci_policy), 899 }; 900 901 static struct ubus_object_type iwinfo_type = 902 UBUS_OBJECT_TYPE("rpcd-plugin-iwinfo", iwinfo_methods); 903 904 static struct ubus_object obj = { 905 .name = "iwinfo", 906 .type = &iwinfo_type, 907 .methods = iwinfo_methods, 908 .n_methods = ARRAY_SIZE(iwinfo_methods), 909 }; 910 911 return ubus_add_object(ctx, &obj); 912 } 913 914 struct rpc_plugin rpc_plugin = { 915 .init = rpc_iwinfo_api_init 916 }; 917
This page was automatically generated by LXR 0.3.1. • OpenWrt