]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - iw.c
split out event handling code
[thirdparty/iw.git] / iw.c
diff --git a/iw.c b/iw.c
index f5fcc185d56d26b402801759908b5f1e1dc89c41..6cc82e886b0f5394a795c287e3d8170b3ecda731 100644 (file)
--- a/iw.c
+++ b/iw.c
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdbool.h>
                      
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>  
 #include <netlink/msg.h>
 #include <netlink/attr.h>
-#include <linux/nl80211.h>
 
+#include "nl80211.h"
 #include "iw.h"
-#include "version.h"
 
-int debug = 0;
+#ifndef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+       return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+       nl_handle_destroy(h);
+}
+
+static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
+{
+       struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
+       if (!tmp)
+               return -ENOMEM;
+       *cache = tmp;
+       return 0;
+}
+#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
+#endif /* CONFIG_LIBNL20 */
+
+int iw_debug = 0;
 
 static int nl80211_init(struct nl80211_state *state)
 {
        int err;
 
-       state->nl_handle = nl_handle_alloc();
-       if (!state->nl_handle) {
-               fprintf(stderr, "Failed to allocate netlink handle.\n");
+       state->nl_sock = nl_socket_alloc();
+       if (!state->nl_sock) {
+               fprintf(stderr, "Failed to allocate netlink socket.\n");
                return -ENOMEM;
        }
 
-       if (genl_connect(state->nl_handle)) {
+       if (genl_connect(state->nl_sock)) {
                fprintf(stderr, "Failed to connect to generic netlink.\n");
                err = -ENOLINK;
                goto out_handle_destroy;
        }
 
-       state->nl_cache = genl_ctrl_alloc_cache(state->nl_handle);
-       if (!state->nl_cache) {
+       if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
                fprintf(stderr, "Failed to allocate generic netlink cache.\n");
                err = -ENOMEM;
                goto out_handle_destroy;
@@ -60,7 +83,7 @@ static int nl80211_init(struct nl80211_state *state)
  out_cache_free:
        nl_cache_free(state->nl_cache);
  out_handle_destroy:
-       nl_handle_destroy(state->nl_handle);
+       nl_socket_free(state->nl_sock);
        return err;
 }
 
@@ -68,14 +91,35 @@ static void nl80211_cleanup(struct nl80211_state *state)
 {
        genl_family_put(state->nl80211);
        nl_cache_free(state->nl_cache);
-       nl_handle_destroy(state->nl_handle);
+       nl_socket_free(state->nl_sock);
 }
 
-__COMMAND(NULL, NULL, NULL, 0, 0, 0, CIB_NONE, NULL);
-__COMMAND(NULL, NULL, NULL, 1, 0, 0, CIB_NONE, NULL);
+__COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL);
+__COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL);
 
 static int cmd_size;
 
+static void usage_cmd(struct cmd *cmd)
+{
+       switch (cmd->idby) {
+       case CIB_NONE:
+               fprintf(stderr, "\t");
+               break;
+       case CIB_PHY:
+               fprintf(stderr, "\tphy <phyname> ");
+               break;
+       case CIB_NETDEV:
+               fprintf(stderr, "\tdev <devname> ");
+               break;
+       }
+       if (cmd->section)
+               fprintf(stderr, "%s ", cmd->section);
+       fprintf(stderr, "%s", cmd->name);
+       if (cmd->args)
+               fprintf(stderr, " %s", cmd->args);
+       fprintf(stderr, "\n");
+}
+
 static void usage(const char *argv0)
 {
        struct cmd *cmd;
@@ -85,35 +129,18 @@ static void usage(const char *argv0)
        fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
        fprintf(stderr, "\t--version\tshow version\n");
        fprintf(stderr, "Commands:\n");
+       fprintf(stderr, "\thelp\n");
        for (cmd = &__start___cmd; cmd < &__stop___cmd;
             cmd = (struct cmd *)((char *)cmd + cmd_size)) {
                if (!cmd->handler || cmd->hidden)
                        continue;
-               switch (cmd->idby) {
-               case CIB_NONE:
-                       fprintf(stderr, "\t");
-                       /* fall through */
-               case CIB_PHY:
-                       if (cmd->idby == CIB_PHY)
-                               fprintf(stderr, "\tphy <phyname> ");
-                       /* fall through */
-               case CIB_NETDEV:
-                       if (cmd->idby == CIB_NETDEV)
-                               fprintf(stderr, "\tdev <devname> ");
-                       if (cmd->section)
-                               fprintf(stderr, "%s ", cmd->section);
-                       fprintf(stderr, "%s", cmd->name);
-                       if (cmd->args)
-                               fprintf(stderr, " %s", cmd->args);
-                       fprintf(stderr, "\n");
-                       break;
-               }
+               usage_cmd(cmd);
        }
 }
 
 static void version(void)
 {
-       printf("iw version " IW_VERSION "\n");
+       printf("iw version %s\n", iw_version);
 }
 
 static int phy_lookup(char *name)
@@ -124,6 +151,8 @@ static int phy_lookup(char *name)
        snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
 
        fd = open(buf, O_RDONLY);
+       if (fd < 0)
+               return -1;
        pos = read(fd, buf, sizeof(buf) - 1);
        if (pos < 0)
                return -1;
@@ -141,6 +170,8 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
 
 static int finish_handler(struct nl_msg *msg, void *arg)
 {
+       int *ret = arg;
+       *ret = 0;
        return NL_SKIP;
 }
 
@@ -151,28 +182,44 @@ static int ack_handler(struct nl_msg *msg, void *arg)
        return NL_STOP;
 }
 
-static int handle_cmd(struct nl80211_state *state,
-                     enum command_identify_by idby,
-                     int argc, char **argv)
+int handle_cmd(struct nl80211_state *state, enum id_input idby,
+              int argc, char **argv)
 {
-       struct cmd *cmd;
-       struct nl_cb *cb = NULL;
+       struct cmd *cmd, *match = NULL;
+       struct nl_cb *cb;
        struct nl_msg *msg;
        int devidx = 0;
-       int err;
+       int err, o_argc;
        const char *command, *section;
+       char *tmp, **o_argv;
+       enum command_identify_by command_idby = CIB_NONE;
 
-       if (argc <= 1 && idby != CIB_NONE)
+       if (argc <= 1 && idby != II_NONE)
                return 1;
 
+       o_argc = argc;
+       o_argv = argv;
+
        switch (idby) {
-       case CIB_PHY:
+       case II_PHY_IDX:
+               command_idby = CIB_PHY;
+               devidx = strtoul(*argv + 4, &tmp, 0);
+               if (*tmp != '\0')
+                       return 1;
+               argc--;
+               argv++;
+               break;
+       case II_PHY_NAME:
+               command_idby = CIB_PHY;
                devidx = phy_lookup(*argv);
                argc--;
                argv++;
                break;
-       case CIB_NETDEV:
+       case II_NETDEV:
+               command_idby = CIB_NETDEV;
                devidx = if_nametoindex(*argv);
+               if (devidx == 0)
+                       devidx = -1;
                argc--;
                argv++;
                break;
@@ -180,6 +227,9 @@ static int handle_cmd(struct nl80211_state *state,
                break;
        }
 
+       if (devidx < 0)
+               return -errno;
+
        section = command = *argv;
        argc--;
        argv++;
@@ -188,15 +238,18 @@ static int handle_cmd(struct nl80211_state *state,
             cmd = (struct cmd *)((char *)cmd + cmd_size)) {
                if (!cmd->handler)
                        continue;
-               if (cmd->idby != idby)
+               if (cmd->idby != command_idby)
                        continue;
                if (cmd->section) {
                        if (strcmp(cmd->section, section))
                                continue;
                        /* this is a bit icky ... */
                        if (command == section) {
-                               if (argc <= 0)
+                               if (argc <= 0) {
+                                       if (match)
+                                               break;
                                        return 1;
+                               }
                                command = *argv;
                                argc--;
                                argv++;
@@ -207,19 +260,28 @@ static int handle_cmd(struct nl80211_state *state,
                        continue;
                if (argc && !cmd->args)
                        continue;
-               break;
+
+               match = cmd;
        }
 
-       if (cmd >= &__stop___cmd)
+       cmd = match;
+
+       if (!cmd)
                return 1;
 
+       if (!cmd->cmd) {
+               argc = o_argc;
+               argv = o_argv;
+               return cmd->handler(state, NULL, NULL, argc, argv);
+       }
+
        msg = nlmsg_alloc();
        if (!msg) {
                fprintf(stderr, "failed to allocate netlink message\n");
                return 2;
        }
 
-       cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+       cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
        if (!cb) {
                fprintf(stderr, "failed to allocate netlink callbacks\n");
                err = 2;
@@ -229,7 +291,7 @@ static int handle_cmd(struct nl80211_state *state,
        genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
                    cmd->nl_msg_flags, cmd->cmd, 0);
 
-       switch (idby) {
+       switch (command_idby) {
        case CIB_PHY:
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
                break;
@@ -240,19 +302,22 @@ static int handle_cmd(struct nl80211_state *state,
                break;
        }
 
-       err = cmd->handler(cb, msg, argc, argv);
+       err = cmd->handler(state, cb, msg, argc, argv);
        if (err)
                goto out;
 
-       err = nl_send_auto_complete(state->nl_handle, msg);
+       err = nl_send_auto_complete(state->nl_sock, msg);
        if (err < 0)
                goto out;
 
+       err = 1;
+
        nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
-       nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL);
+       nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
        nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
 
-       nl_recvmsgs(state->nl_handle, cb);
+       while (err > 0)
+               nl_recvmsgs(state->nl_sock, cb);
  out:
        nl_cb_put(cb);
  out_free_msg:
@@ -269,14 +334,15 @@ int main(int argc, char **argv)
        int err;
        const char *argv0;
 
-       cmd_size = abs((long)&__cmd_NULL_1_CIB_NONE_0
-                    - (long)&__cmd_NULL_0_CIB_NONE_0);
+       /* calculate command size including padding */
+       cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0
+                    - (long)&__cmd_NULL_NULL_0_CIB_NONE_0);
        /* strip off self */
        argc--;
        argv0 = *argv++;
 
        if (argc > 0 && strcmp(*argv, "--debug") == 0) {
-               debug = 1;
+               iw_debug = 1;
                argc--;
                argv++;
        }
@@ -295,16 +361,21 @@ int main(int argc, char **argv)
        if (err)
                return 1;
 
-       if (strcmp(*argv, "dev") == 0) {
-               argc--;
-               argv++;
-               err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
-       } else if (strcmp(*argv, "phy") == 0) {
+       if (strcmp(*argv, "dev") == 0 && argc > 1) {
                argc--;
                argv++;
-               err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
+               err = handle_cmd(&nlstate, II_NETDEV, argc, argv);
+       } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
+               if (strlen(*argv) == 3) {
+                       argc--;
+                       argv++;
+                       err = handle_cmd(&nlstate, II_PHY_NAME, argc, argv);
+               } else if (*(*argv + 3) == '#')
+                       err = handle_cmd(&nlstate, II_PHY_IDX, argc, argv);
+               else
+                       err = 1;
        } else
-               err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
+               err = handle_cmd(&nlstate, II_NONE, argc, argv);
 
        if (err == 1)
                usage(argv0);