]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - scan.c
iw: add extack support
[thirdparty/iw.git] / scan.c
diff --git a/scan.c b/scan.c
index bf39f34be3141a4de01922ae6443e0932e3ad51a..cb7c044a754b143c3af28dd668ebcf036a1a4d59 100644 (file)
--- a/scan.c
+++ b/scan.c
@@ -1,7 +1,6 @@
 #include <net/if.h>
 #include <errno.h>
 #include <string.h>
-#include <ctype.h>
 #include <stdbool.h>
 
 #include <netlink/genl/genl.h>
@@ -102,19 +101,21 @@ static int parse_random_mac_addr(struct nl_msg *msg, char *arg)
 int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
 {
        struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL;
-       struct nlattr *match = NULL;
+       struct nl_msg *scan_plans = NULL;
+       struct nlattr *match = NULL, *plan = NULL;
        enum {
                ND_TOPLEVEL,
                ND_MATCH,
                ND_FREQS,
                ND_ACTIVE,
+               ND_PLANS,
        } parse_state = ND_TOPLEVEL;
        int c  = *argc;
        char *end, **v = *argv;
        int err = 0, i = 0;
-       unsigned int freq, interval = 0, delay = 0;
+       unsigned int freq, interval = 0, delay = 0, iterations = 0;
        bool have_matchset = false, have_freqs = false, have_ssids = false;
-       bool have_active = false, have_passive = false;
+       bool have_active = false, have_passive = false, have_plans = false;
        uint32_t flags = 0;
 
        matchset = nlmsg_alloc();
@@ -135,6 +136,12 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
                goto out;
        }
 
+       scan_plans = nlmsg_alloc();
+       if (!scan_plans) {
+               err = -ENOBUFS;
+               goto out;
+       }
+
        while (c) {
                switch (parse_state) {
                case ND_TOPLEVEL:
@@ -145,7 +152,7 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
                                        goto nla_put_failure;
                                }
 
-                               if (interval) {
+                               if (interval || have_plans) {
                                        err = -EINVAL;
                                        goto nla_put_failure;
                                }
@@ -157,6 +164,15 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
                                NLA_PUT_U32(msg,
                                            NL80211_ATTR_SCHED_SCAN_INTERVAL,
                                            interval);
+                       } else if (!strcmp(v[0], "scan_plans")) {
+                               parse_state = ND_PLANS;
+                               if (have_plans || interval) {
+                                       err = -EINVAL;
+                                       goto nla_put_failure;
+                               }
+
+                               have_plans = true;
+                               i = 0;
                        } else if (!strcmp(v[0], "delay")) {
                                c--; v++;
                                if (c == 0) {
@@ -310,6 +326,47 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
                                parse_state = ND_TOPLEVEL;
                        }
                        break;
+               case ND_PLANS:
+                       iterations = 0;
+                       interval = strtoul(v[0], &end, 10);
+                       if (*end) {
+                               char *iter;
+
+                               if (*end != ':') {
+                                       err = -EINVAL;
+                                       goto nla_put_failure;
+                               }
+
+                               iter = ++end;
+                               iterations = strtoul(iter, &end, 10);
+                               if (*end || !iterations) {
+                                       err = -EINVAL;
+                                       goto nla_put_failure;
+                               }
+                       }
+
+                       plan = nla_nest_start(scan_plans, i + 1);
+                       if (!plan) {
+                               err = -ENOBUFS;
+                               goto nla_put_failure;
+                       }
+
+                       NLA_PUT_U32(scan_plans,
+                                   NL80211_SCHED_SCAN_PLAN_INTERVAL,
+                                   interval);
+
+                       if (iterations)
+                               NLA_PUT_U32(scan_plans,
+                                           NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+                                           iterations);
+                       else
+                               parse_state = ND_TOPLEVEL;
+
+                       nla_nest_end(scan_plans, plan);
+                       plan = NULL;
+                       i++;
+                       c--; v++;
+                       break;
                }
        }
 
@@ -321,6 +378,8 @@ int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
                nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
        if (have_matchset)
                nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, matchset);
+       if (have_plans)
+               nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_PLANS, scan_plans);
        if (flags)
                NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
 
@@ -329,6 +388,7 @@ nla_put_failure:
                nla_nest_end(msg, match);
        nlmsg_free(freqs);
        nlmsg_free(matchset);
+       nlmsg_free(scan_plans);
 
 out:
        *argc = c;
@@ -337,7 +397,6 @@ out:
 }
 
 static int handle_scan(struct nl80211_state *state,
-                      struct nl_cb *cb,
                       struct nl_msg *msg,
                       int argc, char **argv,
                       enum id_input id)
@@ -409,6 +468,8 @@ static int handle_scan(struct nl80211_state *state,
                                break;
                        }
                case DONE:
+                       nlmsg_free(ssids);
+                       nlmsg_free(freqs);
                        return 1;
                case FREQ:
                        freq = strtoul(argv[i], &eptr, 10);
@@ -445,8 +506,11 @@ static int handle_scan(struct nl80211_state *state,
 
        if (ies || meshid) {
                tmpies = (unsigned char *) malloc(ies_len + meshid_len);
-               if (!tmpies)
+               if (!tmpies) {
+                       free(ies);
+                       free(meshid);
                        goto nla_put_failure;
+               }
                if (ies) {
                        memcpy(tmpies, ies, ies_len);
                        free(ies);
@@ -455,7 +519,10 @@ static int handle_scan(struct nl80211_state *state,
                        memcpy(&tmpies[ies_len], meshid, meshid_len);
                        free(meshid);
                }
-               NLA_PUT(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies);
+               if (nla_put(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies) < 0) {
+                       free(tmpies);
+                       goto nla_put_failure;
+               }
                free(tmpies);
        }
 
@@ -1159,6 +1226,8 @@ static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *d
                        CAPA(46, "WNM-Notification");
                        CAPA(47, "Reserved");
                        CAPA(48, "UTF-8 SSID");
+                       CAPA(70, "FTM Responder");
+                       CAPA(71, "FTM Initiator");
                        default:
                                printf(" %d", bit);
                                break;
@@ -1911,6 +1980,12 @@ static int print_bss_handler(struct nl_msg *msg, void *arg)
        }
        printf("\n");
 
+       if (bss[NL80211_BSS_LAST_SEEN_BOOTTIME]) {
+               unsigned long long bt;
+               bt = (unsigned long long)nla_get_u64(bss[NL80211_BSS_LAST_SEEN_BOOTTIME]);
+               printf("\tlast seen: %llu.%.3llus [boottime]\n", bt/1000000000, (bt%1000000000)/1000000);
+       }
+
        if (bss[NL80211_BSS_TSF]) {
                unsigned long long tsf;
                tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
@@ -1970,7 +2045,6 @@ static int print_bss_handler(struct nl_msg *msg, void *arg)
 static struct scan_params scan_params;
 
 static int handle_scan_dump(struct nl80211_state *state,
-                           struct nl_cb *cb,
                            struct nl_msg *msg,
                            int argc, char **argv,
                            enum id_input id)
@@ -1987,13 +2061,12 @@ static int handle_scan_dump(struct nl80211_state *state,
 
        scan_params.type = PRINT_SCAN;
 
-       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
+       register_handler(print_bss_handler,
                  &scan_params);
        return 0;
 }
 
 static int handle_scan_combined(struct nl80211_state *state,
-                               struct nl_cb *cb,
                                struct nl_msg *msg,
                                int argc, char **argv,
                                enum id_input id)
@@ -2010,6 +2083,7 @@ static int handle_scan_combined(struct nl80211_state *state,
                NL80211_CMD_SCAN_ABORTED,
        };
        int trig_argc, dump_argc, err;
+       int i;
 
        if (argc >= 3 && !strcmp(argv[2], "-u")) {
                dump_argc = 4;
@@ -2027,7 +2101,7 @@ static int handle_scan_combined(struct nl80211_state *state,
        trig_argv[0] = argv[0];
        trig_argv[1] = "scan";
        trig_argv[2] = "trigger";
-       int i;
+
        for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
                trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
        err = handle_cmd(state, id, trig_argc, trig_argv);
@@ -2084,14 +2158,25 @@ COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>]
         "SSIDs (or wildcard if not given) unless passive scanning is requested.");
 
 
+static int handle_scan_abort(struct nl80211_state *state,
+                            struct nl_msg *msg,
+                            int argc, char **argv,
+                            enum id_input id)
+{
+       return 0;
+}
+COMMAND(scan, abort, "",
+       NL80211_CMD_ABORT_SCAN, 0, CIB_NETDEV, handle_scan_abort,
+       "Abort ongoing scan");
+
 static int handle_start_sched_scan(struct nl80211_state *state,
-                                  struct nl_cb *cb, struct nl_msg *msg,
+                                  struct nl_msg *msg,
                                   int argc, char **argv, enum id_input id)
 {
        return parse_sched_scan(msg, &argc, &argv);
 }
 
-static int handle_stop_sched_scan(struct nl80211_state *state, struct nl_cb *cb,
+static int handle_stop_sched_scan(struct nl80211_state *state,
                                  struct nl_msg *msg, int argc, char **argv,
                                  enum id_input id)
 {