1 /* 2 * This is a stripped down version of the iw tool designed for 3 * programmatically checking driver/hw capabilities. 4 * 5 * Copyright 2007, 2008 Johannes Berg <johannes (at) sipsolutions.net> 6 */ 7 8 #include <errno.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <net/if.h> 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 #include <unistd.h> 16 #include <stdbool.h> 17 18 #include <netlink/netlink.h> 19 #include <netlink/genl/genl.h> 20 #include <netlink/genl/family.h> 21 #include <netlink/genl/ctrl.h> 22 #include <netlink/msg.h> 23 #include <netlink/attr.h> 24 25 #include "nl80211.h" 26 27 #ifndef CONFIG_LIBNL20 28 /* libnl 2.0 compatibility code */ 29 30 # define nl_sock nl_handle 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, struct nl_cache **cache) 43 { 44 struct nl_cache *tmp = genl_ctrl_alloc_cache(h); 45 if (!tmp) 46 return -ENOMEM; 47 *cache = tmp; 48 return 0; 49 } 50 #define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache 51 #endif /* CONFIG_LIBNL20 */ 52 53 struct nl80211_state { 54 struct nl_sock *nl_sock; 55 struct nl_cache *nl_cache; 56 struct genl_family *nl80211; 57 }; 58 59 static int nl80211_init(struct nl80211_state *state) 60 { 61 int err; 62 63 state->nl_sock = nl_socket_alloc(); 64 if (!state->nl_sock) { 65 fprintf(stderr, "Failed to allocate netlink socket.\n"); 66 return -ENOMEM; 67 } 68 69 if (genl_connect(state->nl_sock)) { 70 fprintf(stderr, "Failed to connect to generic netlink.\n"); 71 err = -ENOLINK; 72 goto out_handle_destroy; 73 } 74 75 if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) { 76 fprintf(stderr, "Failed to allocate generic netlink cache.\n"); 77 err = -ENOMEM; 78 goto out_handle_destroy; 79 } 80 81 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); 82 if (!state->nl80211) { 83 fprintf(stderr, "nl80211 not found.\n"); 84 err = -ENOENT; 85 goto out_cache_free; 86 } 87 88 return 0; 89 90 out_cache_free: 91 nl_cache_free(state->nl_cache); 92 out_handle_destroy: 93 nl_socket_free(state->nl_sock); 94 return err; 95 } 96 97 static void nl80211_cleanup(struct nl80211_state *state) 98 { 99 genl_family_put(state->nl80211); 100 nl_cache_free(state->nl_cache); 101 nl_socket_free(state->nl_sock); 102 } 103 104 static const char *argv0; 105 106 static int phy_lookup(char *name) 107 { 108 char buf[200]; 109 int fd, pos; 110 111 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); 112 113 fd = open(buf, O_RDONLY); 114 if (fd < 0) 115 return -1; 116 pos = read(fd, buf, sizeof(buf) - 1); 117 if (pos < 0) 118 return -1; 119 buf[pos] = '\0'; 120 return atoi(buf); 121 } 122 123 enum { 124 CHECK_IS_HT20 = 0x00000001, 125 CHECK_IS_HT40 = 0x00000002, 126 CHECK_IS_PSMP = 0x00000004, 127 CHECK_IS_AMPDU = 0x00000008, 128 CHECK_IS_AMSDU = 0x00000010, 129 CHECK_IS_SMPS = 0x00000020, 130 CHECK_IS_STA = 0x00000040, 131 CHECK_IS_AP = 0x00000080, 132 CHECK_IS_IBSS = 0x00000100, 133 CHECK_IS_MBSS = 0x00000200, 134 CHECK_IS_MONITOR = 0x00000400, 135 CHECK_BANDS = 0x00000800, 136 CHECK_FREQS = 0x00001000, 137 CHECK_RATES = 0x00002000, 138 CHECK_MCS = 0x00004000, 139 CHECK_AMPDU_DENS = 0x00008000, 140 CHECK_AMPDU_FACT = 0x00010000, 141 CHECK_AMSDU_LEN = 0x00020000, 142 CHECK_IS_LPDC = 0x00040000, 143 CHECK_IS_GREENFIELD = 0x00080000, 144 CHECK_IS_SGI20 = 0x00100000, 145 CHECK_IS_SGI40 = 0x00200000, 146 CHECK_IS_TXSTBC = 0x00400000, 147 CHECK_RXSTBC = 0x00800000, 148 CHECK_IS_DELBA = 0x01000000, 149 /* NB: must be in upper 16-bits to avoid HT caps */ 150 CHECK_IS_24GHZ = 0x02000000, 151 CHECK_IS_5GHZ = 0x04000000, 152 CHECK_IS_11B = 0x08000000, 153 CHECK_IS_11G = 0x10000000, 154 CHECK_IS_11A = 0x20000000, 155 CHECK_IS_11N = 0x40000000, 156 }; 157 158 struct check { 159 const char *name; 160 int namelen; 161 int bits; 162 }; 163 static const struct check checks[] = { 164 { "24ghz", 5, CHECK_IS_24GHZ }, 165 { "5ghz", 4, CHECK_IS_5GHZ }, 166 { "11b", 3, CHECK_IS_11B }, 167 { "11g", 3, CHECK_IS_11G }, 168 { "11a", 3, CHECK_IS_11A }, 169 { "11n", 3, CHECK_IS_11N }, 170 { "ht20", 4, CHECK_IS_HT20 }, 171 { "ht40", 4, CHECK_IS_HT40 }, 172 { "psmp", 5, CHECK_IS_PSMP }, 173 { "ampdu", 5, CHECK_IS_AMPDU }, 174 { "amsdu", 5, CHECK_IS_AMSDU }, 175 { "smps", 4, CHECK_IS_SMPS }, 176 { "sta", 3, CHECK_IS_STA }, 177 { "ap", 2, CHECK_IS_AP }, 178 { "ibss", 4, CHECK_IS_IBSS }, 179 { "mbss", 4, CHECK_IS_MBSS }, 180 { "mon", 3, CHECK_IS_MONITOR }, 181 { "bands", 4, CHECK_BANDS }, 182 { "freqs", 4, CHECK_FREQS }, 183 { "rates", 4, CHECK_RATES }, 184 { "mcs", 3, CHECK_MCS }, 185 { "ampdu_dens", 10, CHECK_AMPDU_DENS }, 186 { "ampdu_fact", 10, CHECK_AMPDU_FACT }, 187 { "amsdu_len", 9, CHECK_AMSDU_LEN }, 188 { "lpdc", 4, CHECK_IS_LPDC }, 189 { "green", 5, CHECK_IS_GREENFIELD }, 190 { "sgi20", 5, CHECK_IS_SGI20 }, 191 { "sgi40", 5, CHECK_IS_SGI40 }, 192 { "txstbc", 6, CHECK_IS_TXSTBC }, 193 { "rxstbc", 6, CHECK_RXSTBC }, 194 { "delba", 5, CHECK_IS_DELBA }, 195 { "all", 3, -1 }, 196 { NULL } 197 }; 198 199 static const struct check *find_check_byname(const char *name) 200 { 201 const struct check *p; 202 203 for (p = checks; p->name != NULL; p++) 204 if (strncasecmp(p->name, name, p->namelen) == 0) 205 return p; 206 return NULL; 207 } 208 209 #if 0 210 static const struct check *find_check_bybits(int bits) 211 { 212 const struct check *p; 213 214 for (p = checks; p->name != NULL; p++) 215 if (p->bits == bits) 216 return p; 217 return NULL; 218 } 219 #endif 220 221 static int check_iftype(struct nlattr *tb_msg[], int nl_type) 222 { 223 struct nlattr *nl_mode; 224 int rem_mode; 225 226 if (!tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) 227 return 0; 228 229 nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) 230 if (nl_mode->nla_type == nl_type) 231 return 1; 232 return 0; 233 } 234 235 static unsigned int get_max_mcs(unsigned char *mcs) 236 { 237 unsigned int mcs_bit, max; 238 239 max = 0; 240 for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) { 241 unsigned int mcs_octet = mcs_bit/8; 242 unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8; 243 bool mcs_rate_idx_set; 244 245 mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT); 246 247 if (!mcs_rate_idx_set) 248 continue; 249 250 if (mcs_bit > max) 251 max = mcs_bit; 252 } 253 return max; 254 } 255 256 static void pbool(const char *tag, int v) 257 { 258 printf("%s: %s\n", tag, v ? "true" : "false"); 259 } 260 261 static void pint(const char *tag, int v) 262 { 263 printf("%s: %d\n", tag, v); 264 } 265 266 static void prate(const char *tag, int v) 267 { 268 printf("%s: %2.1f\n", tag, 0.1*v); 269 } 270 271 static int check_phy_handler(struct nl_msg *msg, void *arg) 272 { 273 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; 274 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 275 uintptr_t checks = (uintptr_t) arg; 276 277 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; 278 279 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; 280 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { 281 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, 282 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, 283 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, 284 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, 285 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, 286 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, 287 }; 288 289 struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; 290 static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { 291 [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, 292 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, 293 }; 294 295 struct nlattr *nl_band; 296 struct nlattr *nl_freq; 297 struct nlattr *nl_rate; 298 int rem_band, rem_freq, rem_rate, phy_caps; 299 int amsdu_len, ampdu_fact, ampdu_dens, max_mcs, max_rate; 300 301 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 302 genlmsg_attrlen(gnlh, 0), NULL); 303 304 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) 305 return NL_SKIP; 306 307 phy_caps = 0; 308 amsdu_len = 0; 309 ampdu_fact = 0; 310 ampdu_dens = 0; 311 max_mcs = 0; 312 max_rate = 0; 313 /* NB: merge each band's findings; this stuff is silly */ 314 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { 315 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), 316 nla_len(nl_band), NULL); 317 318 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { 319 unsigned short caps = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); 320 int len; 321 322 /* XXX not quite right but close enough */ 323 phy_caps |= CHECK_IS_11N | caps; 324 len = 0xeff + ((caps & 0x0800) << 1); 325 if (len > amsdu_len) 326 amsdu_len = len; 327 } 328 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { 329 unsigned char factor = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]); 330 int fact = (1<<(13+factor))-1; 331 if (fact > ampdu_fact) 332 ampdu_fact = fact; 333 } 334 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { 335 unsigned char dens = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]); 336 if (dens > ampdu_dens) 337 ampdu_dens = dens; 338 } 339 if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && 340 nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]) == 16) { 341 /* As defined in 7.3.2.57.4 Supported MCS Set field */ 342 unsigned char *mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); 343 int max = get_max_mcs(&mcs[0]); 344 if (max > max_mcs) 345 max_mcs = max; 346 } 347 348 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { 349 uint32_t freq; 350 351 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, 352 nla_data(nl_freq), nla_len(nl_freq), 353 freq_policy); 354 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) 355 continue; 356 #if 0 357 /* NB: we care about device caps, not regulatory */ 358 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) 359 continue; 360 #endif 361 freq = nla_get_u32( 362 tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); 363 if (checks & CHECK_FREQS) 364 pint("freq", freq); 365 366 /* NB: approximate band boundaries, we get no help */ 367 if (2000 <= freq && freq <= 3000) 368 phy_caps |= CHECK_IS_24GHZ; 369 else if (4000 <= freq && freq <= 6000) 370 phy_caps |= CHECK_IS_5GHZ; 371 } 372 373 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { 374 int rate; 375 376 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), 377 nla_len(nl_rate), rate_policy); 378 if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) 379 continue; 380 rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); 381 if (rate > max_rate) 382 max_rate = rate; 383 } 384 } 385 #if 0 386 /* NB: 11n =>'s legacy support */ 387 if (phy_caps & CHECK_IS_11N) { 388 if (phy_caps & CHECK_IS_24GHZ) 389 phy_caps |= CHECK_IS_11B | CHECK_IS_11G; 390 if (phy_caps & CHECK_IS_5GHZ) 391 phy_caps |= CHECK_IS_11A; 392 } 393 #else 394 /* XXX no way to figure this out; just force 'em */ 395 if (phy_caps & CHECK_IS_24GHZ) 396 phy_caps |= CHECK_IS_11B | CHECK_IS_11G; 397 if (phy_caps & CHECK_IS_5GHZ) 398 phy_caps |= CHECK_IS_11A; 399 #endif 400 401 #define PBOOL(c, b, name) if (checks & (c)) pbool(name, phy_caps & (b)) 402 PBOOL(CHECK_IS_24GHZ, CHECK_IS_24GHZ, "24ghz"); 403 PBOOL(CHECK_IS_5GHZ, CHECK_IS_5GHZ, "5ghz"); 404 PBOOL(CHECK_IS_11B, CHECK_IS_11B, "11b"); 405 PBOOL(CHECK_IS_11G, CHECK_IS_11G, "11g"); 406 PBOOL(CHECK_IS_11A, CHECK_IS_11A, "11a"); 407 PBOOL(CHECK_IS_11N, CHECK_IS_11N, "11n"); 408 PBOOL(CHECK_IS_LPDC, 0x1, "lpdc"); 409 PBOOL(CHECK_IS_HT20, CHECK_IS_11N, "ht20"); 410 PBOOL(CHECK_IS_HT40, 0x2, "ht40"); 411 if (checks & CHECK_IS_SMPS) 412 pbool("smps", ((phy_caps & 0x000c) >> 2) < 2); 413 PBOOL(CHECK_IS_GREENFIELD, 0x10, "green"); 414 PBOOL(CHECK_IS_SGI20, 0x20, "sgi20"); 415 PBOOL(CHECK_IS_SGI40, 0x40, "sgi40"); 416 PBOOL(CHECK_IS_TXSTBC, 0x40, "txstbc"); 417 PBOOL(CHECK_RXSTBC, 0x300, "rxstbc"); 418 PBOOL(CHECK_IS_DELBA, 0x400, "delba"); 419 #if 0 420 PBOOL(CHECK_IS_DSSCCK, 0x1000, "dsscck"); 421 #endif 422 PBOOL(CHECK_IS_PSMP, 0x2000, "psmp"); 423 #if 0 424 PBOOL(CHECK_IS_INTOL, 0x4000, "intol"); 425 #endif 426 #if 0 427 PBOOL(CHECK_IS_LSIGTXOP, 0x8000, "lsigtxop"); 428 #endif 429 #undef PBOOL 430 if (checks & CHECK_AMSDU_LEN) 431 pint("amsdu_len", amsdu_len); 432 if (checks & CHECK_AMPDU_FACT) 433 pint("ampdu_fact", ampdu_fact); 434 if (checks & CHECK_AMPDU_DENS) 435 pint("ampdu_dens", ampdu_dens); 436 if (checks & CHECK_RATES) 437 prate("rate", max_rate); 438 if (checks & CHECK_MCS) 439 pint("mcs", max_mcs); 440 441 if (checks & CHECK_IS_STA) 442 pbool("sta", check_iftype(tb_msg, NL80211_IFTYPE_STATION)); 443 if (checks & CHECK_IS_IBSS) 444 pbool("ibss", check_iftype(tb_msg, NL80211_IFTYPE_ADHOC)); 445 if (checks & CHECK_IS_AP) 446 pbool("ap", check_iftype(tb_msg, NL80211_IFTYPE_AP)); 447 if (checks & CHECK_IS_MBSS) 448 pbool("mbss", check_iftype(tb_msg, NL80211_IFTYPE_MESH_POINT)); 449 if (checks & CHECK_IS_MONITOR) 450 pbool("mon", check_iftype(tb_msg, NL80211_IFTYPE_MONITOR)); 451 452 return NL_SKIP; 453 } 454 455 static int check_phy_caps(struct nl80211_state *state, 456 struct nl_cb *cb, 457 struct nl_msg *msg, 458 int argc, char **argv) 459 { 460 int checks = 0; 461 for (; argc > 0; argc--, argv++) { 462 const struct check *p = find_check_byname(argv[0]); 463 if (p == NULL) { 464 fprintf(stderr, "invalid check %s\n", argv[0]); 465 return 3; /* XXX whatever? */ 466 } 467 checks |= p->bits; 468 } 469 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, check_phy_handler, 470 (void *)(uintptr_t) checks); 471 return 0; 472 } 473 474 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 475 void *arg) 476 { 477 int *ret = arg; 478 *ret = err->error; 479 return NL_STOP; 480 } 481 482 static int finish_handler(struct nl_msg *msg, void *arg) 483 { 484 int *ret = arg; 485 *ret = 0; 486 return NL_SKIP; 487 } 488 489 static int ack_handler(struct nl_msg *msg, void *arg) 490 { 491 int *ret = arg; 492 *ret = 0; 493 return NL_STOP; 494 } 495 496 static int __handle_cmd(struct nl80211_state *state, int argc, char **argv) 497 { 498 struct nl_cb *cb; 499 struct nl_msg *msg; 500 int devidx, err; 501 502 if (argc <= 1) 503 return 1; 504 505 devidx = phy_lookup(*argv); 506 if (devidx < 0) 507 return -errno; 508 argc--, argv++; 509 510 msg = nlmsg_alloc(); 511 if (!msg) { 512 fprintf(stderr, "failed to allocate netlink message\n"); 513 return 2; 514 } 515 516 cb = nl_cb_alloc(NL_CB_DEFAULT); 517 if (!cb) { 518 fprintf(stderr, "failed to allocate netlink callbacks\n"); 519 err = 2; 520 goto out_free_msg; 521 } 522 523 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 524 0, NL80211_CMD_GET_WIPHY, 0); 525 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); 526 527 err = check_phy_caps(state, cb, msg, argc, argv); 528 if (err) 529 goto out; 530 531 err = nl_send_auto_complete(state->nl_sock, msg); 532 if (err < 0) 533 goto out; 534 535 err = 1; 536 537 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 538 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); 539 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 540 541 while (err > 0) 542 nl_recvmsgs(state->nl_sock, cb); 543 out: 544 nl_cb_put(cb); 545 out_free_msg: 546 nlmsg_free(msg); 547 return err; 548 nla_put_failure: 549 fprintf(stderr, "building message failed\n"); 550 return 2; 551 } 552 553 int main(int argc, char **argv) 554 { 555 struct nl80211_state nlstate; 556 int err; 557 558 argc--; 559 argv0 = *argv++; 560 561 err = nl80211_init(&nlstate); 562 if (err == 0) { 563 if (argc > 1 && strncmp(*argv, "phy", 3) == 0) { 564 err = __handle_cmd(&nlstate, argc, argv); 565 if (err < 0) 566 fprintf(stderr, "command failed: %s (%d)\n", 567 strerror(-err), err); 568 else if (err) 569 fprintf(stderr, "command failed: err %d\n", err); 570 } else { 571 fprintf(stderr, "usage: %s phyX [args]\n", argv0); 572 err = 1; 573 } 574 nl80211_cleanup(&nlstate); 575 } 576 return err; 577 } 578