iw.c revision 66f8ca457aa27222f79d97096dd34ec4b0719783
1/* 2 * nl80211 userspace tool 3 * 4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net> 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 "iw.h" 25 26#ifndef CONFIG_LIBNL20 27/* libnl 2.0 compatibility code */ 28 29static inline struct nl_handle *nl_socket_alloc(void) 30{ 31 return nl_handle_alloc(); 32} 33 34static inline void nl_socket_free(struct nl_sock *h) 35{ 36 nl_handle_destroy(h); 37} 38 39static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache) 40{ 41 struct nl_cache *tmp = genl_ctrl_alloc_cache(h); 42 if (!tmp) 43 return -ENOMEM; 44 *cache = tmp; 45 return 0; 46} 47#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache 48#endif /* CONFIG_LIBNL20 */ 49 50int iw_debug = 0; 51 52static int nl80211_init(struct nl80211_state *state) 53{ 54 int err; 55 56 state->nl_sock = nl_socket_alloc(); 57 if (!state->nl_sock) { 58 fprintf(stderr, "Failed to allocate netlink socket.\n"); 59 return -ENOMEM; 60 } 61 62 if (genl_connect(state->nl_sock)) { 63 fprintf(stderr, "Failed to connect to generic netlink.\n"); 64 err = -ENOLINK; 65 goto out_handle_destroy; 66 } 67 68 if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) { 69 fprintf(stderr, "Failed to allocate generic netlink cache.\n"); 70 err = -ENOMEM; 71 goto out_handle_destroy; 72 } 73 74 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); 75 if (!state->nl80211) { 76 fprintf(stderr, "nl80211 not found.\n"); 77 err = -ENOENT; 78 goto out_cache_free; 79 } 80 81 return 0; 82 83 out_cache_free: 84 nl_cache_free(state->nl_cache); 85 out_handle_destroy: 86 nl_socket_free(state->nl_sock); 87 return err; 88} 89 90static void nl80211_cleanup(struct nl80211_state *state) 91{ 92 genl_family_put(state->nl80211); 93 nl_cache_free(state->nl_cache); 94 nl_socket_free(state->nl_sock); 95} 96 97__COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL, NULL); 98__COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL, NULL); 99 100static int cmd_size; 101 102static void __usage_cmd(struct cmd *cmd, char *indent, bool full) 103{ 104 const char *start, *lend, *end; 105 106 fprintf(stderr, "%s", indent); 107 108 switch (cmd->idby) { 109 case CIB_NONE: 110 break; 111 case CIB_PHY: 112 fprintf(stderr, "phy <phyname> "); 113 break; 114 case CIB_NETDEV: 115 fprintf(stderr, "dev <devname> "); 116 break; 117 } 118 if (cmd->section) 119 fprintf(stderr, "%s ", cmd->section); 120 fprintf(stderr, "%s", cmd->name); 121 if (cmd->args) 122 fprintf(stderr, " %s", cmd->args); 123 fprintf(stderr, "\n"); 124 125 if (!full || !cmd->help) 126 return; 127 128 /* hack */ 129 if (strlen(indent)) 130 indent = "\t\t"; 131 else 132 fprintf(stderr, "\n"); 133 134 /* print line by line */ 135 start = cmd->help; 136 end = strchr(start, '\0'); 137 do { 138 lend = strchr(start, '\n'); 139 if (!lend) 140 lend = end; 141 fprintf(stderr, "%s", indent); 142 fprintf(stderr, "%.*s\n", (int)(lend - start), start); 143 start = lend + 1; 144 } while (end != lend); 145 146 fprintf(stderr, "\n"); 147} 148 149static void usage_options(void) 150{ 151 fprintf(stderr, "Options:\n"); 152 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n"); 153} 154 155static const char *argv0; 156 157static void usage(bool full) 158{ 159 struct cmd *cmd; 160 161 fprintf(stderr, "Usage:\t%s [options] command\n", argv0); 162 usage_options(); 163 fprintf(stderr, "\t--version\tshow version (%s)\n", iw_version); 164 fprintf(stderr, "Commands:\n"); 165 for (cmd = &__start___cmd; cmd < &__stop___cmd; 166 cmd = (struct cmd *)((char *)cmd + cmd_size)) { 167 if (!cmd->handler || cmd->hidden) 168 continue; 169 __usage_cmd(cmd, "\t", full); 170 } 171 fprintf(stderr, "\nYou can omit the 'phy' or 'dev' if " 172 "the identification is unique,\n" 173 "e.g. \"iw wlan0 info\" or \"iw phy0 info\". " 174 "(Don't when scripting.)\n\n"); 175} 176 177static int print_help(struct nl80211_state *state, 178 struct nl_cb *cb, 179 struct nl_msg *msg, 180 int argc, char **argv) 181{ 182 exit(3); 183} 184TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help, 185 "Print usage for each command."); 186 187static void usage_cmd(struct cmd *cmd) 188{ 189 fprintf(stderr, "Usage:\t%s [options] ", argv0); 190 __usage_cmd(cmd, "", true); 191 usage_options(); 192} 193 194static void version(void) 195{ 196 printf("iw version %s\n", iw_version); 197} 198 199static int phy_lookup(char *name) 200{ 201 char buf[200]; 202 int fd, pos; 203 204 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 205 206 fd = open(buf, O_RDONLY); 207 if (fd < 0) 208 return -1; 209 pos = read(fd, buf, sizeof(buf) - 1); 210 if (pos < 0) 211 return -1; 212 buf[pos] = '\0'; 213 return atoi(buf); 214} 215 216static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 217 void *arg) 218{ 219 int *ret = arg; 220 *ret = err->error; 221 return NL_STOP; 222} 223 224static int finish_handler(struct nl_msg *msg, void *arg) 225{ 226 int *ret = arg; 227 *ret = 0; 228 return NL_SKIP; 229} 230 231static int ack_handler(struct nl_msg *msg, void *arg) 232{ 233 int *ret = arg; 234 *ret = 0; 235 return NL_STOP; 236} 237 238static int __handle_cmd(struct nl80211_state *state, enum id_input idby, 239 int argc, char **argv, struct cmd **cmdout) 240{ 241 struct cmd *cmd, *match = NULL; 242 struct nl_cb *cb; 243 struct nl_msg *msg; 244 int devidx = 0; 245 int err, o_argc; 246 const char *command, *section; 247 char *tmp, **o_argv; 248 enum command_identify_by command_idby = CIB_NONE; 249 250 if (argc <= 1 && idby != II_NONE) 251 return 1; 252 253 o_argc = argc; 254 o_argv = argv; 255 256 switch (idby) { 257 case II_PHY_IDX: 258 command_idby = CIB_PHY; 259 devidx = strtoul(*argv + 4, &tmp, 0); 260 if (*tmp != '\0') 261 return 1; 262 argc--; 263 argv++; 264 break; 265 case II_PHY_NAME: 266 command_idby = CIB_PHY; 267 devidx = phy_lookup(*argv); 268 argc--; 269 argv++; 270 break; 271 case II_NETDEV: 272 command_idby = CIB_NETDEV; 273 devidx = if_nametoindex(*argv); 274 if (devidx == 0) 275 devidx = -1; 276 argc--; 277 argv++; 278 break; 279 default: 280 break; 281 } 282 283 if (devidx < 0) 284 return -errno; 285 286 section = command = *argv; 287 argc--; 288 argv++; 289 290 for (cmd = &__start___cmd; cmd < &__stop___cmd; 291 cmd = (struct cmd *)((char *)cmd + cmd_size)) { 292 if (!cmd->handler) 293 continue; 294 if (cmd->idby != command_idby) 295 continue; 296 if (cmd->section) { 297 if (strcmp(cmd->section, section)) 298 continue; 299 /* this is a bit icky ... */ 300 if (command == section) { 301 if (argc <= 0) { 302 if (match) 303 break; 304 return 1; 305 } 306 command = *argv; 307 argc--; 308 argv++; 309 } 310 } else if (section != command) 311 continue; 312 if (strcmp(cmd->name, command)) 313 continue; 314 if (argc && !cmd->args) 315 continue; 316 317 match = cmd; 318 } 319 320 cmd = match; 321 322 if (!cmd) 323 return 1; 324 325 if (cmdout) 326 *cmdout = cmd; 327 328 if (!cmd->cmd) { 329 argc = o_argc; 330 argv = o_argv; 331 return cmd->handler(state, NULL, NULL, argc, argv); 332 } 333 334 msg = nlmsg_alloc(); 335 if (!msg) { 336 fprintf(stderr, "failed to allocate netlink message\n"); 337 return 2; 338 } 339 340 cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 341 if (!cb) { 342 fprintf(stderr, "failed to allocate netlink callbacks\n"); 343 err = 2; 344 goto out_free_msg; 345 } 346 347 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 348 cmd->nl_msg_flags, cmd->cmd, 0); 349 350 switch (command_idby) { 351 case CIB_PHY: 352 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); 353 break; 354 case CIB_NETDEV: 355 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); 356 break; 357 default: 358 break; 359 } 360 361 err = cmd->handler(state, cb, msg, argc, argv); 362 if (err) 363 goto out; 364 365 err = nl_send_auto_complete(state->nl_sock, msg); 366 if (err < 0) 367 goto out; 368 369 err = 1; 370 371 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 372 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); 373 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 374 375 while (err > 0) 376 nl_recvmsgs(state->nl_sock, cb); 377 out: 378 nl_cb_put(cb); 379 out_free_msg: 380 nlmsg_free(msg); 381 return err; 382 nla_put_failure: 383 fprintf(stderr, "building message failed\n"); 384 return 2; 385} 386 387int handle_cmd(struct nl80211_state *state, enum id_input idby, 388 int argc, char **argv) 389{ 390 return __handle_cmd(state, idby, argc, argv, NULL); 391} 392 393int main(int argc, char **argv) 394{ 395 struct nl80211_state nlstate; 396 int err; 397 struct cmd *cmd = NULL; 398 399 /* calculate command size including padding */ 400 cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0 401 - (long)&__cmd_NULL_NULL_0_CIB_NONE_0); 402 /* strip off self */ 403 argc--; 404 argv0 = *argv++; 405 406 if (argc > 0 && strcmp(*argv, "--debug") == 0) { 407 iw_debug = 1; 408 argc--; 409 argv++; 410 } 411 412 if (argc > 0 && strcmp(*argv, "--version") == 0) { 413 version(); 414 return 0; 415 } 416 417 /* need to treat "help" command specially so it works w/o nl80211 */ 418 if (argc == 0 || strcmp(*argv, "help") == 0) { 419 usage(argc != 0); 420 return 0; 421 } 422 423 err = nl80211_init(&nlstate); 424 if (err) 425 return 1; 426 427 if (strcmp(*argv, "dev") == 0 && argc > 1) { 428 argc--; 429 argv++; 430 err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd); 431 } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) { 432 if (strlen(*argv) == 3) { 433 argc--; 434 argv++; 435 err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd); 436 } else if (*(*argv + 3) == '#') 437 err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd); 438 else 439 goto detect; 440 } else { 441 int idx; 442 enum id_input idby = II_NONE; 443 detect: 444 if ((idx = if_nametoindex(argv[0])) != 0) 445 idby = II_NETDEV; 446 else if ((idx = phy_lookup(argv[0])) >= 0) 447 idby = II_PHY_NAME; 448 err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); 449 } 450 451 if (err == 1) { 452 if (cmd) 453 usage_cmd(cmd); 454 else 455 usage(false); 456 } else if (err < 0) 457 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); 458 459 nl80211_cleanup(&nlstate); 460 461 return err; 462} 463