1 #include <net/if.h> 2 #include <errno.h> 3 #include <string.h> 4 #include <stdbool.h> 5 6 #include <netlink/genl/genl.h> 7 #include <netlink/genl/family.h> 8 #include <netlink/genl/ctrl.h> 9 #include <netlink/msg.h> 10 #include <netlink/attr.h> 11 12 #include "nl80211.h" 13 #include "iw.h" 14 15 #define VALID_FLAGS "none: no special flags\n"\ 16 "fcsfail: show frames with FCS errors\n"\ 17 "control: show control frames\n"\ 18 "otherbss: show frames from other BSSes\n"\ 19 "cook: use cooked mode\n"\ 20 "active: use active mode (ACK incoming unicast packets)" 21 22 SECTION(interface); 23 24 static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = { 25 "none", 26 "fcsfail", 27 "plcpfail", 28 "control", 29 "otherbss", 30 "cook", 31 "active", 32 }; 33 34 static int parse_mntr_flags(int *_argc, char ***_argv, 35 struct nl_msg *msg) 36 { 37 struct nl_msg *flags; 38 int err = -ENOBUFS; 39 enum nl80211_mntr_flags flag; 40 int argc = *_argc; 41 char **argv = *_argv; 42 43 flags = nlmsg_alloc(); 44 if (!flags) 45 return -ENOMEM; 46 47 while (argc) { 48 int ok = 0; 49 for (flag = __NL80211_MNTR_FLAG_INVALID; 50 flag <= NL80211_MNTR_FLAG_MAX; flag++) { 51 if (strcmp(*argv, mntr_flags[flag]) == 0) { 52 ok = 1; 53 /* 54 * This shouldn't be adding "flag" if that is 55 * zero, but due to a problem in the kernel's 56 * nl80211 code (using NLA_NESTED policy) it 57 * will reject an empty nested attribute but 58 * not one that contains an invalid attribute 59 */ 60 NLA_PUT_FLAG(flags, flag); 61 break; 62 } 63 } 64 if (!ok) { 65 err = -EINVAL; 66 goto out; 67 } 68 argc--; 69 argv++; 70 } 71 72 nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); 73 err = 0; 74 nla_put_failure: 75 out: 76 nlmsg_free(flags); 77 78 *_argc = argc; 79 *_argv = argv; 80 81 return err; 82 } 83 84 /* for help */ 85 #define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds." 86 87 /* return 0 if ok, internal error otherwise */ 88 static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type, 89 bool need_type) 90 { 91 char *tpstr; 92 93 if (*argc < 1 + !!need_type) 94 return 1; 95 96 if (need_type && strcmp((*argv)[0], "type")) 97 return 1; 98 99 tpstr = (*argv)[!!need_type]; 100 *argc -= 1 + !!need_type; 101 *argv += 1 + !!need_type; 102 103 if (strcmp(tpstr, "adhoc") == 0 || 104 strcmp(tpstr, "ibss") == 0) { 105 *type = NL80211_IFTYPE_ADHOC; 106 return 0; 107 } else if (strcmp(tpstr, "ocb") == 0) { 108 *type = NL80211_IFTYPE_OCB; 109 return 0; 110 } else if (strcmp(tpstr, "monitor") == 0) { 111 *type = NL80211_IFTYPE_MONITOR; 112 return 0; 113 } else if (strcmp(tpstr, "master") == 0 || 114 strcmp(tpstr, "ap") == 0) { 115 *type = NL80211_IFTYPE_UNSPECIFIED; 116 fprintf(stderr, "You need to run a management daemon, e.g. hostapd,\n"); 117 fprintf(stderr, "see http://wireless.kernel.org/en/users/Documentation/hostapd\n"); 118 fprintf(stderr, "for more information on how to do that.\n"); 119 return 2; 120 } else if (strcmp(tpstr, "__ap") == 0) { 121 *type = NL80211_IFTYPE_AP; 122 return 0; 123 } else if (strcmp(tpstr, "__ap_vlan") == 0) { 124 *type = NL80211_IFTYPE_AP_VLAN; 125 return 0; 126 } else if (strcmp(tpstr, "wds") == 0) { 127 *type = NL80211_IFTYPE_WDS; 128 return 0; 129 } else if (strcmp(tpstr, "managed") == 0 || 130 strcmp(tpstr, "mgd") == 0 || 131 strcmp(tpstr, "station") == 0) { 132 *type = NL80211_IFTYPE_STATION; 133 return 0; 134 } else if (strcmp(tpstr, "mp") == 0 || 135 strcmp(tpstr, "mesh") == 0) { 136 *type = NL80211_IFTYPE_MESH_POINT; 137 return 0; 138 } else if (strcmp(tpstr, "__p2pcl") == 0) { 139 *type = NL80211_IFTYPE_P2P_CLIENT; 140 return 0; 141 } else if (strcmp(tpstr, "__p2pdev") == 0) { 142 *type = NL80211_IFTYPE_P2P_DEVICE; 143 return 0; 144 } else if (strcmp(tpstr, "__p2pgo") == 0) { 145 *type = NL80211_IFTYPE_P2P_GO; 146 return 0; 147 } 148 149 fprintf(stderr, "invalid interface type %s\n", tpstr); 150 return 2; 151 } 152 153 static int parse_4addr_flag(const char *value, struct nl_msg *msg) 154 { 155 if (strcmp(value, "on") == 0) 156 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1); 157 else if (strcmp(value, "off") == 0) 158 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0); 159 else 160 return 1; 161 return 0; 162 163 nla_put_failure: 164 return 1; 165 } 166 167 static int handle_interface_add(struct nl80211_state *state, 168 struct nl_cb *cb, 169 struct nl_msg *msg, 170 int argc, char **argv, 171 enum id_input id) 172 { 173 char *name; 174 char *mesh_id = NULL; 175 enum nl80211_iftype type; 176 int tpset; 177 unsigned char mac_addr[ETH_ALEN]; 178 int found_mac = 0; 179 180 if (argc < 1) 181 return 1; 182 183 name = argv[0]; 184 argc--; 185 argv++; 186 187 tpset = get_if_type(&argc, &argv, &type, true); 188 if (tpset) 189 return tpset; 190 191 try_another: 192 if (argc) { 193 if (strcmp(argv[0], "mesh_id") == 0) { 194 argc--; 195 argv++; 196 197 if (!argc) 198 return 1; 199 mesh_id = argv[0]; 200 argc--; 201 argv++; 202 } else if (strcmp(argv[0], "addr") == 0) { 203 argc--; 204 argv++; 205 if (mac_addr_a2n(mac_addr, argv[0])) { 206 fprintf(stderr, "Invalid MAC address\n"); 207 return 2; 208 } 209 argc--; 210 argv++; 211 found_mac = 1; 212 goto try_another; 213 } else if (strcmp(argv[0], "4addr") == 0) { 214 argc--; 215 argv++; 216 if (parse_4addr_flag(argv[0], msg)) { 217 fprintf(stderr, "4addr error\n"); 218 return 2; 219 } 220 argc--; 221 argv++; 222 } else if (strcmp(argv[0], "flags") == 0) { 223 argc--; 224 argv++; 225 if (parse_mntr_flags(&argc, &argv, msg)) { 226 fprintf(stderr, "flags error\n"); 227 return 2; 228 } 229 } else { 230 return 1; 231 } 232 } 233 234 if (argc) 235 return 1; 236 237 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); 238 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); 239 if (mesh_id) 240 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); 241 if (found_mac) 242 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); 243 244 return 0; 245 nla_put_failure: 246 return -ENOBUFS; 247 } 248 COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]", 249 NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add, 250 "Add a new virtual interface with the given configuration.\n" 251 IFACE_TYPES "\n\n" 252 "The flags are only used for monitor interfaces, valid flags are:\n" 253 VALID_FLAGS "\n\n" 254 "The mesh_id is used only for mesh mode."); 255 COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]", 256 NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL); 257 258 static int handle_interface_del(struct nl80211_state *state, 259 struct nl_cb *cb, 260 struct nl_msg *msg, 261 int argc, char **argv, 262 enum id_input id) 263 { 264 return 0; 265 } 266 TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del, 267 "Remove this virtual interface"); 268 HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del); 269 270 static char *channel_type_name(enum nl80211_channel_type channel_type) 271 { 272 switch (channel_type) { 273 case NL80211_CHAN_NO_HT: 274 return "NO HT"; 275 case NL80211_CHAN_HT20: 276 return "HT20"; 277 case NL80211_CHAN_HT40MINUS: 278 return "HT40-"; 279 case NL80211_CHAN_HT40PLUS: 280 return "HT40+"; 281 default: 282 return "unknown"; 283 } 284 } 285 286 char *channel_width_name(enum nl80211_chan_width width) 287 { 288 switch (width) { 289 case NL80211_CHAN_WIDTH_20_NOHT: 290 return "20 MHz (no HT)"; 291 case NL80211_CHAN_WIDTH_20: 292 return "20 MHz"; 293 case NL80211_CHAN_WIDTH_40: 294 return "40 MHz"; 295 case NL80211_CHAN_WIDTH_80: 296 return "80 MHz"; 297 case NL80211_CHAN_WIDTH_80P80: 298 return "80+80 MHz"; 299 case NL80211_CHAN_WIDTH_160: 300 return "160 MHz"; 301 default: 302 return "unknown"; 303 } 304 } 305 306 static int print_iface_handler(struct nl_msg *msg, void *arg) 307 { 308 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 309 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; 310 unsigned int *wiphy = arg; 311 const char *indent = ""; 312 313 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 314 genlmsg_attrlen(gnlh, 0), NULL); 315 316 if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) { 317 unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); 318 indent = "\t"; 319 if (*wiphy != thiswiphy) 320 printf("phy#%d\n", thiswiphy); 321 *wiphy = thiswiphy; 322 } 323 324 if (tb_msg[NL80211_ATTR_IFNAME]) 325 printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); 326 else 327 printf("%sUnnamed/non-netdev interface\n", indent); 328 if (tb_msg[NL80211_ATTR_IFINDEX]) 329 printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX])); 330 if (tb_msg[NL80211_ATTR_WDEV]) 331 printf("%s\twdev 0x%llx\n", indent, 332 (unsigned long long)nla_get_u64(tb_msg[NL80211_ATTR_WDEV])); 333 if (tb_msg[NL80211_ATTR_MAC]) { 334 char mac_addr[20]; 335 mac_addr_n2a(mac_addr, nla_data(tb_msg[NL80211_ATTR_MAC])); 336 printf("%s\taddr %s\n", indent, mac_addr); 337 } 338 if (tb_msg[NL80211_ATTR_SSID]) { 339 printf("%s\tssid ", indent); 340 print_ssid_escaped(nla_len(tb_msg[NL80211_ATTR_SSID]), 341 nla_data(tb_msg[NL80211_ATTR_SSID])); 342 printf("\n"); 343 } 344 if (tb_msg[NL80211_ATTR_IFTYPE]) 345 printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]))); 346 if (!wiphy && tb_msg[NL80211_ATTR_WIPHY]) 347 printf("%s\twiphy %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); 348 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { 349 uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); 350 351 printf("%s\tchannel %d (%d MHz)", indent, 352 ieee80211_frequency_to_channel(freq), freq); 353 354 if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) { 355 printf(", width: %s", 356 channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH]))); 357 if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) 358 printf(", center1: %d MHz", 359 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1])); 360 if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) 361 printf(", center2: %d MHz", 362 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2])); 363 } else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { 364 enum nl80211_channel_type channel_type; 365 366 channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); 367 printf(" %s", channel_type_name(channel_type)); 368 } 369 370 printf("\n"); 371 } 372 373 return NL_SKIP; 374 } 375 376 static int handle_interface_info(struct nl80211_state *state, 377 struct nl_cb *cb, 378 struct nl_msg *msg, 379 int argc, char **argv, 380 enum id_input id) 381 { 382 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL); 383 return 0; 384 } 385 TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info, 386 "Show information for this interface."); 387 388 static int handle_interface_set(struct nl80211_state *state, 389 struct nl_cb *cb, 390 struct nl_msg *msg, 391 int argc, char **argv, 392 enum id_input id) 393 { 394 if (!argc) 395 return 1; 396 397 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); 398 399 switch (parse_mntr_flags(&argc, &argv, msg)) { 400 case 0: 401 return 0; 402 case -ENOMEM: 403 fprintf(stderr, "failed to allocate flags\n"); 404 return 2; 405 case -EINVAL: 406 fprintf(stderr, "unknown flag %s\n", *argv); 407 return 2; 408 default: 409 return 2; 410 } 411 nla_put_failure: 412 return -ENOBUFS; 413 } 414 COMMAND(set, monitor, "<flag>*", 415 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set, 416 "Set monitor flags. Valid flags are:\n" 417 VALID_FLAGS); 418 419 static int handle_interface_meshid(struct nl80211_state *state, 420 struct nl_cb *cb, 421 struct nl_msg *msg, 422 int argc, char **argv, 423 enum id_input id) 424 { 425 char *mesh_id = NULL; 426 427 if (argc != 1) 428 return 1; 429 430 mesh_id = argv[0]; 431 432 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); 433 434 return 0; 435 nla_put_failure: 436 return -ENOBUFS; 437 } 438 COMMAND(set, meshid, "<meshid>", 439 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL); 440 441 static unsigned int dev_dump_wiphy; 442 443 static int handle_dev_dump(struct nl80211_state *state, 444 struct nl_cb *cb, 445 struct nl_msg *msg, 446 int argc, char **argv, 447 enum id_input id) 448 { 449 dev_dump_wiphy = -1; 450 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, &dev_dump_wiphy); 451 return 0; 452 } 453 TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump, 454 "List all network interfaces for wireless hardware."); 455 456 static int handle_interface_type(struct nl80211_state *state, 457 struct nl_cb *cb, 458 struct nl_msg *msg, 459 int argc, char **argv, 460 enum id_input id) 461 { 462 enum nl80211_iftype type; 463 int tpset; 464 465 tpset = get_if_type(&argc, &argv, &type, false); 466 if (tpset) 467 return tpset; 468 469 if (argc) 470 return 1; 471 472 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); 473 474 return 0; 475 nla_put_failure: 476 return -ENOBUFS; 477 } 478 COMMAND(set, type, "<type>", 479 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type, 480 "Set interface type/mode.\n" 481 IFACE_TYPES); 482 483 static int handle_interface_4addr(struct nl80211_state *state, 484 struct nl_cb *cb, 485 struct nl_msg *msg, 486 int argc, char **argv, 487 enum id_input id) 488 { 489 if (argc != 1) 490 return 1; 491 return parse_4addr_flag(argv[0], msg); 492 } 493 COMMAND(set, 4addr, "<on|off>", 494 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_4addr, 495 "Set interface 4addr (WDS) mode."); 496 497 static int handle_interface_noack_map(struct nl80211_state *state, 498 struct nl_cb *cb, 499 struct nl_msg *msg, 500 int argc, char **argv, 501 enum id_input id) 502 { 503 uint16_t noack_map; 504 char *end; 505 506 if (argc != 1) 507 return 1; 508 509 noack_map = strtoul(argv[0], &end, 16); 510 if (*end) 511 return 1; 512 513 NLA_PUT_U16(msg, NL80211_ATTR_NOACK_MAP, noack_map); 514 515 return 0; 516 nla_put_failure: 517 return -ENOBUFS; 518 519 } 520 COMMAND(set, noack_map, "<map>", 521 NL80211_CMD_SET_NOACK_MAP, 0, CIB_NETDEV, handle_interface_noack_map, 522 "Set the NoAck map for the TIDs. (0x0009 = BE, 0x0006 = BK, 0x0030 = VI, 0x00C0 = VO)"); 523 524 525 static int handle_interface_wds_peer(struct nl80211_state *state, 526 struct nl_cb *cb, 527 struct nl_msg *msg, 528 int argc, char **argv, 529 enum id_input id) 530 { 531 unsigned char mac_addr[ETH_ALEN]; 532 533 if (argc < 1) 534 return 1; 535 536 if (mac_addr_a2n(mac_addr, argv[0])) { 537 fprintf(stderr, "Invalid MAC address\n"); 538 return 2; 539 } 540 541 argc--; 542 argv++; 543 544 if (argc) 545 return 1; 546 547 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); 548 549 return 0; 550 nla_put_failure: 551 return -ENOBUFS; 552 } 553 COMMAND(set, peer, "<MAC address>", 554 NL80211_CMD_SET_WDS_PEER, 0, CIB_NETDEV, handle_interface_wds_peer, 555 "Set interface WDS peer."); 556 557 static int set_mcast_rate(struct nl80211_state *state, 558 struct nl_cb *cb, 559 struct nl_msg *msg, 560 int argc, char **argv, 561 enum id_input id) 562 { 563 float rate; 564 char *end; 565 566 if (argc != 1) { 567 printf("Invalid parameters!\n"); 568 return 2; 569 } 570 571 rate = strtod(argv[0], &end); 572 if (*end != '\0') 573 return 1; 574 575 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10)); 576 577 return 0; 578 nla_put_failure: 579 return -ENOBUFS; 580 } 581 582 COMMAND(set, mcast_rate, "<rate in Mbps>", 583 NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate, 584 "Set the multicast bitrate."); 585