1/* 2 * PLT utility for wireless chip supported by TI's driver wl12xx 3 * 4 * See README and COPYING for more details. 5 */ 6 7#include <errno.h> 8#include <stdio.h> 9#include <string.h> 10#include <net/if.h> 11#include <sys/types.h> 12#include <sys/stat.h> 13#include <fcntl.h> 14#include <unistd.h> 15#include <stdbool.h> 16 17#include <netlink/genl/genl.h> 18#include <netlink/genl/family.h> 19#include <netlink/genl/ctrl.h> 20#include <netlink/msg.h> 21#include <netlink/attr.h> 22 23#include "nl80211.h" 24#include "calibrator.h" 25#include "plt.h" 26#include "ini.h" 27 28char calibrator_version[] = "0.71"; 29#ifndef CONFIG_LIBNL20 30/* libnl 2.0 compatibility code */ 31 32static inline struct nl_handle *nl_socket_alloc(void) 33{ 34 return nl_handle_alloc(); 35} 36 37static inline void nl_socket_free(struct nl_sock *h) 38{ 39 nl_handle_destroy(h); 40} 41 42static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, 43 struct nl_cache **cache) 44{ 45 struct nl_cache *tmp = genl_ctrl_alloc_cache(h); 46 if (!tmp) { 47 return -ENOMEM; 48 } 49 *cache = tmp; 50 return 0; 51} 52#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache 53#endif /* CONFIG_LIBNL20 */ 54 55int calibrator_debug; 56 57static int nl80211_init(struct nl80211_state *state) 58{ 59 int err; 60 61 state->nl_sock = nl_socket_alloc(); 62 if (!state->nl_sock) { 63 fprintf(stderr, "Failed to allocate netlink socket.\n"); 64 return -ENOMEM; 65 } 66 67 if (genl_connect(state->nl_sock)) { 68 fprintf(stderr, "Failed to connect to generic netlink.\n"); 69 err = -ENOLINK; 70 goto out_handle_destroy; 71 } 72 73 if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) { 74 fprintf(stderr, "Failed to allocate generic netlink cache.\n"); 75 err = -ENOMEM; 76 goto out_handle_destroy; 77 } 78 79 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); 80 if (!state->nl80211) { 81 fprintf(stderr, "nl80211 not found.\n"); 82 err = -ENOENT; 83 goto out_cache_free; 84 } 85 86 return 0; 87 88 out_cache_free: 89 nl_cache_free(state->nl_cache); 90 out_handle_destroy: 91 nl_socket_free(state->nl_sock); 92 return err; 93} 94 95static void nl80211_cleanup(struct nl80211_state *state) 96{ 97 genl_family_put(state->nl80211); 98 nl_cache_free(state->nl_cache); 99 nl_socket_free(state->nl_sock); 100} 101 102static int cmd_size; 103 104extern struct cmd __start___cmd; 105extern struct cmd __stop___cmd; 106 107#define for_each_cmd(_cmd) \ 108 for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \ 109 _cmd = (const struct cmd *)((char *)_cmd + cmd_size)) 110 111 112static void __usage_cmd(const struct cmd *cmd, char *indent, bool full) 113{ 114 const char *start, *lend, *end; 115 116 printf("%s", indent); 117 118 switch (cmd->idby) { 119 case CIB_NONE: 120 break; 121 case CIB_PHY: 122 printf("phy <phyname> "); 123 break; 124 case CIB_NETDEV: 125 printf("dev <devname> "); 126 break; 127 } 128 if (cmd->parent && cmd->parent->name) { 129 printf("%s ", cmd->parent->name); 130 } 131 printf("%s", cmd->name); 132 if (cmd->args) { 133 printf(" %s", cmd->args); 134 } 135 printf("\n"); 136 137 if (!full || !cmd->help) { 138 return; 139 } 140 141 /* hack */ 142 if (strlen(indent)) { 143 indent = "\t\t"; 144 } 145 else { 146 printf("\n"); 147 } 148 149 /* print line by line */ 150 start = cmd->help; 151 end = strchr(start, '\0'); 152 do { 153 lend = strchr(start, '\n'); 154 if (!lend) { 155 lend = end; 156 } 157 printf("%s", indent); 158 printf("%.*s\n", (int)(lend - start), start); 159 start = lend + 1; 160 } while (end != lend); 161 162 printf("\n"); 163} 164 165static void usage_options(void) 166{ 167 printf("Options:\n"); 168 printf("\t--debug\t\tenable netlink debugging\n"); 169} 170 171static const char *argv0; 172 173static void usage(bool full) 174{ 175 const struct cmd *section, *cmd; 176 177 printf("Usage:\t%s [options] command\n", argv0); 178 usage_options(); 179 printf("\t--version\tshow version (%s)\n", calibrator_version); 180 printf("Commands:\n"); 181 for_each_cmd(section) { 182 if (section->parent) { 183 continue; 184 } 185 186 if (section->handler && !section->hidden) { 187 __usage_cmd(section, "\t", full); 188 } 189 190 for_each_cmd(cmd) { 191 if (section != cmd->parent) { 192 continue; 193 } 194 if (!cmd->handler || cmd->hidden) { 195 continue; 196 } 197 __usage_cmd(cmd, "\t", full); 198 } 199 } 200#if 0 201 printf("\nYou can omit the 'phy' or 'dev' if " 202 "the identification is unique,\n" 203 "e.g. \"iw wlan0 info\" or \"iw phy0 info\". " 204 "(Don't when scripting.)\n\n" 205 "Do NOT screenscrape this tool, we don't " 206 "consider its output stable.\n\n"); 207#endif 208} 209 210static int print_help(struct nl80211_state *state, 211 struct nl_cb *cb, 212 struct nl_msg *msg, 213 int argc, char **argv) 214{ 215 exit(3); 216} 217TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help, 218 "Print usage for each command."); 219 220static void usage_cmd(const struct cmd *cmd) 221{ 222 printf("\nUsage:\t%s [options] ", argv0); 223 __usage_cmd(cmd, "", true); 224 usage_options(); 225} 226 227static void version(void) 228{ 229 printf("calibrator version %s\n", calibrator_version); 230} 231 232static int phy_lookup(char *name) 233{ 234 char buf[200]; 235 int fd, pos; 236 237 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 238 239 fd = open(buf, O_RDONLY); 240 if (fd < 0) { 241 return -1; 242 } 243 pos = read(fd, buf, sizeof(buf) - 1); 244 if (pos < 0) { 245 close(fd); 246 return -1; 247 } 248 buf[pos] = '\0'; 249 close(fd); 250 return atoi(buf); 251} 252 253static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 254 void *arg) 255{ 256 int *ret = arg; 257 *ret = err->error; 258 259 return NL_STOP; 260} 261 262static int finish_handler(struct nl_msg *msg, void *arg) 263{ 264 int *ret = arg; 265 *ret = 0; 266 267 return NL_SKIP; 268} 269 270static int ack_handler(struct nl_msg *msg, void *arg) 271{ 272 int *ret = arg; 273 *ret = 0; 274 275 return NL_STOP; 276} 277 278static int __handle_cmd(struct nl80211_state *state, enum id_input idby, 279 int argc, char **argv, const struct cmd **cmdout) 280{ 281 const struct cmd *cmd, *match = NULL, *sectcmd; 282 struct nl_cb *cb; 283 struct nl_msg *msg; 284 int devidx = 0; 285 int err, o_argc; 286 const char *command, *section; 287 char *tmp, **o_argv; 288 enum command_identify_by command_idby = CIB_NONE; 289#if 0 290 if (file_exist(CURRENT_NVS_NAME) < 0) { 291 fprintf(stderr, "\n\tUnable to find NVS file (%s).\n\t" 292 "Make sure to use reference-nvs.bin instead.\n\n", 293 CURRENT_NVS_NAME); 294 return 2; 295 } 296#endif 297 if (argc <= 1) { 298 return 1; 299 } 300 301 o_argc = argc; 302 o_argv = argv; 303 304 switch (idby) { 305 case II_PHY_IDX: 306 command_idby = CIB_PHY; 307 devidx = strtoul(*argv + 4, &tmp, 0); 308 if (*tmp != '\0') { 309 return 1; 310 } 311 argc--; 312 argv++; 313 break; 314 case II_PHY_NAME: 315 command_idby = CIB_PHY; 316 devidx = phy_lookup(*argv); 317 argc--; 318 argv++; 319 break; 320 case II_NETDEV: 321 command_idby = CIB_NETDEV; 322 devidx = if_nametoindex(*argv); 323 if (devidx == 0) { 324 devidx = -1; 325 } 326 argc--; 327 argv++; 328 break; 329 default: 330 break; 331 } 332 333 if (devidx < 0) { 334 return -errno; 335 } 336 337 section = *argv; 338 argc--; 339 argv++; 340 341 for_each_cmd(sectcmd) { 342 if (sectcmd->parent) { 343 continue; 344 } 345 /* ok ... bit of a hack for the dupe 'info' section */ 346 if (match && sectcmd->idby != command_idby) { 347 continue; 348 } 349 350 if (strcmp(sectcmd->name, section) == 0) { 351 match = sectcmd; 352 } 353 } 354 355 sectcmd = match; 356 match = NULL; 357 if (!sectcmd) { 358 return 1; 359 } 360 361 if (argc > 0) { 362 command = *argv; 363 364 for_each_cmd(cmd) { 365 if (!cmd->handler) { 366 continue; 367 } 368 if (cmd->parent != sectcmd) { 369 continue; 370 } 371 if (cmd->idby != command_idby) { 372 continue; 373 } 374 if (strcmp(cmd->name, command)) { 375 continue; 376 } 377 if (argc > 1 && !cmd->args) { 378 continue; 379 } 380 match = cmd; 381 break; 382 } 383 384 if (match) { 385 argc--; 386 argv++; 387 } 388 } 389 390 391 if (match) { 392 cmd = match; 393 } else { 394 /* Use the section itself, if possible. */ 395 cmd = sectcmd; 396 if (argc && !cmd->args) { 397 return 1; 398 } 399 if (cmd->idby != command_idby) { 400 return 1; 401 } 402 if (!cmd->handler) { 403 return 1; 404 } 405 } 406 407 if (cmdout) { 408 *cmdout = cmd; 409 } 410 411 if (!cmd->cmd) { 412 argc = o_argc; 413 argv = o_argv; 414 return cmd->handler(state, NULL, NULL, argc, argv); 415 } 416 417 msg = nlmsg_alloc(); 418 if (!msg) { 419 fprintf(stderr, "failed to allocate netlink message\n"); 420 return 2; 421 } 422 423 cb = nl_cb_alloc(calibrator_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 424 if (!cb) { 425 fprintf(stderr, "failed to allocate netlink callbacks\n"); 426 err = 2; 427 goto out_free_msg; 428 } 429 430 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 431 cmd->nl_msg_flags, cmd->cmd, 0); 432 433 switch (command_idby) { 434 case CIB_PHY: 435 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); 436 break; 437 case CIB_NETDEV: 438 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); 439 break; 440 default: 441 break; 442 } 443 444 err = cmd->handler(state, cb, msg, argc, argv); 445 if (err) { 446 fprintf(stderr, "failed to handle\n"); 447 goto out; 448 } 449 450 err = nl_send_auto_complete(state->nl_sock, msg); 451 if (err < 0) { 452 fprintf(stderr, "failed to autocomplete\n"); 453 goto out; 454 } 455 456 err = 1; 457 458 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 459 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); 460 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 461 462 while (err > 0) 463 nl_recvmsgs(state->nl_sock, cb); 464 465 out: 466 nl_cb_put(cb); 467 out_free_msg: 468 nlmsg_free(msg); 469 return err; 470 471 nla_put_failure: 472 fprintf(stderr, "building message failed\n"); 473 return 2; 474} 475 476int handle_cmd(struct nl80211_state *state, enum id_input idby, 477 int argc, char **argv) 478{ 479 return __handle_cmd(state, idby, argc, argv, NULL); 480} 481 482int main(int argc, char **argv) 483{ 484 struct nl80211_state nlstate; 485 int err; 486 const struct cmd *cmd = NULL; 487 488 /* calculate command size including padding */ 489 cmd_size = abs((long)&__section_set - (long)&__section_get); 490 /* strip off self */ 491 argc--; 492 argv0 = *argv++; 493 494 if (argc > 0 && strcmp(*argv, "--debug") == 0) { 495 calibrator_debug = 1; 496 argc--; 497 argv++; 498 } 499 500 if (argc > 0 && strcmp(*argv, "--version") == 0) { 501 version(); 502 return 0; 503 } 504 505 /* need to treat "help" command specially so it works w/o nl80211 */ 506 if (argc == 0 || strcmp(*argv, "help") == 0) { 507 usage(argc != 0); 508 return 0; 509 } 510 511 err = nl80211_init(&nlstate); 512 if (err) { 513 return 1; 514 } 515 516 if (strcmp(*argv, "dev") == 0 && argc > 1) { 517 argc--; 518 argv++; 519 err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd); 520 } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) { 521 if (strlen(*argv) == 3) { 522 argc--; 523 argv++; 524 err = __handle_cmd(&nlstate, II_PHY_NAME, 525 argc, argv, &cmd); 526 } else if (*(*argv + 3) == '#') 527 err = __handle_cmd(&nlstate, II_PHY_IDX, 528 argc, argv, &cmd); 529 else 530 goto detect; 531 } else { 532 int idx; 533 enum id_input idby = II_NONE; 534 detect: 535 idx = if_nametoindex(argv[0]); 536 if (idx != 0) { 537 idby = II_NETDEV; 538 } else { 539 idx = phy_lookup(argv[0]); 540 if (idx >= 0) { 541 idby = II_PHY_NAME; 542 } 543 } 544 545 err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); 546 } 547 548 if (err == 1) { 549 if (cmd) { 550 usage_cmd(cmd); 551 } 552 else 553 usage(false); 554 } else if (err < 0) 555 fprintf(stderr, "command failed: %s (%d)\n", 556 strerror(-err), err); 557 558 nl80211_cleanup(&nlstate); 559 560 return err; 561} 562