Home | History | Annotate | Download | only in iw
      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