1 #include <stdbool.h> 2 #include <errno.h> 3 #include <net/if.h> 4 #include <strings.h> 5 #include <sys/param.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 9 #include <netlink/genl/genl.h> 10 #include <netlink/genl/family.h> 11 #include <netlink/genl/ctrl.h> 12 #include <netlink/msg.h> 13 #include <netlink/attr.h> 14 15 #include "nl80211.h" 16 #include "iw.h" 17 18 static int handle_name(struct nl80211_state *state, 19 struct nl_cb *cb, 20 struct nl_msg *msg, 21 int argc, char **argv, 22 enum id_input id) 23 { 24 if (argc != 1) 25 return 1; 26 27 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv); 28 29 return 0; 30 nla_put_failure: 31 return -ENOBUFS; 32 } 33 COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name, 34 "Rename this wireless device."); 35 36 static int handle_freqs(struct nl_msg *msg, int argc, char **argv) 37 { 38 static const struct { 39 const char *name; 40 unsigned int val; 41 } bwmap[] = { 42 { .name = "20", .val = NL80211_CHAN_WIDTH_20, }, 43 { .name = "40", .val = NL80211_CHAN_WIDTH_40, }, 44 { .name = "80", .val = NL80211_CHAN_WIDTH_80, }, 45 { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, }, 46 { .name = "160", .val = NL80211_CHAN_WIDTH_160, }, 47 }; 48 uint32_t freq; 49 int i, bwval = NL80211_CHAN_WIDTH_20_NOHT; 50 char *end; 51 52 if (argc < 1) 53 return 1; 54 55 for (i = 0; i < ARRAY_SIZE(bwmap); i++) { 56 if (strcasecmp(bwmap[i].name, argv[0]) == 0) { 57 bwval = bwmap[i].val; 58 break; 59 } 60 } 61 62 if (bwval == NL80211_CHAN_WIDTH_20_NOHT) 63 return 1; 64 65 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval); 66 67 if (argc == 1) 68 return 0; 69 70 /* center freq 1 */ 71 if (!*argv[1]) 72 return 1; 73 freq = strtoul(argv[1], &end, 10); 74 if (*end) 75 return 1; 76 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq); 77 78 if (argc == 2) 79 return 0; 80 81 /* center freq 2 */ 82 if (!*argv[2]) 83 return 1; 84 freq = strtoul(argv[2], &end, 10); 85 if (*end) 86 return 1; 87 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq); 88 89 return 0; 90 nla_put_failure: 91 return -ENOBUFS; 92 } 93 94 static int handle_freqchan(struct nl_msg *msg, bool chan, 95 int argc, char **argv) 96 { 97 char *end; 98 static const struct { 99 const char *name; 100 unsigned int val; 101 } htmap[] = { 102 { .name = "HT20", .val = NL80211_CHAN_HT20, }, 103 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, }, 104 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, }, 105 }; 106 unsigned int htval = NL80211_CHAN_NO_HT; 107 unsigned int freq; 108 int i; 109 110 if (!argc || argc > 4) 111 return 1; 112 113 if (!*argv[0]) 114 return 1; 115 freq = strtoul(argv[0], &end, 10); 116 if (*end) 117 return 1; 118 119 if (chan) { 120 enum nl80211_band band; 121 band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; 122 freq = ieee80211_channel_to_frequency(freq, band); 123 } 124 125 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); 126 127 if (argc > 2) { 128 return handle_freqs(msg, argc - 1, argv + 1); 129 } else if (argc == 2) { 130 for (i = 0; i < ARRAY_SIZE(htmap); i++) { 131 if (strcasecmp(htmap[i].name, argv[1]) == 0) { 132 htval = htmap[i].val; 133 break; 134 } 135 } 136 if (htval == NL80211_CHAN_NO_HT) 137 return handle_freqs(msg, argc - 1, argv + 1); 138 } 139 140 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval); 141 142 return 0; 143 nla_put_failure: 144 return -ENOBUFS; 145 } 146 147 static int handle_freq(struct nl80211_state *state, 148 struct nl_cb *cb, struct nl_msg *msg, 149 int argc, char **argv, 150 enum id_input id) 151 { 152 return handle_freqchan(msg, false, argc, argv); 153 } 154 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]", 155 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq, 156 "Set frequency/channel the hardware is using, including HT\n" 157 "configuration."); 158 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n" 159 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]", 160 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL); 161 162 static int handle_chan(struct nl80211_state *state, 163 struct nl_cb *cb, struct nl_msg *msg, 164 int argc, char **argv, 165 enum id_input id) 166 { 167 return handle_freqchan(msg, true, argc, argv); 168 } 169 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]", 170 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL); 171 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]", 172 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL); 173 174 static int handle_fragmentation(struct nl80211_state *state, 175 struct nl_cb *cb, struct nl_msg *msg, 176 int argc, char **argv, 177 enum id_input id) 178 { 179 unsigned int frag; 180 181 if (argc != 1) 182 return 1; 183 184 if (strcmp("off", argv[0]) == 0) 185 frag = -1; 186 else { 187 char *end; 188 189 if (!*argv[0]) 190 return 1; 191 frag = strtoul(argv[0], &end, 10); 192 if (*end != '\0') 193 return 1; 194 } 195 196 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag); 197 198 return 0; 199 nla_put_failure: 200 return -ENOBUFS; 201 } 202 COMMAND(set, frag, "<fragmentation threshold|off>", 203 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation, 204 "Set fragmentation threshold."); 205 206 static int handle_rts(struct nl80211_state *state, 207 struct nl_cb *cb, struct nl_msg *msg, 208 int argc, char **argv, 209 enum id_input id) 210 { 211 unsigned int rts; 212 213 if (argc != 1) 214 return 1; 215 216 if (strcmp("off", argv[0]) == 0) 217 rts = -1; 218 else { 219 char *end; 220 221 if (!*argv[0]) 222 return 1; 223 rts = strtoul(argv[0], &end, 10); 224 if (*end != '\0') 225 return 1; 226 } 227 228 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts); 229 230 return 0; 231 nla_put_failure: 232 return -ENOBUFS; 233 } 234 COMMAND(set, rts, "<rts threshold|off>", 235 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts, 236 "Set rts threshold."); 237 238 static int handle_retry(struct nl80211_state *state, 239 struct nl_cb *cb, struct nl_msg *msg, 240 int argc, char **argv, enum id_input id) 241 { 242 unsigned int retry_short = 0, retry_long = 0; 243 bool have_retry_s = false, have_retry_l = false; 244 int i; 245 enum { 246 S_NONE, 247 S_SHORT, 248 S_LONG, 249 } parser_state = S_NONE; 250 251 if (!argc || (argc != 2 && argc != 4)) 252 return 1; 253 254 for (i = 0; i < argc; i++) { 255 char *end; 256 unsigned int tmpul; 257 258 if (strcmp(argv[i], "short") == 0) { 259 if (have_retry_s) 260 return 1; 261 parser_state = S_SHORT; 262 have_retry_s = true; 263 } else if (strcmp(argv[i], "long") == 0) { 264 if (have_retry_l) 265 return 1; 266 parser_state = S_LONG; 267 have_retry_l = true; 268 } else { 269 tmpul = strtoul(argv[i], &end, 10); 270 if (*end != '\0') 271 return 1; 272 if (!tmpul || tmpul > 255) 273 return -EINVAL; 274 switch (parser_state) { 275 case S_SHORT: 276 retry_short = tmpul; 277 break; 278 case S_LONG: 279 retry_long = tmpul; 280 break; 281 default: 282 return 1; 283 } 284 } 285 } 286 287 if (!have_retry_s && !have_retry_l) 288 return 1; 289 if (have_retry_s) 290 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short); 291 if (have_retry_l) 292 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long); 293 294 return 0; 295 nla_put_failure: 296 return -ENOBUFS; 297 } 298 COMMAND(set, retry, "[short <limit>] [long <limit>]", 299 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry, 300 "Set retry limit."); 301 302 #ifndef NETNS_RUN_DIR 303 #define NETNS_RUN_DIR "/var/run/netns" 304 #endif 305 int netns_get_fd(const char *name) 306 { 307 char pathbuf[MAXPATHLEN]; 308 const char *path, *ptr; 309 310 path = name; 311 ptr = strchr(name, '/'); 312 if (!ptr) { 313 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", 314 NETNS_RUN_DIR, name ); 315 path = pathbuf; 316 } 317 return open(path, O_RDONLY); 318 } 319 320 static int handle_netns(struct nl80211_state *state, 321 struct nl_cb *cb, 322 struct nl_msg *msg, 323 int argc, char **argv, 324 enum id_input id) 325 { 326 char *end; 327 int fd; 328 329 if (argc < 1 || !*argv[0]) 330 return 1; 331 332 if (argc == 1) { 333 NLA_PUT_U32(msg, NL80211_ATTR_PID, 334 strtoul(argv[0], &end, 10)); 335 if (*end != '\0') { 336 printf("Invalid parameter: pid(%s)\n", argv[0]); 337 return 1; 338 } 339 return 0; 340 } 341 342 if (argc != 2 || strcmp(argv[0], "name")) 343 return 1; 344 345 if ((fd = netns_get_fd(argv[1])) >= 0) { 346 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd); 347 return 0; 348 } else { 349 printf("Invalid parameter: nsname(%s)\n", argv[0]); 350 } 351 352 return 1; 353 354 nla_put_failure: 355 return -ENOBUFS; 356 } 357 COMMAND(set, netns, "{ <pid> | name <nsname> }", 358 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns, 359 "Put this wireless device into a different network namespace:\n" 360 " <pid> - change network namespace by process id\n" 361 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n" 362 " or by absolute path (man ip-netns)\n"); 363 364 static int handle_coverage(struct nl80211_state *state, 365 struct nl_cb *cb, 366 struct nl_msg *msg, 367 int argc, char **argv, 368 enum id_input id) 369 { 370 char *end; 371 unsigned int coverage; 372 373 if (argc != 1) 374 return 1; 375 376 if (!*argv[0]) 377 return 1; 378 coverage = strtoul(argv[0], &end, 10); 379 if (coverage > 255) 380 return 1; 381 382 if (*end) 383 return 1; 384 385 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage); 386 387 return 0; 388 nla_put_failure: 389 return -ENOBUFS; 390 } 391 COMMAND(set, coverage, "<coverage class>", 392 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage, 393 "Set coverage class (1 for every 3 usec of air propagation time).\n" 394 "Valid values: 0 - 255."); 395 396 static int handle_distance(struct nl80211_state *state, 397 struct nl_cb *cb, 398 struct nl_msg *msg, 399 int argc, char **argv, 400 enum id_input id) 401 { 402 if (argc != 1) 403 return 1; 404 405 if (!*argv[0]) 406 return 1; 407 408 if (strcmp("auto", argv[0]) == 0) { 409 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK); 410 } else { 411 char *end; 412 unsigned int distance, coverage; 413 414 distance = strtoul(argv[0], &end, 10); 415 416 if (*end) 417 return 1; 418 419 /* 420 * Divide double the distance by the speed of light 421 * in m/usec (300) to get round-trip time in microseconds 422 * and then divide the result by three to get coverage class 423 * as specified in IEEE 802.11-2007 table 7-27. 424 * Values are rounded upwards. 425 */ 426 coverage = (distance + 449) / 450; 427 if (coverage > 255) 428 return 1; 429 430 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage); 431 } 432 433 return 0; 434 nla_put_failure: 435 return -ENOBUFS; 436 } 437 COMMAND(set, distance, "<auto|distance>", 438 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance, 439 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n" 440 "coverage class for given link distance in meters.\n" 441 "To disable dynack set valid value for coverage class.\n" 442 "Valid values: 0 - 114750"); 443 444 static int handle_txpower(struct nl80211_state *state, 445 struct nl_cb *cb, 446 struct nl_msg *msg, 447 int argc, char **argv, 448 enum id_input id) 449 { 450 enum nl80211_tx_power_setting type; 451 int mbm; 452 453 /* get the required args */ 454 if (argc != 1 && argc != 2) 455 return 1; 456 457 if (!strcmp(argv[0], "auto")) 458 type = NL80211_TX_POWER_AUTOMATIC; 459 else if (!strcmp(argv[0], "fixed")) 460 type = NL80211_TX_POWER_FIXED; 461 else if (!strcmp(argv[0], "limit")) 462 type = NL80211_TX_POWER_LIMITED; 463 else { 464 printf("Invalid parameter: %s\n", argv[0]); 465 return 2; 466 } 467 468 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type); 469 470 if (type != NL80211_TX_POWER_AUTOMATIC) { 471 char *endptr; 472 if (argc != 2) { 473 printf("Missing TX power level argument.\n"); 474 return 2; 475 } 476 477 mbm = strtol(argv[1], &endptr, 10); 478 if (*endptr) 479 return 2; 480 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm); 481 } else if (argc != 1) 482 return 1; 483 484 return 0; 485 486 nla_put_failure: 487 return -ENOBUFS; 488 } 489 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]", 490 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower, 491 "Specify transmit power level and setting type."); 492 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]", 493 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower, 494 "Specify transmit power level and setting type."); 495 496 static int handle_antenna(struct nl80211_state *state, 497 struct nl_cb *cb, 498 struct nl_msg *msg, 499 int argc, char **argv, 500 enum id_input id) 501 { 502 char *end; 503 uint32_t tx_ant = 0, rx_ant = 0; 504 505 if (argc == 1 && strcmp(argv[0], "all") == 0) { 506 tx_ant = 0xffffffff; 507 rx_ant = 0xffffffff; 508 } else if (argc == 1) { 509 tx_ant = rx_ant = strtoul(argv[0], &end, 0); 510 if (*end) 511 return 1; 512 } 513 else if (argc == 2) { 514 tx_ant = strtoul(argv[0], &end, 0); 515 if (*end) 516 return 1; 517 rx_ant = strtoul(argv[1], &end, 0); 518 if (*end) 519 return 1; 520 } else 521 return 1; 522 523 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant); 524 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant); 525 526 return 0; 527 528 nla_put_failure: 529 return -ENOBUFS; 530 } 531 COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>", 532 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna, 533 "Set a bitmap of allowed antennas to use for TX and RX.\n" 534 "The driver may reject antenna configurations it cannot support."); 535