Home | History | Annotate | Download | only in ti-utils
      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 
     28 char calibrator_version[] = "0.71";
     29 #ifndef CONFIG_LIBNL20
     30 /* libnl 2.0 compatibility code */
     31 
     32 static inline struct nl_handle *nl_socket_alloc(void)
     33 {
     34     return nl_handle_alloc();
     35 }
     36 
     37 static inline void nl_socket_free(struct nl_sock *h)
     38 {
     39     nl_handle_destroy(h);
     40 }
     41 
     42 static 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 
     55 int calibrator_debug;
     56 
     57 static 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 
     95 static 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 
    102 static int cmd_size;
    103 
    104 extern struct cmd __start___cmd;
    105 extern 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 
    112 static 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 
    165 static void usage_options(void)
    166 {
    167     printf("Options:\n");
    168     printf("\t--debug\t\tenable netlink debugging\n");
    169 }
    170 
    171 static const char *argv0;
    172 
    173 static 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 
    210 static 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 }
    217 TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help,
    218      "Print usage for each command.");
    219 
    220 static 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 
    227 static void version(void)
    228 {
    229     printf("calibrator version %s\n", calibrator_version);
    230 }
    231 
    232 static 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 
    253 static 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 
    262 static int finish_handler(struct nl_msg *msg, void *arg)
    263 {
    264     int *ret = arg;
    265     *ret = 0;
    266 
    267     return NL_SKIP;
    268 }
    269 
    270 static int ack_handler(struct nl_msg *msg, void *arg)
    271 {
    272     int *ret = arg;
    273     *ret = 0;
    274 
    275     return NL_STOP;
    276 }
    277 
    278 static 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 
    476 int 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 
    482 int 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