1*92022041SSam Saccone #include <errno.h>
2*92022041SSam Saccone #include <string.h>
3*92022041SSam Saccone #include <stdbool.h>
4*92022041SSam Saccone
5*92022041SSam Saccone #include <netlink/genl/genl.h>
6*92022041SSam Saccone #include <netlink/genl/family.h>
7*92022041SSam Saccone #include <netlink/genl/ctrl.h>
8*92022041SSam Saccone #include <netlink/msg.h>
9*92022041SSam Saccone #include <netlink/attr.h>
10*92022041SSam Saccone
11*92022041SSam Saccone #include "nl80211.h"
12*92022041SSam Saccone #include "iw.h"
13*92022041SSam Saccone
14*92022041SSam Saccone #define VALID_FLAGS "none: no special flags\n"\
15*92022041SSam Saccone "fcsfail: show frames with FCS errors\n"\
16*92022041SSam Saccone "control: show control frames\n"\
17*92022041SSam Saccone "otherbss: show frames from other BSSes\n"\
18*92022041SSam Saccone "cook: use cooked mode\n"\
19*92022041SSam Saccone "active: use active mode (ACK incoming unicast packets)\n"\
20*92022041SSam Saccone "mumimo-groupid <GROUP_ID>: use MUMIMO according to a group id\n"\
21*92022041SSam Saccone "mumimo-follow-mac <MAC_ADDRESS>: use MUMIMO according to a MAC address"
22*92022041SSam Saccone
23*92022041SSam Saccone SECTION(interface);
24*92022041SSam Saccone
25*92022041SSam Saccone static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = {
26*92022041SSam Saccone "none",
27*92022041SSam Saccone "fcsfail",
28*92022041SSam Saccone "plcpfail",
29*92022041SSam Saccone "control",
30*92022041SSam Saccone "otherbss",
31*92022041SSam Saccone "cook",
32*92022041SSam Saccone "active",
33*92022041SSam Saccone };
34*92022041SSam Saccone
parse_mumimo_options(int * _argc,char *** _argv,struct nl_msg * msg)35*92022041SSam Saccone static int parse_mumimo_options(int *_argc, char ***_argv, struct nl_msg *msg)
36*92022041SSam Saccone {
37*92022041SSam Saccone uint8_t mumimo_group[VHT_MUMIMO_GROUP_LEN];
38*92022041SSam Saccone unsigned char mac_addr[ETH_ALEN];
39*92022041SSam Saccone char **argv = *_argv;
40*92022041SSam Saccone int argc = *_argc;
41*92022041SSam Saccone int i;
42*92022041SSam Saccone unsigned int val;
43*92022041SSam Saccone
44*92022041SSam Saccone if (strcmp(*argv, "mumimo-groupid") == 0) {
45*92022041SSam Saccone argc--;
46*92022041SSam Saccone argv++;
47*92022041SSam Saccone if (!argc || strlen(*argv) != VHT_MUMIMO_GROUP_LEN*2) {
48*92022041SSam Saccone fprintf(stderr, "Invalid groupID: %s\n", *argv);
49*92022041SSam Saccone return 1;
50*92022041SSam Saccone }
51*92022041SSam Saccone
52*92022041SSam Saccone for (i = 0; i < VHT_MUMIMO_GROUP_LEN; i++) {
53*92022041SSam Saccone if (sscanf((*argv) + i*2, "%2x", &val) != 1) {
54*92022041SSam Saccone fprintf(stderr, "Failed reading groupID\n");
55*92022041SSam Saccone return 1;
56*92022041SSam Saccone }
57*92022041SSam Saccone mumimo_group[i] = val;
58*92022041SSam Saccone }
59*92022041SSam Saccone
60*92022041SSam Saccone NLA_PUT(msg,
61*92022041SSam Saccone NL80211_ATTR_MU_MIMO_GROUP_DATA,
62*92022041SSam Saccone VHT_MUMIMO_GROUP_LEN,
63*92022041SSam Saccone mumimo_group);
64*92022041SSam Saccone argc--;
65*92022041SSam Saccone argv++;
66*92022041SSam Saccone } else if (strcmp(*argv, "mumimo-follow-mac") == 0) {
67*92022041SSam Saccone argc--;
68*92022041SSam Saccone argv++;
69*92022041SSam Saccone if (!argc || mac_addr_a2n(mac_addr, *argv)) {
70*92022041SSam Saccone fprintf(stderr, "Invalid MAC address\n");
71*92022041SSam Saccone return 1;
72*92022041SSam Saccone }
73*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
74*92022041SSam Saccone ETH_ALEN, mac_addr);
75*92022041SSam Saccone argc--;
76*92022041SSam Saccone argv++;
77*92022041SSam Saccone }
78*92022041SSam Saccone nla_put_failure:
79*92022041SSam Saccone *_argc = argc;
80*92022041SSam Saccone *_argv = argv;
81*92022041SSam Saccone return 0;
82*92022041SSam Saccone }
83*92022041SSam Saccone
parse_mntr_flags(int * _argc,char *** _argv,struct nl_msg * msg)84*92022041SSam Saccone static int parse_mntr_flags(int *_argc, char ***_argv,
85*92022041SSam Saccone struct nl_msg *msg)
86*92022041SSam Saccone {
87*92022041SSam Saccone struct nl_msg *flags;
88*92022041SSam Saccone int err = -ENOBUFS;
89*92022041SSam Saccone enum nl80211_mntr_flags flag;
90*92022041SSam Saccone int argc = *_argc;
91*92022041SSam Saccone char **argv = *_argv;
92*92022041SSam Saccone
93*92022041SSam Saccone flags = nlmsg_alloc();
94*92022041SSam Saccone if (!flags)
95*92022041SSam Saccone return -ENOMEM;
96*92022041SSam Saccone
97*92022041SSam Saccone while (argc) {
98*92022041SSam Saccone int ok = 0;
99*92022041SSam Saccone
100*92022041SSam Saccone /* parse MU-MIMO options */
101*92022041SSam Saccone err = parse_mumimo_options(&argc, &argv, msg);
102*92022041SSam Saccone if (err)
103*92022041SSam Saccone goto out;
104*92022041SSam Saccone else if (!argc)
105*92022041SSam Saccone break;
106*92022041SSam Saccone
107*92022041SSam Saccone /* parse monitor flags */
108*92022041SSam Saccone for (flag = __NL80211_MNTR_FLAG_INVALID;
109*92022041SSam Saccone flag <= NL80211_MNTR_FLAG_MAX; flag++) {
110*92022041SSam Saccone if (strcmp(*argv, mntr_flags[flag]) == 0) {
111*92022041SSam Saccone ok = 1;
112*92022041SSam Saccone /*
113*92022041SSam Saccone * This shouldn't be adding "flag" if that is
114*92022041SSam Saccone * zero, but due to a problem in the kernel's
115*92022041SSam Saccone * nl80211 code (using NLA_NESTED policy) it
116*92022041SSam Saccone * will reject an empty nested attribute but
117*92022041SSam Saccone * not one that contains an invalid attribute
118*92022041SSam Saccone */
119*92022041SSam Saccone NLA_PUT_FLAG(flags, flag);
120*92022041SSam Saccone break;
121*92022041SSam Saccone }
122*92022041SSam Saccone }
123*92022041SSam Saccone if (!ok) {
124*92022041SSam Saccone err = -EINVAL;
125*92022041SSam Saccone goto out;
126*92022041SSam Saccone }
127*92022041SSam Saccone argc--;
128*92022041SSam Saccone argv++;
129*92022041SSam Saccone }
130*92022041SSam Saccone
131*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
132*92022041SSam Saccone err = 0;
133*92022041SSam Saccone nla_put_failure:
134*92022041SSam Saccone out:
135*92022041SSam Saccone nlmsg_free(flags);
136*92022041SSam Saccone
137*92022041SSam Saccone *_argc = argc;
138*92022041SSam Saccone *_argv = argv;
139*92022041SSam Saccone
140*92022041SSam Saccone return err;
141*92022041SSam Saccone }
142*92022041SSam Saccone
143*92022041SSam Saccone /* for help */
144*92022041SSam Saccone #define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds."
145*92022041SSam Saccone
146*92022041SSam Saccone /* return 0 if ok, internal error otherwise */
get_if_type(int * argc,char *** argv,enum nl80211_iftype * type,bool need_type)147*92022041SSam Saccone static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type,
148*92022041SSam Saccone bool need_type)
149*92022041SSam Saccone {
150*92022041SSam Saccone char *tpstr;
151*92022041SSam Saccone
152*92022041SSam Saccone if (*argc < 1 + !!need_type)
153*92022041SSam Saccone return 1;
154*92022041SSam Saccone
155*92022041SSam Saccone if (need_type && strcmp((*argv)[0], "type"))
156*92022041SSam Saccone return 1;
157*92022041SSam Saccone
158*92022041SSam Saccone tpstr = (*argv)[!!need_type];
159*92022041SSam Saccone *argc -= 1 + !!need_type;
160*92022041SSam Saccone *argv += 1 + !!need_type;
161*92022041SSam Saccone
162*92022041SSam Saccone if (strcmp(tpstr, "adhoc") == 0 ||
163*92022041SSam Saccone strcmp(tpstr, "ibss") == 0) {
164*92022041SSam Saccone *type = NL80211_IFTYPE_ADHOC;
165*92022041SSam Saccone return 0;
166*92022041SSam Saccone } else if (strcmp(tpstr, "ocb") == 0) {
167*92022041SSam Saccone *type = NL80211_IFTYPE_OCB;
168*92022041SSam Saccone return 0;
169*92022041SSam Saccone } else if (strcmp(tpstr, "monitor") == 0) {
170*92022041SSam Saccone *type = NL80211_IFTYPE_MONITOR;
171*92022041SSam Saccone return 0;
172*92022041SSam Saccone } else if (strcmp(tpstr, "master") == 0 ||
173*92022041SSam Saccone strcmp(tpstr, "ap") == 0) {
174*92022041SSam Saccone *type = NL80211_IFTYPE_UNSPECIFIED;
175*92022041SSam Saccone fprintf(stderr, "You need to run a management daemon, e.g. hostapd,\n");
176*92022041SSam Saccone fprintf(stderr, "see http://wireless.kernel.org/en/users/Documentation/hostapd\n");
177*92022041SSam Saccone fprintf(stderr, "for more information on how to do that.\n");
178*92022041SSam Saccone return 2;
179*92022041SSam Saccone } else if (strcmp(tpstr, "__ap") == 0) {
180*92022041SSam Saccone *type = NL80211_IFTYPE_AP;
181*92022041SSam Saccone return 0;
182*92022041SSam Saccone } else if (strcmp(tpstr, "__ap_vlan") == 0) {
183*92022041SSam Saccone *type = NL80211_IFTYPE_AP_VLAN;
184*92022041SSam Saccone return 0;
185*92022041SSam Saccone } else if (strcmp(tpstr, "wds") == 0) {
186*92022041SSam Saccone *type = NL80211_IFTYPE_WDS;
187*92022041SSam Saccone return 0;
188*92022041SSam Saccone } else if (strcmp(tpstr, "managed") == 0 ||
189*92022041SSam Saccone strcmp(tpstr, "mgd") == 0 ||
190*92022041SSam Saccone strcmp(tpstr, "station") == 0) {
191*92022041SSam Saccone *type = NL80211_IFTYPE_STATION;
192*92022041SSam Saccone return 0;
193*92022041SSam Saccone } else if (strcmp(tpstr, "mp") == 0 ||
194*92022041SSam Saccone strcmp(tpstr, "mesh") == 0) {
195*92022041SSam Saccone *type = NL80211_IFTYPE_MESH_POINT;
196*92022041SSam Saccone return 0;
197*92022041SSam Saccone } else if (strcmp(tpstr, "__p2pcl") == 0) {
198*92022041SSam Saccone *type = NL80211_IFTYPE_P2P_CLIENT;
199*92022041SSam Saccone return 0;
200*92022041SSam Saccone } else if (strcmp(tpstr, "__p2pdev") == 0) {
201*92022041SSam Saccone *type = NL80211_IFTYPE_P2P_DEVICE;
202*92022041SSam Saccone return 0;
203*92022041SSam Saccone } else if (strcmp(tpstr, "__p2pgo") == 0) {
204*92022041SSam Saccone *type = NL80211_IFTYPE_P2P_GO;
205*92022041SSam Saccone return 0;
206*92022041SSam Saccone } else if (strcmp(tpstr, "__nan") == 0) {
207*92022041SSam Saccone *type = NL80211_IFTYPE_NAN;
208*92022041SSam Saccone return 0;
209*92022041SSam Saccone }
210*92022041SSam Saccone
211*92022041SSam Saccone fprintf(stderr, "invalid interface type %s\n", tpstr);
212*92022041SSam Saccone return 2;
213*92022041SSam Saccone }
214*92022041SSam Saccone
parse_4addr_flag(const char * value,struct nl_msg * msg)215*92022041SSam Saccone static int parse_4addr_flag(const char *value, struct nl_msg *msg)
216*92022041SSam Saccone {
217*92022041SSam Saccone if (strcmp(value, "on") == 0)
218*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1);
219*92022041SSam Saccone else if (strcmp(value, "off") == 0)
220*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0);
221*92022041SSam Saccone else
222*92022041SSam Saccone return 1;
223*92022041SSam Saccone return 0;
224*92022041SSam Saccone
225*92022041SSam Saccone nla_put_failure:
226*92022041SSam Saccone return 1;
227*92022041SSam Saccone }
228*92022041SSam Saccone
handle_interface_add(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)229*92022041SSam Saccone static int handle_interface_add(struct nl80211_state *state,
230*92022041SSam Saccone struct nl_msg *msg,
231*92022041SSam Saccone int argc, char **argv,
232*92022041SSam Saccone enum id_input id)
233*92022041SSam Saccone {
234*92022041SSam Saccone char *name;
235*92022041SSam Saccone char *mesh_id = NULL;
236*92022041SSam Saccone enum nl80211_iftype type;
237*92022041SSam Saccone int tpset;
238*92022041SSam Saccone unsigned char mac_addr[ETH_ALEN];
239*92022041SSam Saccone int found_mac = 0;
240*92022041SSam Saccone
241*92022041SSam Saccone if (argc < 1)
242*92022041SSam Saccone return 1;
243*92022041SSam Saccone
244*92022041SSam Saccone name = argv[0];
245*92022041SSam Saccone argc--;
246*92022041SSam Saccone argv++;
247*92022041SSam Saccone
248*92022041SSam Saccone tpset = get_if_type(&argc, &argv, &type, true);
249*92022041SSam Saccone if (tpset)
250*92022041SSam Saccone return tpset;
251*92022041SSam Saccone
252*92022041SSam Saccone try_another:
253*92022041SSam Saccone if (argc) {
254*92022041SSam Saccone if (strcmp(argv[0], "mesh_id") == 0) {
255*92022041SSam Saccone argc--;
256*92022041SSam Saccone argv++;
257*92022041SSam Saccone
258*92022041SSam Saccone if (!argc)
259*92022041SSam Saccone return 1;
260*92022041SSam Saccone mesh_id = argv[0];
261*92022041SSam Saccone argc--;
262*92022041SSam Saccone argv++;
263*92022041SSam Saccone } else if (strcmp(argv[0], "addr") == 0) {
264*92022041SSam Saccone argc--;
265*92022041SSam Saccone argv++;
266*92022041SSam Saccone if (mac_addr_a2n(mac_addr, argv[0])) {
267*92022041SSam Saccone fprintf(stderr, "Invalid MAC address\n");
268*92022041SSam Saccone return 2;
269*92022041SSam Saccone }
270*92022041SSam Saccone argc--;
271*92022041SSam Saccone argv++;
272*92022041SSam Saccone found_mac = 1;
273*92022041SSam Saccone goto try_another;
274*92022041SSam Saccone } else if (strcmp(argv[0], "4addr") == 0) {
275*92022041SSam Saccone argc--;
276*92022041SSam Saccone argv++;
277*92022041SSam Saccone if (parse_4addr_flag(argv[0], msg)) {
278*92022041SSam Saccone fprintf(stderr, "4addr error\n");
279*92022041SSam Saccone return 2;
280*92022041SSam Saccone }
281*92022041SSam Saccone argc--;
282*92022041SSam Saccone argv++;
283*92022041SSam Saccone } else if (strcmp(argv[0], "flags") == 0) {
284*92022041SSam Saccone argc--;
285*92022041SSam Saccone argv++;
286*92022041SSam Saccone if (parse_mntr_flags(&argc, &argv, msg)) {
287*92022041SSam Saccone fprintf(stderr, "flags error\n");
288*92022041SSam Saccone return 2;
289*92022041SSam Saccone }
290*92022041SSam Saccone } else {
291*92022041SSam Saccone return 1;
292*92022041SSam Saccone }
293*92022041SSam Saccone }
294*92022041SSam Saccone
295*92022041SSam Saccone if (argc)
296*92022041SSam Saccone return 1;
297*92022041SSam Saccone
298*92022041SSam Saccone NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
299*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
300*92022041SSam Saccone if (mesh_id)
301*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id);
302*92022041SSam Saccone if (found_mac)
303*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
304*92022041SSam Saccone
305*92022041SSam Saccone return 0;
306*92022041SSam Saccone nla_put_failure:
307*92022041SSam Saccone return -ENOBUFS;
308*92022041SSam Saccone }
309*92022041SSam Saccone COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]",
310*92022041SSam Saccone NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add,
311*92022041SSam Saccone "Add a new virtual interface with the given configuration.\n"
312*92022041SSam Saccone IFACE_TYPES "\n\n"
313*92022041SSam Saccone "The flags are only used for monitor interfaces, valid flags are:\n"
314*92022041SSam Saccone VALID_FLAGS "\n\n"
315*92022041SSam Saccone "The mesh_id is used only for mesh mode.");
316*92022041SSam Saccone COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]",
317*92022041SSam Saccone NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL);
318*92022041SSam Saccone
handle_interface_del(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)319*92022041SSam Saccone static int handle_interface_del(struct nl80211_state *state,
320*92022041SSam Saccone struct nl_msg *msg,
321*92022041SSam Saccone int argc, char **argv,
322*92022041SSam Saccone enum id_input id)
323*92022041SSam Saccone {
324*92022041SSam Saccone return 0;
325*92022041SSam Saccone }
326*92022041SSam Saccone TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del,
327*92022041SSam Saccone "Remove this virtual interface");
328*92022041SSam Saccone HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del);
329*92022041SSam Saccone
channel_type_name(enum nl80211_channel_type channel_type)330*92022041SSam Saccone static char *channel_type_name(enum nl80211_channel_type channel_type)
331*92022041SSam Saccone {
332*92022041SSam Saccone switch (channel_type) {
333*92022041SSam Saccone case NL80211_CHAN_NO_HT:
334*92022041SSam Saccone return "NO HT";
335*92022041SSam Saccone case NL80211_CHAN_HT20:
336*92022041SSam Saccone return "HT20";
337*92022041SSam Saccone case NL80211_CHAN_HT40MINUS:
338*92022041SSam Saccone return "HT40-";
339*92022041SSam Saccone case NL80211_CHAN_HT40PLUS:
340*92022041SSam Saccone return "HT40+";
341*92022041SSam Saccone default:
342*92022041SSam Saccone return "unknown";
343*92022041SSam Saccone }
344*92022041SSam Saccone }
345*92022041SSam Saccone
channel_width_name(enum nl80211_chan_width width)346*92022041SSam Saccone char *channel_width_name(enum nl80211_chan_width width)
347*92022041SSam Saccone {
348*92022041SSam Saccone switch (width) {
349*92022041SSam Saccone case NL80211_CHAN_WIDTH_20_NOHT:
350*92022041SSam Saccone return "20 MHz (no HT)";
351*92022041SSam Saccone case NL80211_CHAN_WIDTH_20:
352*92022041SSam Saccone return "20 MHz";
353*92022041SSam Saccone case NL80211_CHAN_WIDTH_40:
354*92022041SSam Saccone return "40 MHz";
355*92022041SSam Saccone case NL80211_CHAN_WIDTH_80:
356*92022041SSam Saccone return "80 MHz";
357*92022041SSam Saccone case NL80211_CHAN_WIDTH_80P80:
358*92022041SSam Saccone return "80+80 MHz";
359*92022041SSam Saccone case NL80211_CHAN_WIDTH_160:
360*92022041SSam Saccone return "160 MHz";
361*92022041SSam Saccone case NL80211_CHAN_WIDTH_5:
362*92022041SSam Saccone return "5 MHz";
363*92022041SSam Saccone case NL80211_CHAN_WIDTH_10:
364*92022041SSam Saccone return "10 MHz";
365*92022041SSam Saccone case NL80211_CHAN_WIDTH_320:
366*92022041SSam Saccone return "320 MHz";
367*92022041SSam Saccone default:
368*92022041SSam Saccone return "unknown";
369*92022041SSam Saccone }
370*92022041SSam Saccone }
371*92022041SSam Saccone
print_iface_handler(struct nl_msg * msg,void * arg)372*92022041SSam Saccone static int print_iface_handler(struct nl_msg *msg, void *arg)
373*92022041SSam Saccone {
374*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
375*92022041SSam Saccone struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
376*92022041SSam Saccone unsigned int *wiphy = arg;
377*92022041SSam Saccone const char *indent = "";
378*92022041SSam Saccone
379*92022041SSam Saccone nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
380*92022041SSam Saccone genlmsg_attrlen(gnlh, 0), NULL);
381*92022041SSam Saccone
382*92022041SSam Saccone if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) {
383*92022041SSam Saccone unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
384*92022041SSam Saccone indent = "\t";
385*92022041SSam Saccone if (*wiphy != thiswiphy)
386*92022041SSam Saccone printf("phy#%d\n", thiswiphy);
387*92022041SSam Saccone *wiphy = thiswiphy;
388*92022041SSam Saccone }
389*92022041SSam Saccone
390*92022041SSam Saccone if (tb_msg[NL80211_ATTR_IFNAME])
391*92022041SSam Saccone printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
392*92022041SSam Saccone else
393*92022041SSam Saccone printf("%sUnnamed/non-netdev interface\n", indent);
394*92022041SSam Saccone if (tb_msg[NL80211_ATTR_IFINDEX])
395*92022041SSam Saccone printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]));
396*92022041SSam Saccone if (tb_msg[NL80211_ATTR_WDEV])
397*92022041SSam Saccone printf("%s\twdev 0x%llx\n", indent,
398*92022041SSam Saccone (unsigned long long)nla_get_u64(tb_msg[NL80211_ATTR_WDEV]));
399*92022041SSam Saccone if (tb_msg[NL80211_ATTR_MAC]) {
400*92022041SSam Saccone char mac_addr[20];
401*92022041SSam Saccone mac_addr_n2a(mac_addr, nla_data(tb_msg[NL80211_ATTR_MAC]));
402*92022041SSam Saccone printf("%s\taddr %s\n", indent, mac_addr);
403*92022041SSam Saccone }
404*92022041SSam Saccone if (tb_msg[NL80211_ATTR_SSID]) {
405*92022041SSam Saccone printf("%s\tssid ", indent);
406*92022041SSam Saccone print_ssid_escaped(nla_len(tb_msg[NL80211_ATTR_SSID]),
407*92022041SSam Saccone nla_data(tb_msg[NL80211_ATTR_SSID]));
408*92022041SSam Saccone printf("\n");
409*92022041SSam Saccone }
410*92022041SSam Saccone if (tb_msg[NL80211_ATTR_IFTYPE])
411*92022041SSam Saccone printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE])));
412*92022041SSam Saccone if (!wiphy && tb_msg[NL80211_ATTR_WIPHY])
413*92022041SSam Saccone printf("%s\twiphy %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]));
414*92022041SSam Saccone if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
415*92022041SSam Saccone uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
416*92022041SSam Saccone
417*92022041SSam Saccone printf("%s\tchannel %d (%d MHz)", indent,
418*92022041SSam Saccone ieee80211_frequency_to_channel(freq), freq);
419*92022041SSam Saccone
420*92022041SSam Saccone if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
421*92022041SSam Saccone printf(", width: %s",
422*92022041SSam Saccone channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])));
423*92022041SSam Saccone if (tb_msg[NL80211_ATTR_CENTER_FREQ1])
424*92022041SSam Saccone printf(", center1: %d MHz",
425*92022041SSam Saccone nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]));
426*92022041SSam Saccone if (tb_msg[NL80211_ATTR_CENTER_FREQ2])
427*92022041SSam Saccone printf(", center2: %d MHz",
428*92022041SSam Saccone nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]));
429*92022041SSam Saccone } else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
430*92022041SSam Saccone enum nl80211_channel_type channel_type;
431*92022041SSam Saccone
432*92022041SSam Saccone channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
433*92022041SSam Saccone printf(" %s", channel_type_name(channel_type));
434*92022041SSam Saccone }
435*92022041SSam Saccone
436*92022041SSam Saccone printf("\n");
437*92022041SSam Saccone }
438*92022041SSam Saccone
439*92022041SSam Saccone if (tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]) {
440*92022041SSam Saccone int32_t txp = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]);
441*92022041SSam Saccone
442*92022041SSam Saccone printf("%s\ttxpower %d.%.2d dBm\n",
443*92022041SSam Saccone indent, txp / 100, txp % 100);
444*92022041SSam Saccone }
445*92022041SSam Saccone
446*92022041SSam Saccone if (tb_msg[NL80211_ATTR_TXQ_STATS]) {
447*92022041SSam Saccone char buf[150];
448*92022041SSam Saccone parse_txq_stats(buf, sizeof(buf), tb_msg[NL80211_ATTR_TXQ_STATS], 1, -1, indent);
449*92022041SSam Saccone printf("%s\tmulticast TXQ:%s\n", indent, buf);
450*92022041SSam Saccone }
451*92022041SSam Saccone
452*92022041SSam Saccone if (tb_msg[NL80211_ATTR_4ADDR]) {
453*92022041SSam Saccone uint8_t use_4addr = nla_get_u8(tb_msg[NL80211_ATTR_4ADDR]);
454*92022041SSam Saccone if (use_4addr)
455*92022041SSam Saccone printf("%s\t4addr: on\n", indent);
456*92022041SSam Saccone }
457*92022041SSam Saccone
458*92022041SSam Saccone return NL_SKIP;
459*92022041SSam Saccone }
460*92022041SSam Saccone
handle_interface_info(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)461*92022041SSam Saccone static int handle_interface_info(struct nl80211_state *state,
462*92022041SSam Saccone struct nl_msg *msg,
463*92022041SSam Saccone int argc, char **argv,
464*92022041SSam Saccone enum id_input id)
465*92022041SSam Saccone {
466*92022041SSam Saccone register_handler(print_iface_handler, NULL);
467*92022041SSam Saccone return 0;
468*92022041SSam Saccone }
469*92022041SSam Saccone TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info,
470*92022041SSam Saccone "Show information for this interface.");
471*92022041SSam Saccone
handle_interface_set(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)472*92022041SSam Saccone static int handle_interface_set(struct nl80211_state *state,
473*92022041SSam Saccone struct nl_msg *msg,
474*92022041SSam Saccone int argc, char **argv,
475*92022041SSam Saccone enum id_input id)
476*92022041SSam Saccone {
477*92022041SSam Saccone if (!argc)
478*92022041SSam Saccone return 1;
479*92022041SSam Saccone
480*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
481*92022041SSam Saccone
482*92022041SSam Saccone switch (parse_mntr_flags(&argc, &argv, msg)) {
483*92022041SSam Saccone case 0:
484*92022041SSam Saccone return 0;
485*92022041SSam Saccone case 1:
486*92022041SSam Saccone return 1;
487*92022041SSam Saccone case -ENOMEM:
488*92022041SSam Saccone fprintf(stderr, "failed to allocate flags\n");
489*92022041SSam Saccone return 2;
490*92022041SSam Saccone case -EINVAL:
491*92022041SSam Saccone fprintf(stderr, "unknown flag %s\n", *argv);
492*92022041SSam Saccone return 2;
493*92022041SSam Saccone default:
494*92022041SSam Saccone return 2;
495*92022041SSam Saccone }
496*92022041SSam Saccone nla_put_failure:
497*92022041SSam Saccone return -ENOBUFS;
498*92022041SSam Saccone }
499*92022041SSam Saccone COMMAND(set, monitor, "<flag>*",
500*92022041SSam Saccone NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set,
501*92022041SSam Saccone "Set monitor flags. Valid flags are:\n"
502*92022041SSam Saccone VALID_FLAGS);
503*92022041SSam Saccone
handle_interface_meshid(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)504*92022041SSam Saccone static int handle_interface_meshid(struct nl80211_state *state,
505*92022041SSam Saccone struct nl_msg *msg,
506*92022041SSam Saccone int argc, char **argv,
507*92022041SSam Saccone enum id_input id)
508*92022041SSam Saccone {
509*92022041SSam Saccone char *mesh_id = NULL;
510*92022041SSam Saccone
511*92022041SSam Saccone if (argc != 1)
512*92022041SSam Saccone return 1;
513*92022041SSam Saccone
514*92022041SSam Saccone mesh_id = argv[0];
515*92022041SSam Saccone
516*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id);
517*92022041SSam Saccone
518*92022041SSam Saccone return 0;
519*92022041SSam Saccone nla_put_failure:
520*92022041SSam Saccone return -ENOBUFS;
521*92022041SSam Saccone }
522*92022041SSam Saccone COMMAND(set, meshid, "<meshid>",
523*92022041SSam Saccone NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL);
524*92022041SSam Saccone
525*92022041SSam Saccone static unsigned int dev_dump_wiphy;
526*92022041SSam Saccone
handle_dev_dump(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)527*92022041SSam Saccone static int handle_dev_dump(struct nl80211_state *state,
528*92022041SSam Saccone struct nl_msg *msg,
529*92022041SSam Saccone int argc, char **argv,
530*92022041SSam Saccone enum id_input id)
531*92022041SSam Saccone {
532*92022041SSam Saccone dev_dump_wiphy = -1;
533*92022041SSam Saccone register_handler(print_iface_handler, &dev_dump_wiphy);
534*92022041SSam Saccone return 0;
535*92022041SSam Saccone }
536*92022041SSam Saccone TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump,
537*92022041SSam Saccone "List all network interfaces for wireless hardware.");
538*92022041SSam Saccone
handle_interface_type(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)539*92022041SSam Saccone static int handle_interface_type(struct nl80211_state *state,
540*92022041SSam Saccone struct nl_msg *msg,
541*92022041SSam Saccone int argc, char **argv,
542*92022041SSam Saccone enum id_input id)
543*92022041SSam Saccone {
544*92022041SSam Saccone enum nl80211_iftype type;
545*92022041SSam Saccone int tpset;
546*92022041SSam Saccone
547*92022041SSam Saccone tpset = get_if_type(&argc, &argv, &type, false);
548*92022041SSam Saccone if (tpset)
549*92022041SSam Saccone return tpset;
550*92022041SSam Saccone
551*92022041SSam Saccone if (argc)
552*92022041SSam Saccone return 1;
553*92022041SSam Saccone
554*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
555*92022041SSam Saccone
556*92022041SSam Saccone return 0;
557*92022041SSam Saccone nla_put_failure:
558*92022041SSam Saccone return -ENOBUFS;
559*92022041SSam Saccone }
560*92022041SSam Saccone COMMAND(set, type, "<type>",
561*92022041SSam Saccone NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type,
562*92022041SSam Saccone "Set interface type/mode.\n"
563*92022041SSam Saccone IFACE_TYPES);
564*92022041SSam Saccone
handle_interface_4addr(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)565*92022041SSam Saccone static int handle_interface_4addr(struct nl80211_state *state,
566*92022041SSam Saccone struct nl_msg *msg,
567*92022041SSam Saccone int argc, char **argv,
568*92022041SSam Saccone enum id_input id)
569*92022041SSam Saccone {
570*92022041SSam Saccone if (argc != 1)
571*92022041SSam Saccone return 1;
572*92022041SSam Saccone return parse_4addr_flag(argv[0], msg);
573*92022041SSam Saccone }
574*92022041SSam Saccone COMMAND(set, 4addr, "<on|off>",
575*92022041SSam Saccone NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_4addr,
576*92022041SSam Saccone "Set interface 4addr (WDS) mode.");
577*92022041SSam Saccone
handle_interface_noack_map(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)578*92022041SSam Saccone static int handle_interface_noack_map(struct nl80211_state *state,
579*92022041SSam Saccone struct nl_msg *msg,
580*92022041SSam Saccone int argc, char **argv,
581*92022041SSam Saccone enum id_input id)
582*92022041SSam Saccone {
583*92022041SSam Saccone uint16_t noack_map;
584*92022041SSam Saccone char *end;
585*92022041SSam Saccone
586*92022041SSam Saccone if (argc != 1)
587*92022041SSam Saccone return 1;
588*92022041SSam Saccone
589*92022041SSam Saccone noack_map = strtoul(argv[0], &end, 16);
590*92022041SSam Saccone if (*end)
591*92022041SSam Saccone return 1;
592*92022041SSam Saccone
593*92022041SSam Saccone NLA_PUT_U16(msg, NL80211_ATTR_NOACK_MAP, noack_map);
594*92022041SSam Saccone
595*92022041SSam Saccone return 0;
596*92022041SSam Saccone nla_put_failure:
597*92022041SSam Saccone return -ENOBUFS;
598*92022041SSam Saccone
599*92022041SSam Saccone }
600*92022041SSam Saccone COMMAND(set, noack_map, "<map>",
601*92022041SSam Saccone NL80211_CMD_SET_NOACK_MAP, 0, CIB_NETDEV, handle_interface_noack_map,
602*92022041SSam Saccone "Set the NoAck map for the TIDs. (0x0009 = BE, 0x0006 = BK, 0x0030 = VI, 0x00C0 = VO)");
603*92022041SSam Saccone
604*92022041SSam Saccone
handle_interface_wds_peer(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)605*92022041SSam Saccone static int handle_interface_wds_peer(struct nl80211_state *state,
606*92022041SSam Saccone struct nl_msg *msg,
607*92022041SSam Saccone int argc, char **argv,
608*92022041SSam Saccone enum id_input id)
609*92022041SSam Saccone {
610*92022041SSam Saccone unsigned char mac_addr[ETH_ALEN];
611*92022041SSam Saccone
612*92022041SSam Saccone if (argc < 1)
613*92022041SSam Saccone return 1;
614*92022041SSam Saccone
615*92022041SSam Saccone if (mac_addr_a2n(mac_addr, argv[0])) {
616*92022041SSam Saccone fprintf(stderr, "Invalid MAC address\n");
617*92022041SSam Saccone return 2;
618*92022041SSam Saccone }
619*92022041SSam Saccone
620*92022041SSam Saccone argc--;
621*92022041SSam Saccone argv++;
622*92022041SSam Saccone
623*92022041SSam Saccone if (argc)
624*92022041SSam Saccone return 1;
625*92022041SSam Saccone
626*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
627*92022041SSam Saccone
628*92022041SSam Saccone return 0;
629*92022041SSam Saccone nla_put_failure:
630*92022041SSam Saccone return -ENOBUFS;
631*92022041SSam Saccone }
632*92022041SSam Saccone COMMAND(set, peer, "<MAC address>",
633*92022041SSam Saccone NL80211_CMD_SET_WDS_PEER, 0, CIB_NETDEV, handle_interface_wds_peer,
634*92022041SSam Saccone "Set interface WDS peer.");
635*92022041SSam Saccone
set_mcast_rate(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)636*92022041SSam Saccone static int set_mcast_rate(struct nl80211_state *state,
637*92022041SSam Saccone struct nl_msg *msg,
638*92022041SSam Saccone int argc, char **argv,
639*92022041SSam Saccone enum id_input id)
640*92022041SSam Saccone {
641*92022041SSam Saccone float rate;
642*92022041SSam Saccone char *end;
643*92022041SSam Saccone
644*92022041SSam Saccone if (argc != 1)
645*92022041SSam Saccone return 1;
646*92022041SSam Saccone
647*92022041SSam Saccone rate = strtod(argv[0], &end);
648*92022041SSam Saccone if (*end != '\0')
649*92022041SSam Saccone return 1;
650*92022041SSam Saccone
651*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
652*92022041SSam Saccone
653*92022041SSam Saccone return 0;
654*92022041SSam Saccone nla_put_failure:
655*92022041SSam Saccone return -ENOBUFS;
656*92022041SSam Saccone }
657*92022041SSam Saccone
658*92022041SSam Saccone COMMAND(set, mcast_rate, "<rate in Mbps>",
659*92022041SSam Saccone NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate,
660*92022041SSam Saccone "Set the multicast bitrate.");
661*92022041SSam Saccone
662*92022041SSam Saccone
handle_chanfreq(struct nl80211_state * state,struct nl_msg * msg,bool chan,int argc,char ** argv,enum id_input id)663*92022041SSam Saccone static int handle_chanfreq(struct nl80211_state *state, struct nl_msg *msg,
664*92022041SSam Saccone bool chan, int argc, char **argv,
665*92022041SSam Saccone enum id_input id)
666*92022041SSam Saccone {
667*92022041SSam Saccone struct chandef chandef;
668*92022041SSam Saccone int res;
669*92022041SSam Saccone int parsed;
670*92022041SSam Saccone char *end;
671*92022041SSam Saccone
672*92022041SSam Saccone res = parse_freqchan(&chandef, chan, argc, argv, &parsed);
673*92022041SSam Saccone if (res)
674*92022041SSam Saccone return res;
675*92022041SSam Saccone
676*92022041SSam Saccone argc -= parsed;
677*92022041SSam Saccone argv += parsed;
678*92022041SSam Saccone
679*92022041SSam Saccone while (argc) {
680*92022041SSam Saccone unsigned int beacons = 10;
681*92022041SSam Saccone
682*92022041SSam Saccone if (strcmp(argv[0], "beacons") == 0) {
683*92022041SSam Saccone if (argc < 2)
684*92022041SSam Saccone return 1;
685*92022041SSam Saccone
686*92022041SSam Saccone beacons = strtol(argv[1], &end, 10);
687*92022041SSam Saccone if (*end)
688*92022041SSam Saccone return 1;
689*92022041SSam Saccone
690*92022041SSam Saccone argc -= 2;
691*92022041SSam Saccone argv += 2;
692*92022041SSam Saccone
693*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, beacons);
694*92022041SSam Saccone } else if (strcmp(argv[0], "block-tx") == 0) {
695*92022041SSam Saccone argc -= 1;
696*92022041SSam Saccone argv += 1;
697*92022041SSam Saccone
698*92022041SSam Saccone NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
699*92022041SSam Saccone } else {
700*92022041SSam Saccone return 1;
701*92022041SSam Saccone }
702*92022041SSam Saccone }
703*92022041SSam Saccone
704*92022041SSam Saccone return put_chandef(msg, &chandef);
705*92022041SSam Saccone
706*92022041SSam Saccone nla_put_failure:
707*92022041SSam Saccone return -ENOBUFS;
708*92022041SSam Saccone }
709*92022041SSam Saccone
handle_freq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)710*92022041SSam Saccone static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
711*92022041SSam Saccone int argc, char **argv,
712*92022041SSam Saccone enum id_input id)
713*92022041SSam Saccone {
714*92022041SSam Saccone return handle_chanfreq(state, msg, false, argc, argv, id);
715*92022041SSam Saccone }
716*92022041SSam Saccone
handle_chan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)717*92022041SSam Saccone static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
718*92022041SSam Saccone int argc, char **argv,
719*92022041SSam Saccone enum id_input id)
720*92022041SSam Saccone {
721*92022041SSam Saccone return handle_chanfreq(state, msg, true, argc, argv, id);
722*92022041SSam Saccone }
723*92022041SSam Saccone
724*92022041SSam Saccone SECTION(switch);
725*92022041SSam Saccone COMMAND(switch, freq,
726*92022041SSam Saccone "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]\n"
727*92022041SSam Saccone "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]] [beacons <count>] [block-tx]",
728*92022041SSam Saccone NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_freq,
729*92022041SSam Saccone "Switch the operating channel by sending a channel switch announcement (CSA).");
730*92022041SSam Saccone COMMAND(switch, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]",
731*92022041SSam Saccone NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_chan, NULL);
732*92022041SSam Saccone
733*92022041SSam Saccone
toggle_tid_param(const char * argv0,const char * argv1,struct nl_msg * msg,uint32_t attr)734*92022041SSam Saccone static int toggle_tid_param(const char *argv0, const char *argv1,
735*92022041SSam Saccone struct nl_msg *msg, uint32_t attr)
736*92022041SSam Saccone {
737*92022041SSam Saccone uint8_t val;
738*92022041SSam Saccone
739*92022041SSam Saccone if (strcmp(argv1, "on") == 0) {
740*92022041SSam Saccone val = NL80211_TID_CONFIG_ENABLE;
741*92022041SSam Saccone } else if (strcmp(argv1, "off") == 0) {
742*92022041SSam Saccone val = NL80211_TID_CONFIG_DISABLE;
743*92022041SSam Saccone } else {
744*92022041SSam Saccone fprintf(stderr, "Invalid %s parameter: %s\n", argv0, argv1);
745*92022041SSam Saccone return 2;
746*92022041SSam Saccone }
747*92022041SSam Saccone
748*92022041SSam Saccone NLA_PUT_U8(msg, attr, val);
749*92022041SSam Saccone return 0;
750*92022041SSam Saccone
751*92022041SSam Saccone nla_put_failure:
752*92022041SSam Saccone return -ENOBUFS;
753*92022041SSam Saccone }
754*92022041SSam Saccone
handle_tid_config(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)755*92022041SSam Saccone static int handle_tid_config(struct nl80211_state *state,
756*92022041SSam Saccone struct nl_msg *msg,
757*92022041SSam Saccone int argc, char **argv,
758*92022041SSam Saccone enum id_input id)
759*92022041SSam Saccone {
760*92022041SSam Saccone struct nlattr *tids_array = NULL;
761*92022041SSam Saccone struct nlattr *tids_entry = NULL;
762*92022041SSam Saccone enum nl80211_tx_rate_setting txrate_type;
763*92022041SSam Saccone unsigned char peer[ETH_ALEN];
764*92022041SSam Saccone int tids_num = 0;
765*92022041SSam Saccone char *end;
766*92022041SSam Saccone int ret;
767*92022041SSam Saccone enum {
768*92022041SSam Saccone PS_ADDR,
769*92022041SSam Saccone PS_TIDS,
770*92022041SSam Saccone PS_CONF,
771*92022041SSam Saccone } parse_state = PS_ADDR;
772*92022041SSam Saccone unsigned int attr;
773*92022041SSam Saccone
774*92022041SSam Saccone while (argc) {
775*92022041SSam Saccone switch (parse_state) {
776*92022041SSam Saccone case PS_ADDR:
777*92022041SSam Saccone if (strcmp(argv[0], "peer") == 0) {
778*92022041SSam Saccone if (argc < 2) {
779*92022041SSam Saccone fprintf(stderr, "Not enough args for %s\n", argv[0]);
780*92022041SSam Saccone return HANDLER_RET_USAGE;
781*92022041SSam Saccone }
782*92022041SSam Saccone
783*92022041SSam Saccone if (mac_addr_a2n(peer, argv[1])) {
784*92022041SSam Saccone fprintf(stderr, "Invalid MAC address\n");
785*92022041SSam Saccone return 2;
786*92022041SSam Saccone }
787*92022041SSam Saccone
788*92022041SSam Saccone NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
789*92022041SSam Saccone
790*92022041SSam Saccone argc -= 2;
791*92022041SSam Saccone argv += 2;
792*92022041SSam Saccone parse_state = PS_TIDS;
793*92022041SSam Saccone
794*92022041SSam Saccone } else if (strcmp(argv[0], "tids") == 0) {
795*92022041SSam Saccone parse_state = PS_TIDS;
796*92022041SSam Saccone } else {
797*92022041SSam Saccone fprintf(stderr, "Peer MAC address expected\n");
798*92022041SSam Saccone return HANDLER_RET_USAGE;
799*92022041SSam Saccone }
800*92022041SSam Saccone
801*92022041SSam Saccone break;
802*92022041SSam Saccone case PS_TIDS:
803*92022041SSam Saccone if (strcmp(argv[0], "tids") == 0) {
804*92022041SSam Saccone if (argc < 2) {
805*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
806*92022041SSam Saccone return HANDLER_RET_USAGE;
807*92022041SSam Saccone }
808*92022041SSam Saccone
809*92022041SSam Saccone if (!tids_array) {
810*92022041SSam Saccone tids_array = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG);
811*92022041SSam Saccone if (!tids_array)
812*92022041SSam Saccone return -ENOBUFS;
813*92022041SSam Saccone }
814*92022041SSam Saccone
815*92022041SSam Saccone if (tids_entry) {
816*92022041SSam Saccone nla_nest_end(msg, tids_entry);
817*92022041SSam Saccone tids_num++;
818*92022041SSam Saccone }
819*92022041SSam Saccone
820*92022041SSam Saccone tids_entry = nla_nest_start(msg, tids_num);
821*92022041SSam Saccone if (!tids_entry)
822*92022041SSam Saccone return -ENOBUFS;
823*92022041SSam Saccone
824*92022041SSam Saccone NLA_PUT_U16(msg, NL80211_TID_CONFIG_ATTR_TIDS, strtol(argv[1], &end, 0));
825*92022041SSam Saccone if (*end) {
826*92022041SSam Saccone fprintf(stderr, "Invalid TID mask value: %s\n", argv[1]);
827*92022041SSam Saccone return 2;
828*92022041SSam Saccone }
829*92022041SSam Saccone
830*92022041SSam Saccone argc -= 2;
831*92022041SSam Saccone argv += 2;
832*92022041SSam Saccone parse_state = PS_CONF;
833*92022041SSam Saccone } else {
834*92022041SSam Saccone fprintf(stderr, "TID mask expected\n");
835*92022041SSam Saccone return HANDLER_RET_USAGE;
836*92022041SSam Saccone }
837*92022041SSam Saccone
838*92022041SSam Saccone break;
839*92022041SSam Saccone case PS_CONF:
840*92022041SSam Saccone if (strcmp(argv[0], "tids") == 0) {
841*92022041SSam Saccone parse_state = PS_TIDS;
842*92022041SSam Saccone } else if (strcmp(argv[0], "override") == 0) {
843*92022041SSam Saccone NLA_PUT_FLAG(msg, NL80211_TID_CONFIG_ATTR_OVERRIDE);
844*92022041SSam Saccone
845*92022041SSam Saccone argc -= 1;
846*92022041SSam Saccone argv += 1;
847*92022041SSam Saccone } else if (strcmp(argv[0], "ampdu") == 0) {
848*92022041SSam Saccone if (argc < 2) {
849*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
850*92022041SSam Saccone return HANDLER_RET_USAGE;
851*92022041SSam Saccone }
852*92022041SSam Saccone
853*92022041SSam Saccone ret = toggle_tid_param(argv[0], argv[1], msg,
854*92022041SSam Saccone NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
855*92022041SSam Saccone if (ret)
856*92022041SSam Saccone return ret;
857*92022041SSam Saccone
858*92022041SSam Saccone argc -= 2;
859*92022041SSam Saccone argv += 2;
860*92022041SSam Saccone } else if (strcmp(argv[0], "amsdu") == 0) {
861*92022041SSam Saccone if (argc < 2) {
862*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
863*92022041SSam Saccone return HANDLER_RET_USAGE;
864*92022041SSam Saccone }
865*92022041SSam Saccone
866*92022041SSam Saccone ret = toggle_tid_param(argv[0], argv[1], msg,
867*92022041SSam Saccone NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
868*92022041SSam Saccone if (ret)
869*92022041SSam Saccone return ret;
870*92022041SSam Saccone
871*92022041SSam Saccone argc -= 2;
872*92022041SSam Saccone argv += 2;
873*92022041SSam Saccone } else if (strcmp(argv[0], "noack") == 0) {
874*92022041SSam Saccone if (argc < 2) {
875*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
876*92022041SSam Saccone return HANDLER_RET_USAGE;
877*92022041SSam Saccone }
878*92022041SSam Saccone
879*92022041SSam Saccone ret = toggle_tid_param(argv[0], argv[1], msg,
880*92022041SSam Saccone NL80211_TID_CONFIG_ATTR_NOACK);
881*92022041SSam Saccone if (ret)
882*92022041SSam Saccone return ret;
883*92022041SSam Saccone
884*92022041SSam Saccone argc -= 2;
885*92022041SSam Saccone argv += 2;
886*92022041SSam Saccone } else if (strcmp(argv[0], "rtscts") == 0) {
887*92022041SSam Saccone if (argc < 2) {
888*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
889*92022041SSam Saccone return HANDLER_RET_USAGE;
890*92022041SSam Saccone }
891*92022041SSam Saccone
892*92022041SSam Saccone ret = toggle_tid_param(argv[0], argv[1], msg,
893*92022041SSam Saccone NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL);
894*92022041SSam Saccone if (ret)
895*92022041SSam Saccone return ret;
896*92022041SSam Saccone
897*92022041SSam Saccone argc -= 2;
898*92022041SSam Saccone argv += 2;
899*92022041SSam Saccone } else if (strcmp(argv[0], "sretry") == 0) {
900*92022041SSam Saccone if (argc < 2) {
901*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
902*92022041SSam Saccone return HANDLER_RET_USAGE;
903*92022041SSam Saccone }
904*92022041SSam Saccone
905*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT, strtol(argv[1], &end, 0));
906*92022041SSam Saccone if (*end) {
907*92022041SSam Saccone fprintf(stderr, "Invalid short_retry value: %s\n", argv[1]);
908*92022041SSam Saccone return 2;
909*92022041SSam Saccone }
910*92022041SSam Saccone
911*92022041SSam Saccone argc -= 2;
912*92022041SSam Saccone argv += 2;
913*92022041SSam Saccone } else if (strcmp(argv[0], "lretry") == 0) {
914*92022041SSam Saccone if (argc < 2) {
915*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
916*92022041SSam Saccone return HANDLER_RET_USAGE;
917*92022041SSam Saccone }
918*92022041SSam Saccone
919*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG, strtol(argv[1], &end, 0));
920*92022041SSam Saccone if (*end) {
921*92022041SSam Saccone fprintf(stderr, "Invalid long_retry value: %s\n", argv[1]);
922*92022041SSam Saccone return 2;
923*92022041SSam Saccone }
924*92022041SSam Saccone
925*92022041SSam Saccone argc -= 2;
926*92022041SSam Saccone argv += 2;
927*92022041SSam Saccone } else if (strcmp(argv[0], "bitrates") == 0) {
928*92022041SSam Saccone if (argc < 2) {
929*92022041SSam Saccone fprintf(stderr, "not enough args for %s\n", argv[0]);
930*92022041SSam Saccone return HANDLER_RET_USAGE;
931*92022041SSam Saccone }
932*92022041SSam Saccone if (!strcmp(argv[1], "auto"))
933*92022041SSam Saccone txrate_type = NL80211_TX_RATE_AUTOMATIC;
934*92022041SSam Saccone else if (!strcmp(argv[1], "fixed"))
935*92022041SSam Saccone txrate_type = NL80211_TX_RATE_FIXED;
936*92022041SSam Saccone else if (!strcmp(argv[1], "limit"))
937*92022041SSam Saccone txrate_type = NL80211_TX_RATE_LIMITED;
938*92022041SSam Saccone else {
939*92022041SSam Saccone printf("Invalid parameter: %s\n", argv[0]);
940*92022041SSam Saccone return 2;
941*92022041SSam Saccone }
942*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, txrate_type);
943*92022041SSam Saccone argc -= 2;
944*92022041SSam Saccone argv += 2;
945*92022041SSam Saccone if (txrate_type != NL80211_TX_RATE_AUTOMATIC) {
946*92022041SSam Saccone attr = NL80211_TID_CONFIG_ATTR_TX_RATE;
947*92022041SSam Saccone ret = set_bitrates(msg, argc, argv,
948*92022041SSam Saccone attr);
949*92022041SSam Saccone if (ret < 2)
950*92022041SSam Saccone return 1;
951*92022041SSam Saccone
952*92022041SSam Saccone argc -= ret;
953*92022041SSam Saccone argv += ret;
954*92022041SSam Saccone }
955*92022041SSam Saccone } else {
956*92022041SSam Saccone fprintf(stderr, "Unknown parameter: %s\n", argv[0]);
957*92022041SSam Saccone return HANDLER_RET_USAGE;
958*92022041SSam Saccone }
959*92022041SSam Saccone
960*92022041SSam Saccone break;
961*92022041SSam Saccone default:
962*92022041SSam Saccone fprintf(stderr, "Failed to parse: internal failure\n");
963*92022041SSam Saccone return HANDLER_RET_USAGE;
964*92022041SSam Saccone }
965*92022041SSam Saccone }
966*92022041SSam Saccone
967*92022041SSam Saccone if (tids_entry)
968*92022041SSam Saccone nla_nest_end(msg, tids_entry);
969*92022041SSam Saccone
970*92022041SSam Saccone if (tids_array)
971*92022041SSam Saccone nla_nest_end(msg, tids_array);
972*92022041SSam Saccone
973*92022041SSam Saccone return 0;
974*92022041SSam Saccone
975*92022041SSam Saccone nla_put_failure:
976*92022041SSam Saccone return -ENOBUFS;
977*92022041SSam Saccone }
978*92022041SSam Saccone
979*92022041SSam Saccone COMMAND(set, tidconf, "[peer <MAC address>] tids <mask> [override] [sretry <num>] [lretry <num>] "
980*92022041SSam Saccone "[ampdu [on|off]] [amsdu [on|off]] [noack [on|off]] [rtscts [on|off]]"
981*92022041SSam Saccone "[bitrates <type [auto|fixed|limit]> [legacy-<2.4|5> <legacy rate in Mbps>*] [ht-mcs-<2.4|5> <MCS index>*]"
982*92022041SSam Saccone " [vht-mcs-<2.4|5> <NSS:MCSx,MCSy... | NSS:MCSx-MCSy>*] [sgi-2.4|lgi-2.4] [sgi-5|lgi-5]]",
983*92022041SSam Saccone NL80211_CMD_SET_TID_CONFIG, 0, CIB_NETDEV, handle_tid_config,
984*92022041SSam Saccone "Setup per-node TID specific configuration for TIDs selected by bitmask.\n"
985*92022041SSam Saccone "If MAC address is not specified, then supplied TID configuration\n"
986*92022041SSam Saccone "applied to all the peers.\n"
987*92022041SSam Saccone "Examples:\n"
988*92022041SSam Saccone " $ iw dev wlan0 set tidconf tids 0x1 ampdu off\n"
989*92022041SSam Saccone " $ iw dev wlan0 set tidconf tids 0x5 ampdu off amsdu off rtscts on\n"
990*92022041SSam Saccone " $ iw dev wlan0 set tidconf tids 0x3 override ampdu on noack on rtscts on\n"
991*92022041SSam Saccone " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x1 ampdu off tids 0x3 amsdu off rtscts on\n"
992*92022041SSam Saccone " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates auto\n"
993*92022041SSam Saccone " $ iw dev wlan0 set tidconf peer xx:xx:xx:xx:xx:xx tids 0x2 bitrates limit vht-mcs-5 4:9\n"
994*92022041SSam Saccone );
995