• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
parse_mntr_flags(int * _argc,char *** _argv,struct nl_msg * msg)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 */
get_if_type(int * argc,char *** argv,enum nl80211_iftype * type,bool need_type)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 
parse_4addr_flag(const char * value,struct nl_msg * msg)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 
handle_interface_add(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_del(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
channel_type_name(enum nl80211_channel_type channel_type)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 
channel_width_name(enum nl80211_chan_width width)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 
print_iface_handler(struct nl_msg * msg,void * arg)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 
handle_interface_info(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_set(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_meshid(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_dev_dump(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_type(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_4addr(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_noack_map(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
handle_interface_wds_peer(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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 
set_mcast_rate(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)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