8 #include <netlink/genl/genl.h>
9 #include <netlink/genl/family.h>
10 #include <netlink/genl/ctrl.h>
11 #include <netlink/msg.h>
12 #include <netlink/attr.h>
24 static char *dfs_state_name(enum nl80211_dfs_state state
)
27 case NL80211_DFS_USABLE
:
29 case NL80211_DFS_AVAILABLE
:
31 case NL80211_DFS_UNAVAILABLE
:
38 static int print_channels_handler(struct nl_msg
*msg
, void *arg
)
40 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
41 struct channels_ctx
*ctx
= arg
;
42 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
43 struct nlattr
*tb_band
[NL80211_BAND_ATTR_MAX
+ 1];
44 struct nlattr
*tb_freq
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
45 struct nlattr
*nl_band
;
46 struct nlattr
*nl_freq
;
47 int rem_band
, rem_freq
;
49 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0), genlmsg_attrlen(gnlh
, 0), NULL
);
51 if (tb_msg
[NL80211_ATTR_WIPHY_BANDS
]) {
52 nla_for_each_nested(nl_band
, tb_msg
[NL80211_ATTR_WIPHY_BANDS
], rem_band
) {
53 if (ctx
->last_band
!= nl_band
->nla_type
) {
54 printf("Band %d:\n", nl_band
->nla_type
+ 1);
55 ctx
->width_40
= false;
56 ctx
->width_80
= false;
57 ctx
->width_160
= false;
58 ctx
->last_band
= nl_band
->nla_type
;
61 nla_parse(tb_band
, NL80211_BAND_ATTR_MAX
, nla_data(nl_band
), nla_len(nl_band
), NULL
);
63 if (tb_band
[NL80211_BAND_ATTR_HT_CAPA
]) {
64 __u16 cap
= nla_get_u16(tb_band
[NL80211_BAND_ATTR_HT_CAPA
]);
70 if (tb_band
[NL80211_BAND_ATTR_VHT_CAPA
]) {
75 capa
= nla_get_u32(tb_band
[NL80211_BAND_ATTR_VHT_CAPA
]);
76 switch ((capa
>> 2) & 3) {
78 /* width_80p80 = true; */
81 ctx
->width_160
= true;
86 if (tb_band
[NL80211_BAND_ATTR_FREQS
]) {
87 nla_for_each_nested(nl_freq
, tb_band
[NL80211_BAND_ATTR_FREQS
], rem_freq
) {
90 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
, nla_data(nl_freq
), nla_len(nl_freq
), NULL
);
92 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
94 freq
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
]);
95 printf("\t* %d MHz [%d] ", freq
, ieee80211_frequency_to_channel(freq
));
97 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
]) {
98 printf("(disabled)\n");
103 if (tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
])
104 printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
]));
106 /* If both flags are set assume an new kernel */
107 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_IR
] && tb_freq
[__NL80211_FREQUENCY_ATTR_NO_IBSS
]) {
108 printf("\t No IR\n");
109 } else if (tb_freq
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
]) {
110 printf("\t Passive scan\n");
111 } else if (tb_freq
[__NL80211_FREQUENCY_ATTR_NO_IBSS
]){
112 printf("\t No IBSS\n");
115 if (tb_freq
[NL80211_FREQUENCY_ATTR_RADAR
])
116 printf("\t Radar detection\n");
118 printf("\t Channel widths:");
119 if (!tb_freq
[NL80211_FREQUENCY_ATTR_NO_20MHZ
])
121 if (ctx
->width_40
&& !tb_freq
[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS
])
123 if (ctx
->width_40
&& !tb_freq
[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS
])
125 if (ctx
->width_80
&& !tb_freq
[NL80211_FREQUENCY_ATTR_NO_80MHZ
])
127 if (ctx
->width_160
&& !tb_freq
[NL80211_FREQUENCY_ATTR_NO_160MHZ
])
131 if (!tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
] && tb_freq
[NL80211_FREQUENCY_ATTR_DFS_STATE
]) {
132 enum nl80211_dfs_state state
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_DFS_STATE
]);
135 printf("\t DFS state: %s", dfs_state_name(state
));
136 if (tb_freq
[NL80211_FREQUENCY_ATTR_DFS_TIME
]) {
137 time
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_DFS_TIME
]);
138 printf(" (for %lu sec)", time
/ 1000);
141 if (tb_freq
[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME
])
142 printf("\t DFS CAC time: %u ms\n",
143 nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME
]));
153 static int handle_channels(struct nl80211_state
*state
, struct nl_msg
*msg
,
154 int argc
, char **argv
, enum id_input id
)
156 static struct channels_ctx ctx
= {
160 nla_put_flag(msg
, NL80211_ATTR_SPLIT_WIPHY_DUMP
);
161 nlmsg_hdr(msg
)->nlmsg_flags
|= NLM_F_DUMP
;
163 register_handler(print_channels_handler
, &ctx
);
167 TOPLEVEL(channels
, NULL
, NL80211_CMD_GET_WIPHY
, 0, CIB_PHY
, handle_channels
, "Show available channels.");
169 static int handle_name(struct nl80211_state
*state
,
171 int argc
, char **argv
,
177 NLA_PUT_STRING(msg
, NL80211_ATTR_WIPHY_NAME
, *argv
);
183 COMMAND(set
, name
, "<new name>", NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_name
,
184 "Rename this wireless device.");
186 static int handle_freqs(struct nl_msg
*msg
, int argc
, char **argv
)
188 static const struct {
192 { .name
= "20", .val
= NL80211_CHAN_WIDTH_20
, },
193 { .name
= "40", .val
= NL80211_CHAN_WIDTH_40
, },
194 { .name
= "80", .val
= NL80211_CHAN_WIDTH_80
, },
195 { .name
= "80+80", .val
= NL80211_CHAN_WIDTH_80P80
, },
196 { .name
= "160", .val
= NL80211_CHAN_WIDTH_160
, },
199 unsigned int i
, bwval
= NL80211_CHAN_WIDTH_20_NOHT
;
205 for (i
= 0; i
< ARRAY_SIZE(bwmap
); i
++) {
206 if (strcasecmp(bwmap
[i
].name
, argv
[0]) == 0) {
207 bwval
= bwmap
[i
].val
;
212 if (bwval
== NL80211_CHAN_WIDTH_20_NOHT
)
215 NLA_PUT_U32(msg
, NL80211_ATTR_CHANNEL_WIDTH
, bwval
);
223 freq
= strtoul(argv
[1], &end
, 10);
226 NLA_PUT_U32(msg
, NL80211_ATTR_CENTER_FREQ1
, freq
);
234 freq
= strtoul(argv
[2], &end
, 10);
237 NLA_PUT_U32(msg
, NL80211_ATTR_CENTER_FREQ2
, freq
);
244 static int handle_freqchan(struct nl_msg
*msg
, bool chan
,
245 int argc
, char **argv
)
248 static const struct {
252 { .name
= "HT20", .val
= NL80211_CHAN_HT20
, },
253 { .name
= "HT40+", .val
= NL80211_CHAN_HT40PLUS
, },
254 { .name
= "HT40-", .val
= NL80211_CHAN_HT40MINUS
, },
256 unsigned int htval
= NL80211_CHAN_NO_HT
;
260 if (!argc
|| argc
> 4)
265 freq
= strtoul(argv
[0], &end
, 10);
270 enum nl80211_band band
;
271 band
= freq
<= 14 ? NL80211_BAND_2GHZ
: NL80211_BAND_5GHZ
;
272 freq
= ieee80211_channel_to_frequency(freq
, band
);
275 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_FREQ
, freq
);
278 return handle_freqs(msg
, argc
- 1, argv
+ 1);
279 } else if (argc
== 2) {
280 for (i
= 0; i
< ARRAY_SIZE(htmap
); i
++) {
281 if (strcasecmp(htmap
[i
].name
, argv
[1]) == 0) {
282 htval
= htmap
[i
].val
;
286 if (htval
== NL80211_CHAN_NO_HT
)
287 return handle_freqs(msg
, argc
- 1, argv
+ 1);
290 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_CHANNEL_TYPE
, htval
);
297 static int handle_freq(struct nl80211_state
*state
, struct nl_msg
*msg
,
298 int argc
, char **argv
,
301 return handle_freqchan(msg
, false, argc
, argv
);
303 COMMAND(set
, freq
, "<freq> [HT20|HT40+|HT40-]",
304 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_freq
,
305 "Set frequency/channel the hardware is using, including HT\n"
307 COMMAND(set
, freq
, "<freq> [HT20|HT40+|HT40-]\n"
308 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
309 NL80211_CMD_SET_WIPHY
, 0, CIB_NETDEV
, handle_freq
, NULL
);
311 static int handle_chan(struct nl80211_state
*state
, struct nl_msg
*msg
,
312 int argc
, char **argv
,
315 return handle_freqchan(msg
, true, argc
, argv
);
317 COMMAND(set
, channel
, "<channel> [HT20|HT40+|HT40-]",
318 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_chan
, NULL
);
319 COMMAND(set
, channel
, "<channel> [HT20|HT40+|HT40-]",
320 NL80211_CMD_SET_WIPHY
, 0, CIB_NETDEV
, handle_chan
, NULL
);
322 static int handle_fragmentation(struct nl80211_state
*state
,
324 int argc
, char **argv
,
332 if (strcmp("off", argv
[0]) == 0)
339 frag
= strtoul(argv
[0], &end
, 10);
344 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_FRAG_THRESHOLD
, frag
);
350 COMMAND(set
, frag
, "<fragmentation threshold|off>",
351 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_fragmentation
,
352 "Set fragmentation threshold.");
354 static int handle_rts(struct nl80211_state
*state
,
356 int argc
, char **argv
,
364 if (strcmp("off", argv
[0]) == 0)
371 rts
= strtoul(argv
[0], &end
, 10);
376 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_RTS_THRESHOLD
, rts
);
382 COMMAND(set
, rts
, "<rts threshold|off>",
383 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_rts
,
384 "Set rts threshold.");
386 static int handle_retry(struct nl80211_state
*state
,
388 int argc
, char **argv
, enum id_input id
)
390 unsigned int retry_short
= 0, retry_long
= 0;
391 bool have_retry_s
= false, have_retry_l
= false;
397 } parser_state
= S_NONE
;
399 if (!argc
|| (argc
!= 2 && argc
!= 4))
402 for (i
= 0; i
< argc
; i
++) {
406 if (strcmp(argv
[i
], "short") == 0) {
409 parser_state
= S_SHORT
;
411 } else if (strcmp(argv
[i
], "long") == 0) {
414 parser_state
= S_LONG
;
417 tmpul
= strtoul(argv
[i
], &end
, 10);
420 if (!tmpul
|| tmpul
> 255)
422 switch (parser_state
) {
435 if (!have_retry_s
&& !have_retry_l
)
438 NLA_PUT_U8(msg
, NL80211_ATTR_WIPHY_RETRY_SHORT
, retry_short
);
440 NLA_PUT_U8(msg
, NL80211_ATTR_WIPHY_RETRY_LONG
, retry_long
);
446 COMMAND(set
, retry
, "[short <limit>] [long <limit>]",
447 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_retry
,
450 #ifndef NETNS_RUN_DIR
451 #define NETNS_RUN_DIR "/var/run/netns"
453 static int netns_get_fd(const char *name
)
455 char pathbuf
[MAXPATHLEN
];
456 const char *path
, *ptr
;
459 ptr
= strchr(name
, '/');
461 snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
462 NETNS_RUN_DIR
, name
);
465 return open(path
, O_RDONLY
);
468 static int handle_netns(struct nl80211_state
*state
,
470 int argc
, char **argv
,
476 if (argc
< 1 || !*argv
[0])
480 NLA_PUT_U32(msg
, NL80211_ATTR_PID
,
481 strtoul(argv
[0], &end
, 10));
483 printf("Invalid parameter: pid(%s)\n", argv
[0]);
489 if (argc
!= 2 || strcmp(argv
[0], "name"))
492 if ((fd
= netns_get_fd(argv
[1])) >= 0) {
493 NLA_PUT_U32(msg
, NL80211_ATTR_NETNS_FD
, fd
);
496 printf("Invalid parameter: nsname(%s)\n", argv
[0]);
504 COMMAND(set
, netns
, "{ <pid> | name <nsname> }",
505 NL80211_CMD_SET_WIPHY_NETNS
, 0, CIB_PHY
, handle_netns
,
506 "Put this wireless device into a different network namespace:\n"
507 " <pid> - change network namespace by process id\n"
508 " <nsname> - change network namespace by name from "NETNS_RUN_DIR
"\n"
509 " or by absolute path (man ip-netns)\n");
511 static int handle_coverage(struct nl80211_state
*state
,
513 int argc
, char **argv
,
517 unsigned int coverage
;
524 coverage
= strtoul(argv
[0], &end
, 10);
531 NLA_PUT_U8(msg
, NL80211_ATTR_WIPHY_COVERAGE_CLASS
, coverage
);
537 COMMAND(set
, coverage
, "<coverage class>",
538 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_coverage
,
539 "Set coverage class (1 for every 3 usec of air propagation time).\n"
540 "Valid values: 0 - 255.");
542 static int handle_distance(struct nl80211_state
*state
,
544 int argc
, char **argv
,
553 if (strcmp("auto", argv
[0]) == 0) {
554 NLA_PUT_FLAG(msg
, NL80211_ATTR_WIPHY_DYN_ACK
);
557 unsigned int distance
, coverage
;
559 distance
= strtoul(argv
[0], &end
, 10);
565 * Divide double the distance by the speed of light
566 * in m/usec (300) to get round-trip time in microseconds
567 * and then divide the result by three to get coverage class
568 * as specified in IEEE 802.11-2007 table 7-27.
569 * Values are rounded upwards.
571 coverage
= (distance
+ 449) / 450;
575 NLA_PUT_U8(msg
, NL80211_ATTR_WIPHY_COVERAGE_CLASS
, coverage
);
582 COMMAND(set
, distance
, "<auto|distance>",
583 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_distance
,
584 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
585 "coverage class for given link distance in meters.\n"
586 "To disable dynack set valid value for coverage class.\n"
587 "Valid values: 0 - 114750");
589 static int handle_txpower(struct nl80211_state
*state
,
591 int argc
, char **argv
,
594 enum nl80211_tx_power_setting type
;
597 /* get the required args */
598 if (argc
!= 1 && argc
!= 2)
601 if (!strcmp(argv
[0], "auto"))
602 type
= NL80211_TX_POWER_AUTOMATIC
;
603 else if (!strcmp(argv
[0], "fixed"))
604 type
= NL80211_TX_POWER_FIXED
;
605 else if (!strcmp(argv
[0], "limit"))
606 type
= NL80211_TX_POWER_LIMITED
;
608 printf("Invalid parameter: %s\n", argv
[0]);
612 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_TX_POWER_SETTING
, type
);
614 if (type
!= NL80211_TX_POWER_AUTOMATIC
) {
617 printf("Missing TX power level argument.\n");
621 mbm
= strtol(argv
[1], &endptr
, 10);
624 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_TX_POWER_LEVEL
, mbm
);
625 } else if (argc
!= 1)
633 COMMAND(set
, txpower
, "<auto|fixed|limit> [<tx power in mBm>]",
634 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_txpower
,
635 "Specify transmit power level and setting type.");
636 COMMAND(set
, txpower
, "<auto|fixed|limit> [<tx power in mBm>]",
637 NL80211_CMD_SET_WIPHY
, 0, CIB_NETDEV
, handle_txpower
,
638 "Specify transmit power level and setting type.");
640 static int handle_antenna(struct nl80211_state
*state
,
642 int argc
, char **argv
,
646 uint32_t tx_ant
= 0, rx_ant
= 0;
648 if (argc
== 1 && strcmp(argv
[0], "all") == 0) {
651 } else if (argc
== 1) {
652 tx_ant
= rx_ant
= strtoul(argv
[0], &end
, 0);
656 else if (argc
== 2) {
657 tx_ant
= strtoul(argv
[0], &end
, 0);
660 rx_ant
= strtoul(argv
[1], &end
, 0);
666 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_ANTENNA_TX
, tx_ant
);
667 NLA_PUT_U32(msg
, NL80211_ATTR_WIPHY_ANTENNA_RX
, rx_ant
);
674 COMMAND(set
, antenna
, "<bitmap> | all | <tx bitmap> <rx bitmap>",
675 NL80211_CMD_SET_WIPHY
, 0, CIB_PHY
, handle_antenna
,
676 "Set a bitmap of allowed antennas to use for TX and RX.\n"
677 "The driver may reject antenna configurations it cannot support.");