1*92022041SSam Saccone #include <stdbool.h>
2*92022041SSam Saccone #include <errno.h>
3*92022041SSam Saccone #include <strings.h>
4*92022041SSam Saccone #include <unistd.h>
5*92022041SSam Saccone #include <sys/param.h>
6*92022041SSam Saccone #include <sys/stat.h>
7*92022041SSam Saccone #include <fcntl.h>
8*92022041SSam Saccone
9*92022041SSam Saccone #include <netlink/genl/genl.h>
10*92022041SSam Saccone #include <netlink/genl/family.h>
11*92022041SSam Saccone #include <netlink/genl/ctrl.h>
12*92022041SSam Saccone #include <netlink/msg.h>
13*92022041SSam Saccone #include <netlink/attr.h>
14*92022041SSam Saccone
15*92022041SSam Saccone #include "nl80211.h"
16*92022041SSam Saccone #include "iw.h"
17*92022041SSam Saccone
18*92022041SSam Saccone struct channels_ctx {
19*92022041SSam Saccone int last_band;
20*92022041SSam Saccone bool width_40;
21*92022041SSam Saccone bool width_80;
22*92022041SSam Saccone bool width_160;
23*92022041SSam Saccone };
24*92022041SSam Saccone
dfs_state_name(enum nl80211_dfs_state state)25*92022041SSam Saccone static char *dfs_state_name(enum nl80211_dfs_state state)
26*92022041SSam Saccone {
27*92022041SSam Saccone switch (state) {
28*92022041SSam Saccone case NL80211_DFS_USABLE:
29*92022041SSam Saccone return "usable";
30*92022041SSam Saccone case NL80211_DFS_AVAILABLE:
31*92022041SSam Saccone return "available";
32*92022041SSam Saccone case NL80211_DFS_UNAVAILABLE:
33*92022041SSam Saccone return "unavailable";
34*92022041SSam Saccone default:
35*92022041SSam Saccone return "unknown";
36*92022041SSam Saccone }
37*92022041SSam Saccone }
38*92022041SSam Saccone
print_channels_handler(struct nl_msg * msg,void * arg)39*92022041SSam Saccone static int print_channels_handler(struct nl_msg *msg, void *arg)
40*92022041SSam Saccone {
41*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
42*92022041SSam Saccone struct channels_ctx *ctx = arg;
43*92022041SSam Saccone struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
44*92022041SSam Saccone struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
45*92022041SSam Saccone struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
46*92022041SSam Saccone struct nlattr *nl_band;
47*92022041SSam Saccone struct nlattr *nl_freq;
48*92022041SSam Saccone int rem_band, rem_freq;
49*92022041SSam Saccone
50*92022041SSam Saccone nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
51*92022041SSam Saccone
52*92022041SSam Saccone if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
53*92022041SSam Saccone nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
54*92022041SSam Saccone if (ctx->last_band != nl_band->nla_type) {
55*92022041SSam Saccone printf("Band %d:\n", nl_band->nla_type + 1);
56*92022041SSam Saccone ctx->width_40 = false;
57*92022041SSam Saccone ctx->width_80 = false;
58*92022041SSam Saccone ctx->width_160 = false;
59*92022041SSam Saccone ctx->last_band = nl_band->nla_type;
60*92022041SSam Saccone }
61*92022041SSam Saccone
62*92022041SSam Saccone nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL);
63*92022041SSam Saccone
64*92022041SSam Saccone if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
65*92022041SSam Saccone __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
66*92022041SSam Saccone
67*92022041SSam Saccone if (cap & BIT(1))
68*92022041SSam Saccone ctx->width_40 = true;
69*92022041SSam Saccone }
70*92022041SSam Saccone
71*92022041SSam Saccone if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
72*92022041SSam Saccone __u32 capa;
73*92022041SSam Saccone
74*92022041SSam Saccone ctx->width_80 = true;
75*92022041SSam Saccone
76*92022041SSam Saccone capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
77*92022041SSam Saccone switch ((capa >> 2) & 3) {
78*92022041SSam Saccone case 2:
79*92022041SSam Saccone /* width_80p80 = true; */
80*92022041SSam Saccone /* fall through */
81*92022041SSam Saccone case 1:
82*92022041SSam Saccone ctx->width_160 = true;
83*92022041SSam Saccone break;
84*92022041SSam Saccone }
85*92022041SSam Saccone }
86*92022041SSam Saccone
87*92022041SSam Saccone if (tb_band[NL80211_BAND_ATTR_FREQS]) {
88*92022041SSam Saccone nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
89*92022041SSam Saccone uint32_t freq;
90*92022041SSam Saccone
91*92022041SSam Saccone nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL);
92*92022041SSam Saccone
93*92022041SSam Saccone if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
94*92022041SSam Saccone continue;
95*92022041SSam Saccone freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
96*92022041SSam Saccone printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq));
97*92022041SSam Saccone
98*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
99*92022041SSam Saccone printf("(disabled)\n");
100*92022041SSam Saccone continue;
101*92022041SSam Saccone }
102*92022041SSam Saccone printf("\n");
103*92022041SSam Saccone
104*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
105*92022041SSam Saccone printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
106*92022041SSam Saccone
107*92022041SSam Saccone /* If both flags are set assume an new kernel */
108*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) {
109*92022041SSam Saccone printf("\t No IR\n");
110*92022041SSam Saccone } else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) {
111*92022041SSam Saccone printf("\t Passive scan\n");
112*92022041SSam Saccone } else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){
113*92022041SSam Saccone printf("\t No IBSS\n");
114*92022041SSam Saccone }
115*92022041SSam Saccone
116*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
117*92022041SSam Saccone printf("\t Radar detection\n");
118*92022041SSam Saccone
119*92022041SSam Saccone printf("\t Channel widths:");
120*92022041SSam Saccone if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
121*92022041SSam Saccone printf(" 20MHz");
122*92022041SSam Saccone if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
123*92022041SSam Saccone printf(" HT40-");
124*92022041SSam Saccone if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
125*92022041SSam Saccone printf(" HT40+");
126*92022041SSam Saccone if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
127*92022041SSam Saccone printf(" VHT80");
128*92022041SSam Saccone if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
129*92022041SSam Saccone printf(" VHT160");
130*92022041SSam Saccone printf("\n");
131*92022041SSam Saccone
132*92022041SSam Saccone if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
133*92022041SSam Saccone enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
134*92022041SSam Saccone unsigned long time;
135*92022041SSam Saccone
136*92022041SSam Saccone printf("\t DFS state: %s", dfs_state_name(state));
137*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) {
138*92022041SSam Saccone time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]);
139*92022041SSam Saccone printf(" (for %lu sec)", time / 1000);
140*92022041SSam Saccone }
141*92022041SSam Saccone printf("\n");
142*92022041SSam Saccone if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])
143*92022041SSam Saccone printf("\t DFS CAC time: %u ms\n",
144*92022041SSam Saccone nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]));
145*92022041SSam Saccone }
146*92022041SSam Saccone }
147*92022041SSam Saccone }
148*92022041SSam Saccone }
149*92022041SSam Saccone }
150*92022041SSam Saccone
151*92022041SSam Saccone return NL_SKIP;
152*92022041SSam Saccone }
153*92022041SSam Saccone
handle_channels(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)154*92022041SSam Saccone static int handle_channels(struct nl80211_state *state, struct nl_msg *msg,
155*92022041SSam Saccone int argc, char **argv, enum id_input id)
156*92022041SSam Saccone {
157*92022041SSam Saccone static struct channels_ctx ctx = {
158*92022041SSam Saccone .last_band = -1,
159*92022041SSam Saccone };
160*92022041SSam Saccone
161*92022041SSam Saccone nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
162*92022041SSam Saccone nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
163*92022041SSam Saccone
164*92022041SSam Saccone register_handler(print_channels_handler, &ctx);
165*92022041SSam Saccone
166*92022041SSam Saccone return 0;
167*92022041SSam Saccone }
168*92022041SSam Saccone TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
169*92022041SSam Saccone
handle_name(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)170*92022041SSam Saccone static int handle_name(struct nl80211_state *state,
171*92022041SSam Saccone struct nl_msg *msg,
172*92022041SSam Saccone int argc, char **argv,
173*92022041SSam Saccone enum id_input id)
174*92022041SSam Saccone {
175*92022041SSam Saccone if (argc != 1)
176*92022041SSam Saccone return 1;
177*92022041SSam Saccone
178*92022041SSam Saccone NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
179*92022041SSam Saccone
180*92022041SSam Saccone return 0;
181*92022041SSam Saccone nla_put_failure:
182*92022041SSam Saccone return -ENOBUFS;
183*92022041SSam Saccone }
184*92022041SSam Saccone COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
185*92022041SSam Saccone "Rename this wireless device.");
186*92022041SSam Saccone
handle_freq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)187*92022041SSam Saccone static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
188*92022041SSam Saccone int argc, char **argv,
189*92022041SSam Saccone enum id_input id)
190*92022041SSam Saccone {
191*92022041SSam Saccone struct chandef chandef;
192*92022041SSam Saccone int res;
193*92022041SSam Saccone
194*92022041SSam Saccone res = parse_freqchan(&chandef, false, argc, argv, NULL);
195*92022041SSam Saccone if (res)
196*92022041SSam Saccone return res;
197*92022041SSam Saccone
198*92022041SSam Saccone return put_chandef(msg, &chandef);
199*92022041SSam Saccone }
200*92022041SSam Saccone
201*92022041SSam Saccone COMMAND(set, freq,
202*92022041SSam Saccone "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
203*92022041SSam Saccone "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
204*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
205*92022041SSam Saccone "Set frequency/channel the hardware is using, including HT\n"
206*92022041SSam Saccone "configuration.");
207*92022041SSam Saccone COMMAND(set, freq,
208*92022041SSam Saccone "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
209*92022041SSam Saccone "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
210*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
211*92022041SSam Saccone
handle_chan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)212*92022041SSam Saccone static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
213*92022041SSam Saccone int argc, char **argv,
214*92022041SSam Saccone enum id_input id)
215*92022041SSam Saccone {
216*92022041SSam Saccone struct chandef chandef;
217*92022041SSam Saccone int res;
218*92022041SSam Saccone
219*92022041SSam Saccone res = parse_freqchan(&chandef, true, argc, argv, NULL);
220*92022041SSam Saccone if (res)
221*92022041SSam Saccone return res;
222*92022041SSam Saccone
223*92022041SSam Saccone return put_chandef(msg, &chandef);
224*92022041SSam Saccone }
225*92022041SSam Saccone COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
226*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
227*92022041SSam Saccone COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
228*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
229*92022041SSam Saccone
230*92022041SSam Saccone
231*92022041SSam Saccone struct cac_event {
232*92022041SSam Saccone int ret;
233*92022041SSam Saccone uint32_t freq;
234*92022041SSam Saccone };
235*92022041SSam Saccone
print_cac_event(struct nl_msg * msg,void * arg)236*92022041SSam Saccone static int print_cac_event(struct nl_msg *msg, void *arg)
237*92022041SSam Saccone {
238*92022041SSam Saccone struct nlattr *tb[NL80211_ATTR_MAX + 1];
239*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
240*92022041SSam Saccone enum nl80211_radar_event event_type;
241*92022041SSam Saccone struct cac_event *cac_event = arg;
242*92022041SSam Saccone uint32_t freq;
243*92022041SSam Saccone
244*92022041SSam Saccone if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
245*92022041SSam Saccone return NL_SKIP;
246*92022041SSam Saccone
247*92022041SSam Saccone nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
248*92022041SSam Saccone genlmsg_attrlen(gnlh, 0), NULL);
249*92022041SSam Saccone
250*92022041SSam Saccone if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
251*92022041SSam Saccone return NL_SKIP;
252*92022041SSam Saccone
253*92022041SSam Saccone freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
254*92022041SSam Saccone event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
255*92022041SSam Saccone if (freq != cac_event->freq)
256*92022041SSam Saccone return NL_SKIP;
257*92022041SSam Saccone
258*92022041SSam Saccone switch (event_type) {
259*92022041SSam Saccone case NL80211_RADAR_DETECTED:
260*92022041SSam Saccone printf("%d MHz: radar detected\n", freq);
261*92022041SSam Saccone break;
262*92022041SSam Saccone case NL80211_RADAR_CAC_FINISHED:
263*92022041SSam Saccone printf("%d MHz: CAC finished\n", freq);
264*92022041SSam Saccone break;
265*92022041SSam Saccone case NL80211_RADAR_CAC_ABORTED:
266*92022041SSam Saccone printf("%d MHz: CAC was aborted\n", freq);
267*92022041SSam Saccone break;
268*92022041SSam Saccone case NL80211_RADAR_NOP_FINISHED:
269*92022041SSam Saccone printf("%d MHz: NOP finished\n", freq);
270*92022041SSam Saccone break;
271*92022041SSam Saccone default:
272*92022041SSam Saccone printf("%d MHz: unknown radar event\n", freq);
273*92022041SSam Saccone }
274*92022041SSam Saccone cac_event->ret = 0;
275*92022041SSam Saccone
276*92022041SSam Saccone return NL_SKIP;
277*92022041SSam Saccone }
278*92022041SSam Saccone
handle_cac_trigger(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)279*92022041SSam Saccone static int handle_cac_trigger(struct nl80211_state *state,
280*92022041SSam Saccone struct nl_msg *msg,
281*92022041SSam Saccone int argc, char **argv,
282*92022041SSam Saccone enum id_input id)
283*92022041SSam Saccone {
284*92022041SSam Saccone struct chandef chandef;
285*92022041SSam Saccone int res;
286*92022041SSam Saccone
287*92022041SSam Saccone if (argc < 2)
288*92022041SSam Saccone return 1;
289*92022041SSam Saccone
290*92022041SSam Saccone if (strcmp(argv[0], "channel") == 0) {
291*92022041SSam Saccone res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL);
292*92022041SSam Saccone } else if (strcmp(argv[0], "freq") == 0) {
293*92022041SSam Saccone res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL);
294*92022041SSam Saccone } else {
295*92022041SSam Saccone return 1;
296*92022041SSam Saccone }
297*92022041SSam Saccone
298*92022041SSam Saccone if (res)
299*92022041SSam Saccone return res;
300*92022041SSam Saccone
301*92022041SSam Saccone return put_chandef(msg, &chandef);
302*92022041SSam Saccone }
303*92022041SSam Saccone
no_seq_check(struct nl_msg * msg,void * arg)304*92022041SSam Saccone static int no_seq_check(struct nl_msg *msg, void *arg)
305*92022041SSam Saccone {
306*92022041SSam Saccone return NL_OK;
307*92022041SSam Saccone }
308*92022041SSam Saccone
handle_cac(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)309*92022041SSam Saccone static int handle_cac(struct nl80211_state *state,
310*92022041SSam Saccone struct nl_msg *msg,
311*92022041SSam Saccone int argc, char **argv,
312*92022041SSam Saccone enum id_input id)
313*92022041SSam Saccone {
314*92022041SSam Saccone int err;
315*92022041SSam Saccone struct nl_cb *radar_cb;
316*92022041SSam Saccone struct chandef chandef;
317*92022041SSam Saccone struct cac_event cac_event;
318*92022041SSam Saccone char **cac_trigger_argv = NULL;
319*92022041SSam Saccone
320*92022041SSam Saccone radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
321*92022041SSam Saccone if (!radar_cb)
322*92022041SSam Saccone return 1;
323*92022041SSam Saccone
324*92022041SSam Saccone if (argc < 3)
325*92022041SSam Saccone return 1;
326*92022041SSam Saccone
327*92022041SSam Saccone if (strcmp(argv[2], "channel") == 0) {
328*92022041SSam Saccone err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL);
329*92022041SSam Saccone } else if (strcmp(argv[2], "freq") == 0) {
330*92022041SSam Saccone err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL);
331*92022041SSam Saccone } else {
332*92022041SSam Saccone err = 1;
333*92022041SSam Saccone }
334*92022041SSam Saccone if (err)
335*92022041SSam Saccone goto err_out;
336*92022041SSam Saccone
337*92022041SSam Saccone cac_trigger_argv = calloc(argc + 1, sizeof(char*));
338*92022041SSam Saccone if (!cac_trigger_argv) {
339*92022041SSam Saccone err = -ENOMEM;
340*92022041SSam Saccone goto err_out;
341*92022041SSam Saccone }
342*92022041SSam Saccone
343*92022041SSam Saccone cac_trigger_argv[0] = argv[0];
344*92022041SSam Saccone cac_trigger_argv[1] = "cac";
345*92022041SSam Saccone cac_trigger_argv[2] = "trigger";
346*92022041SSam Saccone memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
347*92022041SSam Saccone
348*92022041SSam Saccone err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
349*92022041SSam Saccone if (err)
350*92022041SSam Saccone goto err_out;
351*92022041SSam Saccone
352*92022041SSam Saccone cac_event.ret = 1;
353*92022041SSam Saccone cac_event.freq = chandef.control_freq;
354*92022041SSam Saccone
355*92022041SSam Saccone __prepare_listen_events(state);
356*92022041SSam Saccone nl_socket_set_cb(state->nl_sock, radar_cb);
357*92022041SSam Saccone
358*92022041SSam Saccone /* need to turn off sequence number checking */
359*92022041SSam Saccone nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
360*92022041SSam Saccone nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
361*92022041SSam Saccone while (cac_event.ret > 0)
362*92022041SSam Saccone nl_recvmsgs(state->nl_sock, radar_cb);
363*92022041SSam Saccone
364*92022041SSam Saccone err = 0;
365*92022041SSam Saccone err_out:
366*92022041SSam Saccone if (radar_cb)
367*92022041SSam Saccone nl_cb_put(radar_cb);
368*92022041SSam Saccone if (cac_trigger_argv)
369*92022041SSam Saccone free(cac_trigger_argv);
370*92022041SSam Saccone return err;
371*92022041SSam Saccone }
372*92022041SSam Saccone TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
373*92022041SSam Saccone "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
374*92022041SSam Saccone "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
375*92022041SSam Saccone 0, 0, CIB_NETDEV, handle_cac, NULL);
376*92022041SSam Saccone COMMAND(cac, trigger,
377*92022041SSam Saccone "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
378*92022041SSam Saccone "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
379*92022041SSam Saccone "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
380*92022041SSam Saccone NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
381*92022041SSam Saccone "Start or trigger a channel availability check (CAC) looking to look for\n"
382*92022041SSam Saccone "radars on the given channel.");
383*92022041SSam Saccone
handle_fragmentation(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)384*92022041SSam Saccone static int handle_fragmentation(struct nl80211_state *state,
385*92022041SSam Saccone struct nl_msg *msg,
386*92022041SSam Saccone int argc, char **argv,
387*92022041SSam Saccone enum id_input id)
388*92022041SSam Saccone {
389*92022041SSam Saccone unsigned int frag;
390*92022041SSam Saccone
391*92022041SSam Saccone if (argc != 1)
392*92022041SSam Saccone return 1;
393*92022041SSam Saccone
394*92022041SSam Saccone if (strcmp("off", argv[0]) == 0)
395*92022041SSam Saccone frag = -1;
396*92022041SSam Saccone else {
397*92022041SSam Saccone char *end;
398*92022041SSam Saccone
399*92022041SSam Saccone if (!*argv[0])
400*92022041SSam Saccone return 1;
401*92022041SSam Saccone frag = strtoul(argv[0], &end, 10);
402*92022041SSam Saccone if (*end != '\0')
403*92022041SSam Saccone return 1;
404*92022041SSam Saccone }
405*92022041SSam Saccone
406*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
407*92022041SSam Saccone
408*92022041SSam Saccone return 0;
409*92022041SSam Saccone nla_put_failure:
410*92022041SSam Saccone return -ENOBUFS;
411*92022041SSam Saccone }
412*92022041SSam Saccone COMMAND(set, frag, "<fragmentation threshold|off>",
413*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
414*92022041SSam Saccone "Set fragmentation threshold.");
415*92022041SSam Saccone
handle_rts(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)416*92022041SSam Saccone static int handle_rts(struct nl80211_state *state,
417*92022041SSam Saccone struct nl_msg *msg,
418*92022041SSam Saccone int argc, char **argv,
419*92022041SSam Saccone enum id_input id)
420*92022041SSam Saccone {
421*92022041SSam Saccone unsigned int rts;
422*92022041SSam Saccone
423*92022041SSam Saccone if (argc != 1)
424*92022041SSam Saccone return 1;
425*92022041SSam Saccone
426*92022041SSam Saccone if (strcmp("off", argv[0]) == 0)
427*92022041SSam Saccone rts = -1;
428*92022041SSam Saccone else {
429*92022041SSam Saccone char *end;
430*92022041SSam Saccone
431*92022041SSam Saccone if (!*argv[0])
432*92022041SSam Saccone return 1;
433*92022041SSam Saccone rts = strtoul(argv[0], &end, 10);
434*92022041SSam Saccone if (*end != '\0')
435*92022041SSam Saccone return 1;
436*92022041SSam Saccone }
437*92022041SSam Saccone
438*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
439*92022041SSam Saccone
440*92022041SSam Saccone return 0;
441*92022041SSam Saccone nla_put_failure:
442*92022041SSam Saccone return -ENOBUFS;
443*92022041SSam Saccone }
444*92022041SSam Saccone COMMAND(set, rts, "<rts threshold|off>",
445*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
446*92022041SSam Saccone "Set rts threshold.");
447*92022041SSam Saccone
handle_retry(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)448*92022041SSam Saccone static int handle_retry(struct nl80211_state *state,
449*92022041SSam Saccone struct nl_msg *msg,
450*92022041SSam Saccone int argc, char **argv, enum id_input id)
451*92022041SSam Saccone {
452*92022041SSam Saccone unsigned int retry_short = 0, retry_long = 0;
453*92022041SSam Saccone bool have_retry_s = false, have_retry_l = false;
454*92022041SSam Saccone int i;
455*92022041SSam Saccone enum {
456*92022041SSam Saccone S_NONE,
457*92022041SSam Saccone S_SHORT,
458*92022041SSam Saccone S_LONG,
459*92022041SSam Saccone } parser_state = S_NONE;
460*92022041SSam Saccone
461*92022041SSam Saccone if (!argc || (argc != 2 && argc != 4))
462*92022041SSam Saccone return 1;
463*92022041SSam Saccone
464*92022041SSam Saccone for (i = 0; i < argc; i++) {
465*92022041SSam Saccone char *end;
466*92022041SSam Saccone unsigned int tmpul;
467*92022041SSam Saccone
468*92022041SSam Saccone if (strcmp(argv[i], "short") == 0) {
469*92022041SSam Saccone if (have_retry_s)
470*92022041SSam Saccone return 1;
471*92022041SSam Saccone parser_state = S_SHORT;
472*92022041SSam Saccone have_retry_s = true;
473*92022041SSam Saccone } else if (strcmp(argv[i], "long") == 0) {
474*92022041SSam Saccone if (have_retry_l)
475*92022041SSam Saccone return 1;
476*92022041SSam Saccone parser_state = S_LONG;
477*92022041SSam Saccone have_retry_l = true;
478*92022041SSam Saccone } else {
479*92022041SSam Saccone tmpul = strtoul(argv[i], &end, 10);
480*92022041SSam Saccone if (*end != '\0')
481*92022041SSam Saccone return 1;
482*92022041SSam Saccone if (!tmpul || tmpul > 255)
483*92022041SSam Saccone return -EINVAL;
484*92022041SSam Saccone switch (parser_state) {
485*92022041SSam Saccone case S_SHORT:
486*92022041SSam Saccone retry_short = tmpul;
487*92022041SSam Saccone break;
488*92022041SSam Saccone case S_LONG:
489*92022041SSam Saccone retry_long = tmpul;
490*92022041SSam Saccone break;
491*92022041SSam Saccone default:
492*92022041SSam Saccone return 1;
493*92022041SSam Saccone }
494*92022041SSam Saccone }
495*92022041SSam Saccone }
496*92022041SSam Saccone
497*92022041SSam Saccone if (!have_retry_s && !have_retry_l)
498*92022041SSam Saccone return 1;
499*92022041SSam Saccone if (have_retry_s)
500*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
501*92022041SSam Saccone if (have_retry_l)
502*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
503*92022041SSam Saccone
504*92022041SSam Saccone return 0;
505*92022041SSam Saccone nla_put_failure:
506*92022041SSam Saccone return -ENOBUFS;
507*92022041SSam Saccone }
508*92022041SSam Saccone COMMAND(set, retry, "[short <limit>] [long <limit>]",
509*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
510*92022041SSam Saccone "Set retry limit.");
511*92022041SSam Saccone
512*92022041SSam Saccone #ifndef NETNS_RUN_DIR
513*92022041SSam Saccone #define NETNS_RUN_DIR "/var/run/netns"
514*92022041SSam Saccone #endif
netns_get_fd(const char * name)515*92022041SSam Saccone static int netns_get_fd(const char *name)
516*92022041SSam Saccone {
517*92022041SSam Saccone char pathbuf[MAXPATHLEN];
518*92022041SSam Saccone const char *path, *ptr;
519*92022041SSam Saccone
520*92022041SSam Saccone path = name;
521*92022041SSam Saccone ptr = strchr(name, '/');
522*92022041SSam Saccone if (!ptr) {
523*92022041SSam Saccone snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
524*92022041SSam Saccone NETNS_RUN_DIR, name );
525*92022041SSam Saccone path = pathbuf;
526*92022041SSam Saccone }
527*92022041SSam Saccone return open(path, O_RDONLY);
528*92022041SSam Saccone }
529*92022041SSam Saccone
handle_netns(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)530*92022041SSam Saccone static int handle_netns(struct nl80211_state *state,
531*92022041SSam Saccone struct nl_msg *msg,
532*92022041SSam Saccone int argc, char **argv,
533*92022041SSam Saccone enum id_input id)
534*92022041SSam Saccone {
535*92022041SSam Saccone char *end;
536*92022041SSam Saccone int fd = -1;
537*92022041SSam Saccone
538*92022041SSam Saccone if (argc < 1 || !*argv[0])
539*92022041SSam Saccone return 1;
540*92022041SSam Saccone
541*92022041SSam Saccone if (argc == 1) {
542*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_PID,
543*92022041SSam Saccone strtoul(argv[0], &end, 10));
544*92022041SSam Saccone if (*end != '\0') {
545*92022041SSam Saccone printf("Invalid parameter: pid(%s)\n", argv[0]);
546*92022041SSam Saccone return 1;
547*92022041SSam Saccone }
548*92022041SSam Saccone return 0;
549*92022041SSam Saccone }
550*92022041SSam Saccone
551*92022041SSam Saccone if (argc != 2 || strcmp(argv[0], "name"))
552*92022041SSam Saccone return 1;
553*92022041SSam Saccone
554*92022041SSam Saccone if ((fd = netns_get_fd(argv[1])) >= 0) {
555*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
556*92022041SSam Saccone return 0;
557*92022041SSam Saccone } else {
558*92022041SSam Saccone printf("Invalid parameter: nsname(%s)\n", argv[0]);
559*92022041SSam Saccone }
560*92022041SSam Saccone
561*92022041SSam Saccone return 1;
562*92022041SSam Saccone
563*92022041SSam Saccone nla_put_failure:
564*92022041SSam Saccone if (fd >= 0)
565*92022041SSam Saccone close(fd);
566*92022041SSam Saccone return -ENOBUFS;
567*92022041SSam Saccone }
568*92022041SSam Saccone COMMAND(set, netns, "{ <pid> | name <nsname> }",
569*92022041SSam Saccone NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
570*92022041SSam Saccone "Put this wireless device into a different network namespace:\n"
571*92022041SSam Saccone " <pid> - change network namespace by process id\n"
572*92022041SSam Saccone " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
573*92022041SSam Saccone " or by absolute path (man ip-netns)\n");
574*92022041SSam Saccone
handle_coverage(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)575*92022041SSam Saccone static int handle_coverage(struct nl80211_state *state,
576*92022041SSam Saccone struct nl_msg *msg,
577*92022041SSam Saccone int argc, char **argv,
578*92022041SSam Saccone enum id_input id)
579*92022041SSam Saccone {
580*92022041SSam Saccone char *end;
581*92022041SSam Saccone unsigned int coverage;
582*92022041SSam Saccone
583*92022041SSam Saccone if (argc != 1)
584*92022041SSam Saccone return 1;
585*92022041SSam Saccone
586*92022041SSam Saccone if (!*argv[0])
587*92022041SSam Saccone return 1;
588*92022041SSam Saccone coverage = strtoul(argv[0], &end, 10);
589*92022041SSam Saccone if (coverage > 255)
590*92022041SSam Saccone return 1;
591*92022041SSam Saccone
592*92022041SSam Saccone if (*end)
593*92022041SSam Saccone return 1;
594*92022041SSam Saccone
595*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
596*92022041SSam Saccone
597*92022041SSam Saccone return 0;
598*92022041SSam Saccone nla_put_failure:
599*92022041SSam Saccone return -ENOBUFS;
600*92022041SSam Saccone }
601*92022041SSam Saccone COMMAND(set, coverage, "<coverage class>",
602*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
603*92022041SSam Saccone "Set coverage class (1 for every 3 usec of air propagation time).\n"
604*92022041SSam Saccone "Valid values: 0 - 255.");
605*92022041SSam Saccone
handle_distance(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)606*92022041SSam Saccone static int handle_distance(struct nl80211_state *state,
607*92022041SSam Saccone struct nl_msg *msg,
608*92022041SSam Saccone int argc, char **argv,
609*92022041SSam Saccone enum id_input id)
610*92022041SSam Saccone {
611*92022041SSam Saccone if (argc != 1)
612*92022041SSam Saccone return 1;
613*92022041SSam Saccone
614*92022041SSam Saccone if (!*argv[0])
615*92022041SSam Saccone return 1;
616*92022041SSam Saccone
617*92022041SSam Saccone if (strcmp("auto", argv[0]) == 0) {
618*92022041SSam Saccone NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
619*92022041SSam Saccone } else {
620*92022041SSam Saccone char *end;
621*92022041SSam Saccone unsigned int distance, coverage;
622*92022041SSam Saccone
623*92022041SSam Saccone distance = strtoul(argv[0], &end, 10);
624*92022041SSam Saccone
625*92022041SSam Saccone if (*end)
626*92022041SSam Saccone return 1;
627*92022041SSam Saccone
628*92022041SSam Saccone /*
629*92022041SSam Saccone * Divide double the distance by the speed of light
630*92022041SSam Saccone * in m/usec (300) to get round-trip time in microseconds
631*92022041SSam Saccone * and then divide the result by three to get coverage class
632*92022041SSam Saccone * as specified in IEEE 802.11-2007 table 7-27.
633*92022041SSam Saccone * Values are rounded upwards.
634*92022041SSam Saccone */
635*92022041SSam Saccone coverage = (distance + 449) / 450;
636*92022041SSam Saccone if (coverage > 255)
637*92022041SSam Saccone return 1;
638*92022041SSam Saccone
639*92022041SSam Saccone NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
640*92022041SSam Saccone }
641*92022041SSam Saccone
642*92022041SSam Saccone return 0;
643*92022041SSam Saccone nla_put_failure:
644*92022041SSam Saccone return -ENOBUFS;
645*92022041SSam Saccone }
646*92022041SSam Saccone COMMAND(set, distance, "<auto|distance>",
647*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
648*92022041SSam Saccone "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
649*92022041SSam Saccone "coverage class for given link distance in meters.\n"
650*92022041SSam Saccone "To disable dynack set valid value for coverage class.\n"
651*92022041SSam Saccone "Valid values: 0 - 114750");
652*92022041SSam Saccone
handle_txpower(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)653*92022041SSam Saccone static int handle_txpower(struct nl80211_state *state,
654*92022041SSam Saccone struct nl_msg *msg,
655*92022041SSam Saccone int argc, char **argv,
656*92022041SSam Saccone enum id_input id)
657*92022041SSam Saccone {
658*92022041SSam Saccone enum nl80211_tx_power_setting type;
659*92022041SSam Saccone int mbm;
660*92022041SSam Saccone
661*92022041SSam Saccone /* get the required args */
662*92022041SSam Saccone if (argc != 1 && argc != 2)
663*92022041SSam Saccone return 1;
664*92022041SSam Saccone
665*92022041SSam Saccone if (!strcmp(argv[0], "auto"))
666*92022041SSam Saccone type = NL80211_TX_POWER_AUTOMATIC;
667*92022041SSam Saccone else if (!strcmp(argv[0], "fixed"))
668*92022041SSam Saccone type = NL80211_TX_POWER_FIXED;
669*92022041SSam Saccone else if (!strcmp(argv[0], "limit"))
670*92022041SSam Saccone type = NL80211_TX_POWER_LIMITED;
671*92022041SSam Saccone else {
672*92022041SSam Saccone printf("Invalid parameter: %s\n", argv[0]);
673*92022041SSam Saccone return 2;
674*92022041SSam Saccone }
675*92022041SSam Saccone
676*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
677*92022041SSam Saccone
678*92022041SSam Saccone if (type != NL80211_TX_POWER_AUTOMATIC) {
679*92022041SSam Saccone char *endptr;
680*92022041SSam Saccone if (argc != 2) {
681*92022041SSam Saccone printf("Missing TX power level argument.\n");
682*92022041SSam Saccone return 2;
683*92022041SSam Saccone }
684*92022041SSam Saccone
685*92022041SSam Saccone mbm = strtol(argv[1], &endptr, 10);
686*92022041SSam Saccone if (*endptr)
687*92022041SSam Saccone return 2;
688*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
689*92022041SSam Saccone } else if (argc != 1)
690*92022041SSam Saccone return 1;
691*92022041SSam Saccone
692*92022041SSam Saccone return 0;
693*92022041SSam Saccone
694*92022041SSam Saccone nla_put_failure:
695*92022041SSam Saccone return -ENOBUFS;
696*92022041SSam Saccone }
697*92022041SSam Saccone COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
698*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
699*92022041SSam Saccone "Specify transmit power level and setting type.");
700*92022041SSam Saccone COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
701*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
702*92022041SSam Saccone "Specify transmit power level and setting type.");
703*92022041SSam Saccone
handle_antenna(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)704*92022041SSam Saccone static int handle_antenna(struct nl80211_state *state,
705*92022041SSam Saccone struct nl_msg *msg,
706*92022041SSam Saccone int argc, char **argv,
707*92022041SSam Saccone enum id_input id)
708*92022041SSam Saccone {
709*92022041SSam Saccone char *end;
710*92022041SSam Saccone uint32_t tx_ant = 0, rx_ant = 0;
711*92022041SSam Saccone
712*92022041SSam Saccone if (argc == 1 && strcmp(argv[0], "all") == 0) {
713*92022041SSam Saccone tx_ant = 0xffffffff;
714*92022041SSam Saccone rx_ant = 0xffffffff;
715*92022041SSam Saccone } else if (argc == 1) {
716*92022041SSam Saccone tx_ant = rx_ant = strtoul(argv[0], &end, 0);
717*92022041SSam Saccone if (*end)
718*92022041SSam Saccone return 1;
719*92022041SSam Saccone }
720*92022041SSam Saccone else if (argc == 2) {
721*92022041SSam Saccone tx_ant = strtoul(argv[0], &end, 0);
722*92022041SSam Saccone if (*end)
723*92022041SSam Saccone return 1;
724*92022041SSam Saccone rx_ant = strtoul(argv[1], &end, 0);
725*92022041SSam Saccone if (*end)
726*92022041SSam Saccone return 1;
727*92022041SSam Saccone } else
728*92022041SSam Saccone return 1;
729*92022041SSam Saccone
730*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
731*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
732*92022041SSam Saccone
733*92022041SSam Saccone return 0;
734*92022041SSam Saccone
735*92022041SSam Saccone nla_put_failure:
736*92022041SSam Saccone return -ENOBUFS;
737*92022041SSam Saccone }
738*92022041SSam Saccone COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
739*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
740*92022041SSam Saccone "Set a bitmap of allowed antennas to use for TX and RX.\n"
741*92022041SSam Saccone "The driver may reject antenna configurations it cannot support.");
742*92022041SSam Saccone
handle_set_txq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)743*92022041SSam Saccone static int handle_set_txq(struct nl80211_state *state,
744*92022041SSam Saccone struct nl_msg *msg,
745*92022041SSam Saccone int argc, char **argv,
746*92022041SSam Saccone enum id_input id)
747*92022041SSam Saccone {
748*92022041SSam Saccone unsigned int argval;
749*92022041SSam Saccone char *end;
750*92022041SSam Saccone
751*92022041SSam Saccone if (argc != 2)
752*92022041SSam Saccone return 1;
753*92022041SSam Saccone
754*92022041SSam Saccone if (!*argv[0] || !*argv[1])
755*92022041SSam Saccone return 1;
756*92022041SSam Saccone
757*92022041SSam Saccone argval = strtoul(argv[1], &end, 10);
758*92022041SSam Saccone
759*92022041SSam Saccone if (*end)
760*92022041SSam Saccone return 1;
761*92022041SSam Saccone
762*92022041SSam Saccone if (!argval)
763*92022041SSam Saccone return 1;
764*92022041SSam Saccone
765*92022041SSam Saccone if (strcmp("limit", argv[0]) == 0)
766*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
767*92022041SSam Saccone else if (strcmp("memory_limit", argv[0]) == 0)
768*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
769*92022041SSam Saccone else if (strcmp("quantum", argv[0]) == 0)
770*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
771*92022041SSam Saccone else
772*92022041SSam Saccone return -1;
773*92022041SSam Saccone
774*92022041SSam Saccone return 0;
775*92022041SSam Saccone nla_put_failure:
776*92022041SSam Saccone return -ENOBUFS;
777*92022041SSam Saccone }
778*92022041SSam Saccone COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
779*92022041SSam Saccone NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
780*92022041SSam Saccone "Set TXQ parameters. The limit and memory_limit are global queue limits\n"
781*92022041SSam Saccone "for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
782*92022041SSam Saccone "Valid values: 1 - 2**32");
783*92022041SSam Saccone
print_txq_handler(struct nl_msg * msg,void * arg)784*92022041SSam Saccone static int print_txq_handler(struct nl_msg *msg, void *arg)
785*92022041SSam Saccone {
786*92022041SSam Saccone struct nlattr *attrs[NL80211_ATTR_MAX + 1];
787*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
788*92022041SSam Saccone struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
789*92022041SSam Saccone static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
790*92022041SSam Saccone [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
791*92022041SSam Saccone [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
792*92022041SSam Saccone [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
793*92022041SSam Saccone [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
794*92022041SSam Saccone [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
795*92022041SSam Saccone [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
796*92022041SSam Saccone };
797*92022041SSam Saccone
798*92022041SSam Saccone nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
799*92022041SSam Saccone genlmsg_attrlen(gnlh, 0), NULL);
800*92022041SSam Saccone
801*92022041SSam Saccone
802*92022041SSam Saccone if (attrs[NL80211_ATTR_TXQ_LIMIT])
803*92022041SSam Saccone printf("Packet limit:\t\t%u pkts\n",
804*92022041SSam Saccone nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
805*92022041SSam Saccone if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
806*92022041SSam Saccone printf("Memory limit:\t\t%u bytes\n",
807*92022041SSam Saccone nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
808*92022041SSam Saccone if (attrs[NL80211_ATTR_TXQ_QUANTUM])
809*92022041SSam Saccone printf("Quantum:\t\t%u bytes\n",
810*92022041SSam Saccone nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
811*92022041SSam Saccone
812*92022041SSam Saccone if (attrs[NL80211_ATTR_TXQ_STATS]) {
813*92022041SSam Saccone if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
814*92022041SSam Saccone attrs[NL80211_ATTR_TXQ_STATS],
815*92022041SSam Saccone txqstats_policy)) {
816*92022041SSam Saccone printf("failed to parse nested TXQ stats attributes!");
817*92022041SSam Saccone return 0;
818*92022041SSam Saccone }
819*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
820*92022041SSam Saccone if (txqinfo)
821*92022041SSam Saccone printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
822*92022041SSam Saccone
823*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
824*92022041SSam Saccone if (txqinfo)
825*92022041SSam Saccone printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
826*92022041SSam Saccone
827*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
828*92022041SSam Saccone if (txqinfo)
829*92022041SSam Saccone printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
830*92022041SSam Saccone
831*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
832*92022041SSam Saccone if (txqinfo)
833*92022041SSam Saccone printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
834*92022041SSam Saccone
835*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
836*92022041SSam Saccone if (txqinfo)
837*92022041SSam Saccone printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
838*92022041SSam Saccone txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
839*92022041SSam Saccone if (txqinfo)
840*92022041SSam Saccone printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
841*92022041SSam Saccone }
842*92022041SSam Saccone return NL_SKIP;
843*92022041SSam Saccone }
844*92022041SSam Saccone
handle_get_txq(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)845*92022041SSam Saccone static int handle_get_txq(struct nl80211_state *state,
846*92022041SSam Saccone struct nl_msg *msg,
847*92022041SSam Saccone int argc, char **argv,
848*92022041SSam Saccone enum id_input id)
849*92022041SSam Saccone {
850*92022041SSam Saccone nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
851*92022041SSam Saccone nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
852*92022041SSam Saccone register_handler(print_txq_handler, NULL);
853*92022041SSam Saccone return 0;
854*92022041SSam Saccone }
855*92022041SSam Saccone COMMAND(get, txq, "",
856*92022041SSam Saccone NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
857*92022041SSam Saccone "Get TXQ parameters.");
858