]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - phy.c
iw: display 5/10 MHz channel widths
[thirdparty/iw.git] / phy.c
diff --git a/phy.c b/phy.c
index aab462d2ed41b0285b5aef56b4cae09ace580d54..c57a71f92eaf3799fb6cb93fa5f7f73e852539f7 100644 (file)
--- a/phy.c
+++ b/phy.c
@@ -1,7 +1,9 @@
 #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)
@@ -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, "<freq> [HT20|HT40+|HT40-]\n"
                   "<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)
 {
@@ -169,7 +320,7 @@ COMMAND(set, channel, "<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, "<fragmentation threshold|off>",
        "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, "<rts threshold|off>",
        "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 <limit>] [long <limit>]",
        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)
@@ -357,7 +540,6 @@ COMMAND(set, coverage, "<coverage class>",
        "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, "<auto|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, "<auto|fixed|limit> [<tx power in mBm>]",
        "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)