iw.c revision 601c6ab203c52c038e1b3a34232486295a84a999
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 16#include <netlink/genl/genl.h> 17#include <netlink/genl/family.h> 18#include <netlink/genl/ctrl.h> 19#include <netlink/msg.h> 20#include <netlink/attr.h> 21 22#include "nl80211.h" 23#include "iw.h" 24#include "version.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 50static int 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); 98__COMMAND(NULL, NULL, NULL, 1, 0, 0, CIB_NONE, NULL); 99 100static int cmd_size; 101 102static void usage(const char *argv0) 103{ 104 struct cmd *cmd; 105 106 fprintf(stderr, "Usage:\t%s [options] command\n", argv0); 107 fprintf(stderr, "Options:\n"); 108 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n"); 109 fprintf(stderr, "\t--version\tshow version\n"); 110 fprintf(stderr, "Commands:\n"); 111 fprintf(stderr, "\thelp\n"); 112 fprintf(stderr, "\tevent\n"); 113 for (cmd = &__start___cmd; cmd < &__stop___cmd; 114 cmd = (struct cmd *)((char *)cmd + cmd_size)) { 115 if (!cmd->handler || cmd->hidden) 116 continue; 117 switch (cmd->idby) { 118 case CIB_NONE: 119 fprintf(stderr, "\t"); 120 /* fall through */ 121 case CIB_PHY: 122 if (cmd->idby == CIB_PHY) 123 fprintf(stderr, "\tphy <phyname> "); 124 /* fall through */ 125 case CIB_NETDEV: 126 if (cmd->idby == CIB_NETDEV) 127 fprintf(stderr, "\tdev <devname> "); 128 if (cmd->section) 129 fprintf(stderr, "%s ", cmd->section); 130 fprintf(stderr, "%s", cmd->name); 131 if (cmd->args) 132 fprintf(stderr, " %s", cmd->args); 133 fprintf(stderr, "\n"); 134 break; 135 } 136 } 137} 138 139static void version(void) 140{ 141 printf("iw version " IW_VERSION "\n"); 142} 143 144static int phy_lookup(char *name) 145{ 146 char buf[200]; 147 int fd, pos; 148 149 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 150 151 fd = open(buf, O_RDONLY); 152 pos = read(fd, buf, sizeof(buf) - 1); 153 if (pos < 0) 154 return -1; 155 buf[pos] = '\0'; 156 return atoi(buf); 157} 158 159static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 160 void *arg) 161{ 162 int *ret = arg; 163 *ret = err->error; 164 return NL_STOP; 165} 166 167static int finish_handler(struct nl_msg *msg, void *arg) 168{ 169 int *ret = arg; 170 *ret = 0; 171 return NL_SKIP; 172} 173 174static int ack_handler(struct nl_msg *msg, void *arg) 175{ 176 int *ret = arg; 177 *ret = 0; 178 return NL_STOP; 179} 180 181static int handle_cmd(struct nl80211_state *state, 182 enum command_identify_by idby, 183 int argc, char **argv) 184{ 185 struct cmd *cmd; 186 struct nl_cb *cb = NULL; 187 struct nl_msg *msg; 188 int devidx = 0; 189 int err; 190 const char *command, *section; 191 192 if (argc <= 1 && idby != CIB_NONE) 193 return 1; 194 195 switch (idby) { 196 case CIB_PHY: 197 devidx = phy_lookup(*argv); 198 argc--; 199 argv++; 200 break; 201 case CIB_NETDEV: 202 devidx = if_nametoindex(*argv); 203 argc--; 204 argv++; 205 break; 206 default: 207 break; 208 } 209 210 section = command = *argv; 211 argc--; 212 argv++; 213 214 for (cmd = &__start___cmd; cmd < &__stop___cmd; 215 cmd = (struct cmd *)((char *)cmd + cmd_size)) { 216 if (!cmd->handler) 217 continue; 218 if (cmd->idby != idby) 219 continue; 220 if (cmd->section) { 221 if (strcmp(cmd->section, section)) 222 continue; 223 /* this is a bit icky ... */ 224 if (command == section) { 225 if (argc <= 0) 226 return 1; 227 command = *argv; 228 argc--; 229 argv++; 230 } 231 } else if (section != command) 232 continue; 233 if (strcmp(cmd->name, command)) 234 continue; 235 if (argc && !cmd->args) 236 continue; 237 break; 238 } 239 240 if (cmd >= &__stop___cmd) 241 return 1; 242 243 msg = nlmsg_alloc(); 244 if (!msg) { 245 fprintf(stderr, "failed to allocate netlink message\n"); 246 return 2; 247 } 248 249 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 250 if (!cb) { 251 fprintf(stderr, "failed to allocate netlink callbacks\n"); 252 err = 2; 253 goto out_free_msg; 254 } 255 256 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 257 cmd->nl_msg_flags, cmd->cmd, 0); 258 259 switch (idby) { 260 case CIB_PHY: 261 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); 262 break; 263 case CIB_NETDEV: 264 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); 265 break; 266 default: 267 break; 268 } 269 270 err = cmd->handler(cb, msg, argc, argv); 271 if (err) 272 goto out; 273 274 err = nl_send_auto_complete(state->nl_sock, msg); 275 if (err < 0) 276 goto out; 277 278 err = 1; 279 280 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 281 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); 282 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 283 284 while (err > 0) 285 nl_recvmsgs(state->nl_sock, cb); 286 out: 287 nl_cb_put(cb); 288 out_free_msg: 289 nlmsg_free(msg); 290 return err; 291 nla_put_failure: 292 fprintf(stderr, "building message failed\n"); 293 return 2; 294} 295 296static int no_seq_check(struct nl_msg *msg, void *arg) 297{ 298 return NL_OK; 299} 300 301static int print_event(struct nl_msg *msg, void *arg) 302{ 303 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 304 struct nlattr *tb[NL80211_ATTR_MAX + 1]; 305 char ifname[100]; 306 __u8 reg_type; 307 308 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 309 genlmsg_attrlen(gnlh, 0), NULL); 310 311 switch (gnlh->cmd) { 312 case NL80211_CMD_NEW_WIPHY: 313 printf("wiphy rename: phy #%d to %s\n", 314 nla_get_u32(tb[NL80211_ATTR_WIPHY]), 315 nla_get_string(tb[NL80211_ATTR_WIPHY_NAME])); 316 break; 317 case NL80211_CMD_NEW_SCAN_RESULTS: 318 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); 319 printf("scan finished on %s (phy #%d)\n", 320 ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); 321 break; 322 case NL80211_CMD_SCAN_ABORTED: 323 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); 324 printf("scan aborted on %s (phy #%d)\n", 325 ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); 326 break; 327 case NL80211_CMD_REG_CHANGE: 328 329 printf("regulatory domain change: "); 330 331 reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); 332 333 switch (reg_type) { 334 case NL80211_REGDOM_TYPE_COUNTRY: 335 printf("set to %s by %s request", 336 nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), 337 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 338 if (tb[NL80211_ATTR_WIPHY]) 339 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 340 break; 341 case NL80211_REGDOM_TYPE_WORLD: 342 printf("set to world roaming by %s request", 343 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 344 break; 345 case NL80211_REGDOM_TYPE_CUSTOM_WORLD: 346 printf("custom world roaming rules in place on phy%d by %s request", 347 nla_get_u32(tb[NL80211_ATTR_WIPHY]), 348 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 349 break; 350 case NL80211_REGDOM_TYPE_INTERSECTION: 351 printf("intersection used due to a request made by %s", 352 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 353 if (tb[NL80211_ATTR_WIPHY]) 354 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 355 break; 356 default: 357 printf("unknown source (upgrade this utility)"); 358 break; 359 } 360 361 printf("\n"); 362 break; 363 default: 364 printf("unknown event: %d\n", gnlh->cmd); 365 break; 366 } 367 368 return NL_SKIP; 369} 370 371static int listen_events(struct nl80211_state *state, 372 int argc, char **argv) 373{ 374 int mcid, ret; 375 struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 376 377 if (!cb) { 378 fprintf(stderr, "failed to allocate netlink callbacks\n"); 379 return -ENOMEM; 380 } 381 382 /* Configuration multicast group */ 383 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config"); 384 if (mcid < 0) 385 return mcid; 386 387 ret = nl_socket_add_membership(state->nl_sock, mcid); 388 if (ret) 389 return ret; 390 391 /* Scan multicast group */ 392 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan"); 393 if (mcid >= 0) { 394 ret = nl_socket_add_membership(state->nl_sock, mcid); 395 if (ret) 396 return ret; 397 } 398 399 /* Regulatory multicast group */ 400 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory"); 401 if (mcid >= 0) { 402 ret = nl_socket_add_membership(state->nl_sock, mcid); 403 if (ret) 404 return ret; 405 } 406 407 /* no sequence checking for multicast messages */ 408 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); 409 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL); 410 411 while (1) 412 nl_recvmsgs(state->nl_sock, cb); 413 414 nl_cb_put(cb); 415 416 return 0; 417} 418 419int main(int argc, char **argv) 420{ 421 struct nl80211_state nlstate; 422 int err; 423 const char *argv0; 424 425 /* calculate command size including padding */ 426 cmd_size = abs((long)&__cmd_NULL_1_CIB_NONE_0 427 - (long)&__cmd_NULL_0_CIB_NONE_0); 428 /* strip off self */ 429 argc--; 430 argv0 = *argv++; 431 432 if (argc > 0 && strcmp(*argv, "--debug") == 0) { 433 debug = 1; 434 argc--; 435 argv++; 436 } 437 438 if (argc > 0 && strcmp(*argv, "--version") == 0) { 439 version(); 440 return 0; 441 } 442 443 if (argc == 0 || strcmp(*argv, "help") == 0) { 444 usage(argv0); 445 return 0; 446 } 447 448 err = nl80211_init(&nlstate); 449 if (err) 450 return 1; 451 452 if (strcmp(*argv, "event") == 0) { 453 err = listen_events(&nlstate, argc, argv); 454 } else if (strcmp(*argv, "dev") == 0) { 455 argc--; 456 argv++; 457 err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv); 458 } else if (strcmp(*argv, "phy") == 0) { 459 argc--; 460 argv++; 461 err = handle_cmd(&nlstate, CIB_PHY, argc, argv); 462 } else 463 err = handle_cmd(&nlstate, CIB_NONE, argc, argv); 464 465 if (err == 1) 466 usage(argv0); 467 if (err < 0) 468 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); 469 470 nl80211_cleanup(&nlstate); 471 472 return err; 473} 474