]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
make connect able to wait
authorJohannes Berg <johannes@sipsolutions.net>
Wed, 8 Jul 2009 16:53:06 +0000 (18:53 +0200)
committerJohannes Berg <johannes@sipsolutions.net>
Wed, 8 Jul 2009 16:53:06 +0000 (18:53 +0200)
connect.c
event.c
iw.h

index 678d22181b5ab4dae7a7b07a0d08ee77ec424107..91be62ac16af68556eeadb2cfdb48573a758c955 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -9,10 +9,8 @@
 #include "nl80211.h"
 #include "iw.h"
 
-static int iw_connect(struct nl80211_state *state,
-                     struct nl_cb *cb,
-                     struct nl_msg *msg,
-                     int argc, char **argv)
+static int iw_conn(struct nl80211_state *state, struct nl_cb *cb,
+                  struct nl_msg *msg, int argc, char **argv)
 {
        char *end;
        unsigned char bssid[6];
@@ -69,6 +67,74 @@ static int disconnect(struct nl80211_state *state,
 TOPLEVEL(disconnect, NULL,
        NL80211_CMD_DISCONNECT, 0, CIB_NETDEV, disconnect,
        "Disconnect from the current network.");
-TOPLEVEL(connect, "<SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]",
-       NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_connect,
-       "Join the network with the given SSID (and frequency, BSSID).");
+HIDDEN(conn, establish, "", NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_conn);
+
+static int iw_connect(struct nl80211_state *state, struct nl_cb *cb,
+                     struct nl_msg *msg, int argc, char **argv)
+{
+       char **conn_argv, *dev = argv[0];
+       static const __u32 cmds[] = {
+               NL80211_CMD_CONNECT,
+       };
+       struct print_event_args printargs = { };
+       int conn_argc, err;
+       bool wait = false;
+       int i;
+
+       /* strip "wlan0 connect" */
+       argc -= 2;
+       argv += 2;
+
+       /* check -w */
+       if (argc && strcmp(argv[0], "-w") == 0) {
+               wait = true;
+               argc--;
+               argv++;
+       }
+
+       conn_argc = 3 + argc;
+       conn_argv = calloc(conn_argc, sizeof(*conn_argv));
+       if (!conn_argv)
+               return -ENOMEM;
+       conn_argv[0] = dev;
+       conn_argv[1] = "conn";
+       conn_argv[2] = "establish";
+       for (i = 0; i < argc; i++)
+               conn_argv[i + 3] = argv[i];
+       err = handle_cmd(state, II_NETDEV, conn_argc, conn_argv);
+       free(conn_argv);
+       if (err)
+               return err;
+
+       if (!wait)
+               return 0;
+
+       /*
+        * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
+        *
+        * This code has a bug, which requires creating a separate
+        * nl80211 socket to fix:
+        * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
+        * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
+        * before (!) we listen to it, because we only start listening
+        * after we send our scan request.
+        *
+        * Doing it the other way around has a race condition as well,
+        * if you first open the events socket you may get a notification
+        * for a previous scan.
+        *
+        * The only proper way to fix this would be to listen to events
+        * before sending the command, and for the kernel to send the
+        * connect request along with the event, so that you can match
+        * up whether the connect _you_ requested was finished or aborted.
+        *
+        * Alas, the kernel doesn't do that (yet).
+        */
+
+       __listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs);
+       return 0;
+}
+TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]",
+       0, 0, CIB_NETDEV, iw_connect,
+       "Join the network with the given SSID (and frequency, BSSID).\n"
+       "With -w, wait for the connect to finish or fail.");
diff --git a/event.c b/event.c
index c0475420d921fabf1ef49cdb7a42f08160e86fd2..26713312a3b80f283c07ffff2807bab1099dde31 100644 (file)
--- a/event.c
+++ b/event.c
@@ -9,10 +9,6 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
        return NL_OK;
 }
 
-struct print_event_args {
-       bool frame, time;
-};
-
 static void print_frame(struct print_event_args *args, struct nlattr *attr)
 {
        uint8_t *frame;
@@ -246,6 +242,7 @@ struct wait_event {
        int n_cmds;
        const __u32 *cmds;
        __u32 cmd;
+       struct print_event_args *pargs;
 };
 
 static int wait_event(struct nl_msg *msg, void *arg)
@@ -257,15 +254,17 @@ static int wait_event(struct nl_msg *msg, void *arg)
        for (i = 0; i < wait->n_cmds; i++) {
                if (gnlh->cmd == wait->cmds[i]) {
                        wait->cmd = gnlh->cmd;
+               if (wait->pargs)
+                       print_event(msg, wait->pargs);
                }
        }
 
        return NL_SKIP;
 }
 
-static __u32 __listen_events(struct nl80211_state *state,
-                            const int n_waits, const __u32 *waits,
-                            struct print_event_args *args)
+__u32 __listen_events(struct nl80211_state *state,
+                     const int n_waits, const __u32 *waits,
+                     struct print_event_args *args)
 {
        int mcid, ret;
        struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
@@ -315,10 +314,10 @@ static __u32 __listen_events(struct nl80211_state *state,
        if (n_waits && waits) {
                wait_ev.cmds = waits;
                wait_ev.n_cmds = n_waits;
+               wait_ev.pargs = args;
                nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
-       } else {
+       } else
                nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args);
-       }
 
        wait_ev.cmd = 0;
 
diff --git a/iw.h b/iw.h
index 69bb17c4b62e024dba43941a4d4271da3797a841..651e85c74cf0fa85dd26c436354041995c9daf3a 100644 (file)
--- a/iw.h
+++ b/iw.h
@@ -1,6 +1,7 @@
 #ifndef __IW_H
 #define __IW_H
 
+#include <stdbool.h>
 #include <netlink/netlink.h>
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
@@ -84,8 +85,16 @@ extern int iw_debug;
 
 int handle_cmd(struct nl80211_state *state, enum id_input idby,
               int argc, char **argv);
+
+struct print_event_args {
+       bool frame, time;
+};
+
 __u32 listen_events(struct nl80211_state *state,
                    const int n_waits, const __u32 *waits);
+__u32 __listen_events(struct nl80211_state *state,
+                     const int n_waits, const __u32 *waits,
+                     struct print_event_args *args);
 
 
 int mac_addr_a2n(unsigned char *mac_addr, char *arg);