X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=phy.c;h=c57a71f92eaf3799fb6cb93fa5f7f73e852539f7;hb=432b5ae2c87eb112464891e86b1306425f93dbfd;hp=aab462d2ed41b0285b5aef56b4cae09ace580d54;hpb=e642142d68850b7eb161489a984ec6817b10c51b;p=thirdparty%2Fiw.git diff --git a/phy.c b/phy.c index aab462d..c57a71f 100644 --- a/phy.c +++ b/phy.c @@ -1,7 +1,9 @@ #include #include -#include #include +#include +#include +#include #include #include @@ -12,8 +14,159 @@ #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) @@ -43,7 +196,7 @@ static int handle_freqs(struct nl_msg *msg, int argc, char **argv) { .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) @@ -102,7 +255,7 @@ static int handle_freqchan(struct nl_msg *msg, bool chan, }; unsigned int htval = NL80211_CHAN_NO_HT; unsigned int freq; - int i; + unsigned int i; if (!argc || argc > 4) return 1; @@ -141,8 +294,7 @@ static int handle_freqchan(struct nl_msg *msg, bool chan, 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) { @@ -156,8 +308,7 @@ COMMAND(set, freq, " [HT20|HT40+|HT40-]\n" " [20|40|80|80+80|160] [
] [
]", 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) { @@ -169,7 +320,7 @@ COMMAND(set, channel, " [HT20|HT40+|HT40-]", 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) { @@ -201,7 +352,7 @@ COMMAND(set, frag, "", "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) { @@ -233,7 +384,7 @@ COMMAND(set, rts, "", "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; @@ -296,36 +447,68 @@ COMMAND(set, retry, "[short ] [long ]", 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, "", +COMMAND(set, netns, "{ | name }", 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" + " - change network namespace by process id\n" + " - 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) @@ -357,7 +540,6 @@ COMMAND(set, coverage, "", "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) @@ -405,7 +587,6 @@ COMMAND(set, distance, "", "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) @@ -457,7 +638,6 @@ COMMAND(set, txpower, " []", "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)