]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
add event command
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 24 Oct 2008 18:24:44 +0000 (20:24 +0200)
committerJohannes Berg <johannes@sipsolutions.net>
Fri, 24 Oct 2008 18:24:44 +0000 (20:24 +0200)
This adds the 'event' command that listens for netlink
events on the 'config' multicast group.

Makefile
genl.c [new file with mode: 0644]
iw.c
iw.h

index 6a9010e045a1abcc044a6b332c565cce9099f33a..3fa0a83e2ab5a24a833e84f25dac075c6f14e3ba 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ CFLAGS += -O2 -g
 LDFLAGS += `pkg-config --libs libnl-1`
 NLVERSION = 1.0
 
-OBJS = iw.o info.o phy.o interface.o station.o util.o mpath.o reg.o mesh.o
+OBJS = iw.o info.o phy.o interface.o station.o util.o mpath.o reg.o mesh.o genl.o
 ALL = iw
 
 ifeq ($(V),1)
diff --git a/genl.c b/genl.c
new file mode 100644 (file)
index 0000000..0dff622
--- /dev/null
+++ b/genl.c
@@ -0,0 +1,120 @@
+/*
+ * This ought to be provided by libnl
+ */
+
+#include <asm/errno.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>  
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+                        void *arg)
+{
+       int *ret = arg;
+       *ret = err->error;
+       return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+       return NL_SKIP;
+}
+
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+       int *ret = arg;
+       *ret = 0;
+       return NL_STOP;
+}
+
+struct handler_args {
+       const char *group;
+       int id;
+};
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+       struct handler_args *grp = arg;
+       struct nlattr *tb[CTRL_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *mcgrp;
+       int rem_mcgrp;
+
+       nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+        if (!tb[CTRL_ATTR_MCAST_GROUPS])
+               return NL_SKIP;
+
+       nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
+               struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
+
+               nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
+                         nla_data(mcgrp), nla_len(mcgrp), NULL);
+
+               if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
+                   !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
+                       continue;
+               if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
+                           grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
+                       continue;
+               grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
+               break;
+       }
+       
+       return NL_SKIP;
+}
+
+int nl_get_multicast_id(struct nl_handle *handle, const char *family, const char *group)
+{
+       struct nl_msg *msg;
+       struct nl_cb *cb;
+       int ret, ctrlid;
+       struct handler_args grp = {
+               .group = group,
+               .id = -ENOENT,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!cb) {
+               ret = -ENOMEM;
+               goto out_fail_cb;
+       }
+
+       ctrlid = genl_ctrl_resolve(handle, "nlctrl");
+
+        genlmsg_put(msg, 0, 0, ctrlid, 0,
+                   0, CTRL_CMD_GETFAMILY, 0);
+
+       ret = -ENOBUFS;
+       NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+
+       ret = nl_send_auto_complete(handle, msg);
+       if (ret < 0)
+               goto out;
+
+       ret = 1;
+
+       nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
+       nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL);
+       nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp);
+
+       while (ret > 0)
+               nl_recvmsgs(handle, cb);
+
+       if (ret == 0)
+               ret = grp.id;
+ nla_put_failure:
+ out:
+       nl_cb_put(cb);
+ out_fail_cb:
+       nlmsg_free(msg);
+       return ret;
+}
diff --git a/iw.c b/iw.c
index e6d7232abccb37c38cf648fcdccf14e2e9c4dbb9..8e0ff178678abcb81cece6c8a748c4dc34b4f78f 100644 (file)
--- a/iw.c
+++ b/iw.c
@@ -85,6 +85,8 @@ 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");
+       fprintf(stderr, "\tevent\n");
        for (cmd = &__start___cmd; cmd < &__stop___cmd;
             cmd = (struct cmd *)((char *)cmd + cmd_size)) {
                if (!cmd->handler || cmd->hidden)
@@ -266,6 +268,62 @@ static int handle_cmd(struct nl80211_state *state,
        return 2;
 }
 
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+       return NL_OK;
+}
+
+static int print_event(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+                          
+       switch (gnlh->cmd) {
+       case NL80211_CMD_NEW_WIPHY: {
+               printf("wiphy rename: phy #%d to %s\n",
+                      nla_get_u32(tb[NL80211_ATTR_WIPHY]),
+                      nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
+               break;
+       }
+       }
+
+       return NL_SKIP;
+}
+
+static int listen_events(struct nl80211_state *state,
+                        int argc, char **argv)
+{
+       int mcid, ret;
+       struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+
+       if (!cb) {
+               fprintf(stderr, "failed to allocate netlink callbacks\n");
+               return -ENOMEM;
+       }
+
+       mcid = nl_get_multicast_id(state->nl_handle, "nl80211", "config");
+       if (mcid < 0)
+               return mcid;
+
+       ret = nl_socket_add_membership(state->nl_handle, mcid);
+       if (ret)
+               return ret;
+       
+       /* no sequence checking for multicast messages */
+       nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
+
+       while (1)
+               nl_recvmsgs(state->nl_handle, cb);
+
+       nl_cb_put(cb);
+
+       return 0;
+}
+
 int main(int argc, char **argv)
 {
        struct nl80211_state nlstate;
@@ -299,7 +357,9 @@ int main(int argc, char **argv)
        if (err)
                return 1;
 
-       if (strcmp(*argv, "dev") == 0) {
+       if (strcmp(*argv, "event") == 0) {
+               err = listen_events(&nlstate, argc, argv);
+       } else if (strcmp(*argv, "dev") == 0) {
                argc--;
                argv++;
                err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
diff --git a/iw.h b/iw.h
index 2a5be6f2ae768b54a422c016cdfff6b60d4dcc43..a69bd3098c72aabd917b82cdc8f0deb60b37c6c7 100644 (file)
--- a/iw.h
+++ b/iw.h
@@ -58,4 +58,6 @@ int mac_addr_n2a(char *mac_addr, unsigned char *arg);
 
 const char *iftype_name(enum nl80211_iftype iftype);
 
+int nl_get_multicast_id(struct nl_handle *handle, const char *family, const char *group);
+
 #endif /* __IW_H */