#include <stdbool.h>
#include <errno.h>
-#include <net/if.h>
#include <strings.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include "nl80211.h"
#include "iw.h"
+struct channels_ctx {
+ int last_band;
+ bool width_40;
+ bool width_80;
+ bool width_160;
+};
+
+static char *dfs_state_name(enum nl80211_dfs_state state)
+{
+ switch (state) {
+ case NL80211_DFS_USABLE:
+ return "usable";
+ case NL80211_DFS_AVAILABLE:
+ return "available";
+ case NL80211_DFS_UNAVAILABLE:
+ return "unavailable";
+ default:
+ return "unknown";
+ }
+}
+
+static int print_channels_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct channels_ctx *ctx = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ int rem_band, rem_freq;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ if (ctx->last_band != nl_band->nla_type) {
+ printf("Band %d:\n", nl_band->nla_type + 1);
+ ctx->width_40 = false;
+ ctx->width_80 = false;
+ ctx->width_160 = false;
+ ctx->last_band = nl_band->nla_type;
+ }
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL);
+
+ if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
+ __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
+
+ if (cap & BIT(1))
+ ctx->width_40 = true;
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
+ __u32 capa;
+
+ ctx->width_80 = true;
+
+ capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+ switch ((capa >> 2) & 3) {
+ case 2:
+ /* width_80p80 = true; */
+ /* fall through */
+ case 1:
+ ctx->width_160 = true;
+ break;
+ }
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_FREQS]) {
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ uint32_t freq;
+
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL);
+
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq));
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
+ printf("(disabled)\n");
+ continue;
+ }
+ printf("\n");
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
+ printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
+
+ /* If both flags are set assume an new kernel */
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) {
+ printf("\t No IR\n");
+ } else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) {
+ printf("\t Passive scan\n");
+ } else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){
+ printf("\t No IBSS\n");
+ }
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ printf("\t Radar detection\n");
+
+ printf("\t Channel widths:");
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
+ printf(" 20MHz");
+ if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
+ printf(" HT40-");
+ if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
+ printf(" HT40+");
+ if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
+ printf(" VHT80");
+ if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
+ printf(" VHT160");
+ printf("\n");
+
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+ enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+ unsigned long time;
+
+ printf("\t DFS state: %s", dfs_state_name(state));
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) {
+ time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]);
+ printf(" (for %lu sec)", time / 1000);
+ }
+ printf("\n");
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])
+ printf("\t DFS CAC time: %u ms\n",
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]));
+ }
+ }
+ }
+ }
+ }
+
+ return NL_SKIP;
+}
+
+static int handle_channels(struct nl80211_state *state, struct nl_msg *msg,
+ int argc, char **argv, enum id_input id)
+{
+ static struct channels_ctx ctx = {
+ .last_band = -1,
+ };
+
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
+ nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
+
+ register_handler(print_channels_handler, &ctx);
+
+ return 0;
+}
+TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
+
static int handle_name(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{ .name = "160", .val = NL80211_CHAN_WIDTH_160, },
};
uint32_t freq;
- int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
+ unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
char *end;
if (argc < 1)
};
unsigned int htval = NL80211_CHAN_NO_HT;
unsigned int freq;
- int i;
+ unsigned int i;
if (!argc || argc > 4)
return 1;
return -ENOBUFS;
}
-static int handle_freq(struct nl80211_state *state,
- struct nl_cb *cb, struct nl_msg *msg,
+static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
"<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
-static int handle_chan(struct nl80211_state *state,
- struct nl_cb *cb, struct nl_msg *msg,
+static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
static int handle_fragmentation(struct nl80211_state *state,
- struct nl_cb *cb, struct nl_msg *msg,
+ struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
"Set fragmentation threshold.");
static int handle_rts(struct nl80211_state *state,
- struct nl_cb *cb, struct nl_msg *msg,
+ struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
"Set rts threshold.");
static int handle_retry(struct nl80211_state *state,
- struct nl_cb *cb, struct nl_msg *msg,
+ struct nl_msg *msg,
int argc, char **argv, enum id_input id)
{
unsigned int retry_short = 0, retry_long = 0;
NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
"Set retry limit.");
+#ifndef NETNS_RUN_DIR
+#define NETNS_RUN_DIR "/var/run/netns"
+#endif
+static int netns_get_fd(const char *name)
+{
+ char pathbuf[MAXPATHLEN];
+ const char *path, *ptr;
+
+ path = name;
+ ptr = strchr(name, '/');
+ if (!ptr) {
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+ NETNS_RUN_DIR, name );
+ path = pathbuf;
+ }
+ return open(path, O_RDONLY);
+}
+
static int handle_netns(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
char *end;
+ int fd;
- if (argc != 1)
+ if (argc < 1 || !*argv[0])
return 1;
- if (!*argv[0])
+ if (argc == 1) {
+ NLA_PUT_U32(msg, NL80211_ATTR_PID,
+ strtoul(argv[0], &end, 10));
+ if (*end != '\0') {
+ printf("Invalid parameter: pid(%s)\n", argv[0]);
+ return 1;
+ }
+ return 0;
+ }
+
+ if (argc != 2 || strcmp(argv[0], "name"))
return 1;
- NLA_PUT_U32(msg, NL80211_ATTR_PID,
- strtoul(argv[0], &end, 10));
+ if ((fd = netns_get_fd(argv[1])) >= 0) {
+ NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
+ return 0;
+ } else {
+ printf("Invalid parameter: nsname(%s)\n", argv[0]);
+ }
- if (*end != '\0')
- return 1;
+ return 1;
- return 0;
nla_put_failure:
return -ENOBUFS;
}
-COMMAND(set, netns, "<pid>",
+COMMAND(set, netns, "{ <pid> | name <nsname> }",
NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
- "Put this wireless device into a different network namespace");
+ "Put this wireless device into a different network namespace:\n"
+ " <pid> - change network namespace by process id\n"
+ " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
+ " or by absolute path (man ip-netns)\n");
static int handle_coverage(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
"Valid values: 0 - 255.");
static int handle_distance(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
"Valid values: 0 - 114750");
static int handle_txpower(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
"Specify transmit power level and setting type.");
static int handle_antenna(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)