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 rpc_iwinfo_add_encryption("encryption", &e->crypto); 441 442 blobmsg_close_table(&buf, d); 443 } 444 } 445 446 blobmsg_close_array(&buf, c); 447 448 ubus_send_reply(ctx, req, buf.head); 449 450 rpc_iwinfo_close(); 451 452 return UBUS_STATUS_OK; 453 } 454 455 static void 456 rpc_iwinfo_add_rateinfo(struct iwinfo_rate_entry *r) 457 { 458 blobmsg_add_u8(&buf, "ht", r->is_ht); 459 blobmsg_add_u8(&buf, "vht", r->is_vht); 460 blobmsg_add_u8(&buf, "he", r->is_he); 461 blobmsg_add_u8(&buf, "eht", r->is_eht); 462 blobmsg_add_u32(&buf, "mhz", r->mhz_hi * 256 + r->mhz); 463 blobmsg_add_u32(&buf, "rate", r->rate); 464 465 if (r->is_ht) { 466 blobmsg_add_u32(&buf, "mcs", r->mcs); 467 blobmsg_add_u8(&buf, "40mhz", r->is_40mhz); 468 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 469 } 470 else if (r->is_vht) { 471 blobmsg_add_u32(&buf, "mcs", r->mcs); 472 blobmsg_add_u32(&buf, "nss", r->nss); 473 blobmsg_add_u8(&buf, "short_gi", r->is_short_gi); 474 } 475 else if (r->is_he) { 476 blobmsg_add_u32(&buf, "mcs", r->mcs); 477 blobmsg_add_u32(&buf, "nss", r->nss); 478 blobmsg_add_u32(&buf, "he_gi", r->he_gi); 479 blobmsg_add_u32(&buf, "he_dcm", r->he_dcm); 480 } 481 else if (r->is_eht) { 482 blobmsg_add_u32(&buf, "mcs", r->mcs); 483 blobmsg_add_u32(&buf, "nss", r->nss); 484 blobmsg_add_u32(&buf, "eht_gi", r->eht_gi); 485 } 486 } 487 488 static int 489 rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj, 490 struct ubus_request_data *req, const char *method, 491 struct blob_attr *msg) 492 { 493 int i, rv, len; 494 char mac[18]; 495 char res[IWINFO_BUFSIZE]; 496 struct iwinfo_assoclist_entry *a; 497 struct ether_addr *macaddr = NULL; 498 void *c = NULL, *d, *e; 499 struct blob_attr *tb[__RPC_A_MAX]; 500 bool found = false; 501 502 blobmsg_parse(rpc_assoclist_policy, __RPC_A_MAX, tb, 503 blob_data(msg), blob_len(msg)); 504 505 rv = __rpc_iwinfo_open(tb[RPC_A_DEVICE]); 506 if (rv) 507 return rv; 508 509 if (tb[RPC_A_MACADDR]) 510 macaddr = ether_aton(blobmsg_data(tb[RPC_A_MACADDR])); 511 512 blob_buf_init(&buf, 0); 513 514 if (!macaddr) 515 c = blobmsg_open_array(&buf, "results"); 516 517 if (!iw->assoclist(ifname, res, &len) && (len > 0)) 518 { 519 for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) 520 { 521 a = (struct iwinfo_assoclist_entry *)&res[i]; 522 523 if (!macaddr) 524 d = blobmsg_open_table(&buf, NULL); 525 else if (memcmp(macaddr, a->mac, ETH_ALEN) != 0) 526 continue; 527 528 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", 529 a->mac[0], a->mac[1], a->mac[2], 530 a->mac[3], a->mac[4], a->mac[5]); 531 532 blobmsg_add_string(&buf, "mac", mac); 533 blobmsg_add_u32(&buf, "signal", a->signal); 534 blobmsg_add_u32(&buf, "signal_avg", a->signal_avg); 535 blobmsg_add_u32(&buf, "noise", a->noise); 536 blobmsg_add_u32(&buf, "inactive", a->inactive); 537 blobmsg_add_u32(&buf, "connected_time", a->connected_time); 538 blobmsg_add_u32(&buf, "thr", a->thr); 539 blobmsg_add_u8(&buf, "authorized", a->is_authorized); 540 blobmsg_add_u8(&buf, "authenticated", a->is_authenticated); 541 blobmsg_add_string(&buf, "preamble", a->is_preamble_short ? "short" : "long"); 542 blobmsg_add_u8(&buf, "wme", a->is_wme); 543 blobmsg_add_u8(&buf, "mfp", a->is_mfp); 544 blobmsg_add_u8(&buf, "tdls", a->is_tdls); 545 546 blobmsg_add_u16(&buf, "mesh llid", a->llid); 547 blobmsg_add_u16(&buf, "mesh plid", a->plid); 548 blobmsg_add_string(&buf, "mesh plink", a->plink_state); 549 blobmsg_add_string(&buf, "mesh local PS", a->local_ps); 550 blobmsg_add_string(&buf, "mesh peer PS", a->peer_ps); 551 blobmsg_add_string(&buf, "mesh non-peer PS", a->nonpeer_ps); 552 553 e = blobmsg_open_table(&buf, "rx"); 554 blobmsg_add_u64(&buf, "drop_misc", a->rx_drop_misc); 555 blobmsg_add_u32(&buf, "packets", a->rx_packets); 556 blobmsg_add_u64(&buf, "bytes", a->rx_bytes); 557 rpc_iwinfo_add_rateinfo(&a->rx_rate); 558 blobmsg_close_table(&buf, e); 559 560 e = blobmsg_open_table(&buf, "tx"); 561 blobmsg_add_u32(&buf, "failed", a->tx_failed); 562 blobmsg_add_u32(&buf, "retries", a->tx_retries); 563 blobmsg_add_u32(&buf, "packets", a->tx_packets); 564 blobmsg_add_u64(&buf, "bytes", a->tx_bytes); 565 rpc_iwinfo_add_rateinfo(&a->tx_rate); 566 blobmsg_close_table(&buf, e); 567 568 found = true; 569 if (!macaddr) 570 blobmsg_close_table(&buf, d); 571 else 572 break; 573 } 574 } 575 576 if (!macaddr) 577 blobmsg_close_array(&buf, c); 578 else if (!found) 579 return UBUS_STATUS_NOT_FOUND; 580 581 ubus_send_reply(ctx, req, buf.head); 582 583 rpc_iwinfo_close(); 584 585 return UBUS_STATUS_OK; 586 } 587 588 static int 589 rpc_iwinfo_survey(struct ubus_context *ctx, struct ubus_object *obj, 590 struct ubus_request_data *req, const char *method, 591 struct blob_attr *msg) 592 { 593 char res[IWINFO_BUFSIZE]; 594 struct iwinfo_survey_entry *e; 595 void *c, *d; 596 int i, rv, len; 597 598 blob_buf_init(&buf, 0); 599 600 rv = rpc_iwinfo_open(msg); 601 602 c = blobmsg_open_array(&buf, "results"); 603 604 if (rv || iw->survey(ifname, res, &len) || len < 0) 605 return UBUS_STATUS_OK; 606 607 for (i = 0; i < len; i += sizeof(struct iwinfo_survey_entry)) { 608 e = (struct iwinfo_survey_entry *)&res[i]; 609 610 d = blobmsg_open_table(&buf, NULL); 611 blobmsg_add_u32(&buf, "mhz", e->mhz); 612 blobmsg_add_u32(&buf, "noise", e->noise); 613 blobmsg_add_u64(&buf, "active_time", e->active_time); 614 blobmsg_add_u64(&buf, "busy_time", e->busy_time); 615 blobmsg_add_u64(&buf, "busy_time_ext", e->busy_time_ext); 616 blobmsg_add_u64(&buf, "rx_time", e->rxtime); 617 blobmsg_add_u64(&buf, "tx_time", e->txtime); 618 blobmsg_close_table(&buf, d); 619 } 620 621 blobmsg_close_array(&buf, c); 622 ubus_send_reply(ctx, req, buf.head); 623 rpc_iwinfo_close(); 624 return UBUS_STATUS_OK; 625 } 626 627 static int 628 rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj, 629 struct ubus_request_data *req, const char *method, 630 struct blob_attr *msg) 631 { 632 int i, rv, len, ch, band; 633 char res[IWINFO_BUFSIZE]; 634 struct iwinfo_freqlist_entry *f; 635 void *c, *d; 636 637 rv = rpc_iwinfo_open(msg); 638 639 if (rv) 640 return rv; 641 642 blob_buf_init(&buf, 0); 643 644 c = blobmsg_open_array(&buf, "results"); 645 646 if (!iw->freqlist(ifname, res, &len) && (len > 0)) 647 { 648 if (iw->channel(ifname, &ch)) 649 ch = -1; 650 651 for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry)) 652 { 653 f = (struct iwinfo_freqlist_entry *)&res[i]; 654 d = blobmsg_open_table(&buf, NULL); 655 656 band = iwinfo_band2ghz(f->band); 657 if (band > 0) 658 blobmsg_add_u32(&buf, "band", band); 659 blobmsg_add_u32(&buf, "channel", f->channel); 660 blobmsg_add_u32(&buf, "mhz", f->mhz); 661 blobmsg_add_u8(&buf, "restricted", f->restricted); 662 663 rpc_iwinfo_add_bit_array("flags", f->flags, 664 IWINFO_FREQ_FLAG_NAMES, 665 IWINFO_FREQ_FLAG_COUNT, 666 true, 0); 667 668 if (ch > -1) 669 blobmsg_add_u8(&buf, "active", f->channel == ch); 670 671 blobmsg_close_table(&buf, d); 672 } 673 } 674 675 blobmsg_close_array(&buf, c); 676 677 ubus_send_reply(ctx, req, buf.head); 678 679 rpc_iwinfo_close(); 680 681 return UBUS_STATUS_OK; 682 } 683 684 static int 685 rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj, 686 struct ubus_request_data *req, const char *method, 687 struct blob_attr *msg) 688 { 689 int i, rv, len, pwr, off; 690 char res[IWINFO_BUFSIZE]; 691 struct iwinfo_txpwrlist_entry *t; 692 void *c, *d; 693 694 rv = rpc_iwinfo_open(msg); 695 696 if (rv) 697 return rv; 698 699 blob_buf_init(&buf, 0); 700 701 c = blobmsg_open_array(&buf, "results"); 702 703 if (!iw->txpwrlist(ifname, res, &len) && (len > 0)) 704 { 705 if (iw->txpower(ifname, &pwr)) 706 pwr = -1; 707 708 if (iw->txpower_offset(ifname, &off)) 709 off = 0; 710 711 for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry)) 712 { 713 t = (struct iwinfo_txpwrlist_entry *)&res[i]; 714 d = blobmsg_open_table(&buf, NULL); 715 716 blobmsg_add_u32(&buf, "dbm", t->dbm + off); 717 blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off)); 718 719 if (pwr > -1) 720 blobmsg_add_u8(&buf, "active", t->dbm == pwr); 721 722 blobmsg_close_table(&buf, d); 723 } 724 } 725 726 blobmsg_close_array(&buf, c); 727 728 ubus_send_reply(ctx, req, buf.head); 729 730 rpc_iwinfo_close(); 731 732 return UBUS_STATUS_OK; 733 } 734 735 static const char * 736 rpc_iwinfo_lookup_country(char *buf, int len, int iso3166) 737 { 738 int i; 739 static char ccode[5]; 740 struct iwinfo_country_entry *c; 741 742 for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry)) 743 { 744 c = (struct iwinfo_country_entry *)&buf[i]; 745 746 if (c->iso3166 == iso3166) 747 { 748 snprintf(ccode, sizeof(ccode), "%s", c->ccode); 749 return ccode; 750 } 751 } 752 753 return NULL; 754 } 755 756 static int 757 rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj, 758 struct ubus_request_data *req, const char *method, 759 struct blob_attr *msg) 760 { 761 int rv, len; 762 char cur[3]; 763 char iso3166[3]; 764 char res[IWINFO_BUFSIZE] = {0}; 765 const char *ccode; 766 const struct iwinfo_iso3166_label *l; 767 void *c, *d; 768 769 rv = rpc_iwinfo_open(msg); 770 771 if (rv) 772 return rv; 773 774 blob_buf_init(&buf, 0); 775 776 c = blobmsg_open_array(&buf, "results"); 777 778 if (!iw->countrylist(ifname, res, &len) && (len > 0)) 779 { 780 if (iw->country(ifname, cur)) 781 memset(cur, 0, sizeof(cur)); 782 783 for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++) 784 { 785 ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166); 786 787 if (!ccode) 788 continue; 789 790 d = blobmsg_open_table(&buf, NULL); 791 792 blobmsg_add_string(&buf, "code", ccode); 793 blobmsg_add_string(&buf, "country", (const char *)l->name); 794 795 snprintf(iso3166, sizeof(iso3166), "%c%c", 796 (l->iso3166 / 256), (l->iso3166 % 256)); 797 798 blobmsg_add_string(&buf, "iso3166", iso3166); 799 800 if (cur[0]) 801 blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2)); 802 803 blobmsg_close_table(&buf, d); 804 } 805 } 806 807 blobmsg_close_array(&buf, c); 808 809 ubus_send_reply(ctx, req, buf.head); 810 811 rpc_iwinfo_close(); 812 813 return UBUS_STATUS_OK; 814 } 815 816 static int 817 rpc_iwinfo_phyname(struct ubus_context *ctx, struct ubus_object *obj, 818 struct ubus_request_data *req, const char *method, 819 struct blob_attr *msg) 820 { 821 int i; 822 bool found = false; 823 char res[IWINFO_BUFSIZE]; 824 const struct iwinfo_ops *ops; 825 struct blob_attr *tb[__RPC_U_MAX]; 826 const char *backends[] = { 827 "nl80211", 828 "madwifi", 829 "wl" 830 }; 831 832 blobmsg_parse(rpc_uci_policy, __RPC_U_MAX, tb, 833 blob_data(msg), blob_len(msg)); 834 835 if (!tb[RPC_U_SECTION]) 836 return UBUS_STATUS_INVALID_ARGUMENT; 837 838 for (i = 0; i < ARRAY_SIZE(backends); i++) 839 { 840 ops = iwinfo_backend_by_name(backends[i]); 841 842 if (!ops || !ops->lookup_phy) 843 continue; 844 845 if (!ops->lookup_phy(blobmsg_get_string(tb[RPC_U_SECTION]), res)) 846 { 847 found = true; 848 break; 849 } 850 } 851 852 if (found) 853 { 854 blob_buf_init(&buf, 0); 855 blobmsg_add_string(&buf, "phyname", res); 856 857 ubus_send_reply(ctx, req, buf.head); 858 } 859 860 rpc_iwinfo_close(); 861 862 return found ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND; 863 } 864 865 static int 866 rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj, 867 struct ubus_request_data *req, const char *method, 868 struct blob_attr *msg) 869 { 870 void *c; 871 struct dirent *e; 872 DIR *d; 873 874 d = opendir("/sys/class/net"); 875 876 if (!d) 877 return UBUS_STATUS_UNKNOWN_ERROR; 878 879 blob_buf_init(&buf, 0); 880 881 c = blobmsg_open_array(&buf, "devices"); 882 883 while ((e = readdir(d)) != NULL) 884 { 885 if (e->d_type != DT_LNK) 886 continue; 887 888 if (iwinfo_type(e->d_name)) 889 blobmsg_add_string(&buf, NULL, e->d_name); 890 } 891 892 blobmsg_close_array(&buf, c); 893 894 closedir(d); 895 896 ubus_send_reply(ctx, req, buf.head); 897 898 rpc_iwinfo_close(); 899 900 return UBUS_STATUS_OK; 901 } 902 903 904 static int 905 rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 906 { 907 static const struct ubus_method iwinfo_methods[] = { 908 UBUS_METHOD_NOARG("devices", rpc_iwinfo_devices), 909 UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy), 910 UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy), 911 UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_assoclist_policy), 912 UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy), 913 UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy), 914 UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy), 915 UBUS_METHOD("survey", rpc_iwinfo_survey, rpc_device_policy), 916 UBUS_METHOD("phyname", rpc_iwinfo_phyname, rpc_uci_policy), 917 }; 918 919 static struct ubus_object_type iwinfo_type = 920 UBUS_OBJECT_TYPE("rpcd-plugin-iwinfo", iwinfo_methods); 921 922 static struct ubus_object obj = { 923 .name = "iwinfo", 924 .type = &iwinfo_type, 925 .methods = iwinfo_methods, 926 .n_methods = ARRAY_SIZE(iwinfo_methods), 927 }; 928 929 return ubus_add_object(ctx, &obj); 930 } 931 932 struct rpc_plugin rpc_plugin = { 933 .init = rpc_iwinfo_api_init 934 }; 935
This page was automatically generated by LXR 0.3.1. • OpenWrt