]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
Add cac command to allow clearing channels
authorBenjamin Berg <benjamin.berg@open-mesh.com>
Mon, 7 Nov 2016 14:59:40 +0000 (15:59 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 16 Nov 2016 12:26:05 +0000 (13:26 +0100)
Allow the user to start a CAC for clearing DFS channels.

Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
phy.c

diff --git a/phy.c b/phy.c
index 266de4db591338a5fe4057df3e6b0985e96b3128..be31820afdfc47462db74b50b2a9257f17c967ce 100644 (file)
--- a/phy.c
+++ b/phy.c
@@ -226,6 +226,151 @@ COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
 COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
        NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
 
+
+struct cac_event {
+       int ret;
+       uint32_t freq;
+};
+
+static int print_cac_event(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       enum nl80211_radar_event event_type;
+       struct cac_event *cac_event = arg;
+       uint32_t freq;
+
+       if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
+               return NL_SKIP;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
+               return NL_SKIP;
+
+       freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+       event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+       if (freq != cac_event->freq)
+               return NL_SKIP;
+
+       switch (event_type) {
+       case NL80211_RADAR_DETECTED:
+               printf("%d MHz: radar detected\n", freq);
+               break;
+       case NL80211_RADAR_CAC_FINISHED:
+               printf("%d MHz: CAC finished\n", freq);
+               break;
+       case NL80211_RADAR_CAC_ABORTED:
+               printf("%d MHz: CAC was aborted\n", freq);
+               break;
+       case NL80211_RADAR_NOP_FINISHED:
+               printf("%d MHz: NOP finished\n", freq);
+               break;
+       default:
+               printf("%d MHz: unknown radar event\n", freq);
+       }
+       cac_event->ret = 0;
+
+       return NL_SKIP;
+}
+
+static int handle_cac_trigger(struct nl80211_state *state,
+                           struct nl_msg *msg,
+                           int argc, char **argv,
+                           enum id_input id)
+{
+       struct chandef chandef;
+       int res;
+
+       if (argc < 2)
+               return 1;
+
+       if (strcmp(argv[0], "channel") == 0) {
+               res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL);
+       } else if (strcmp(argv[0], "freq") == 0) {
+               res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL);
+       } else {
+               return 1;
+       }
+
+       if (res)
+               return res;
+
+       return put_chandef(msg, &chandef);
+}
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+       return NL_OK;
+}
+
+static int handle_cac(struct nl80211_state *state,
+                     struct nl_msg *msg,
+                     int argc, char **argv,
+                     enum id_input id)
+{
+       int err;
+       struct nl_cb *radar_cb;
+       struct chandef chandef;
+       struct cac_event cac_event;
+       char **cac_trigger_argv = NULL;
+
+       radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+       if (!radar_cb)
+               return 1;
+
+       if (argc < 3)
+               return 1;
+
+       if (strcmp(argv[2], "channel") == 0) {
+               err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL);
+       } else if (strcmp(argv[2], "freq") == 0) {
+               err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL);
+       } else {
+               return 1;
+       }
+
+       cac_trigger_argv = calloc(argc + 1, sizeof(char*));
+       if (!cac_trigger_argv)
+               return -ENOMEM;
+
+       cac_trigger_argv[0] = argv[0];
+       cac_trigger_argv[1] = "cac";
+       cac_trigger_argv[2] = "trigger";
+       memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
+
+       err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
+       free(cac_trigger_argv);
+       if (err)
+               return err;
+
+       cac_event.ret = 1;
+       cac_event.freq = chandef.control_freq;
+
+       __prepare_listen_events(state);
+       nl_socket_set_cb(state->nl_sock, radar_cb);
+
+       /* need to turn off sequence number checking */
+       nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+       nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
+       while (cac_event.ret > 0)
+               nl_recvmsgs(state->nl_sock, radar_cb);
+
+       return 0;
+}
+TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+             "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+             "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
+        0, 0, CIB_NETDEV, handle_cac, NULL);
+COMMAND(cac, trigger,
+       "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+       "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+       "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
+       NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
+       "Start or trigger a channel availability check (CAC) looking to look for\n"
+       "radars on the given channel.");
+
 static int handle_fragmentation(struct nl80211_state *state,
                                struct nl_msg *msg,
                                int argc, char **argv,