summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky.perez-gonzalez>2008-12-05 10:36:28 -0800
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2008-12-05 10:36:28 -0800
commitdb3556cf952c4b319afbaa9f5179d109e628ef43 (patch)
treebbde583102ffcbd6dad87fc8a1866023eb4c1d46
parent4552dbe5c165c73b8831ac4bd5bbbf387b6bb567 (diff)
libwimaxll: use genl controller instead of op-open and rp-ifinfo
The generic netlink controller can provide all the information needed for listing the multicast groups, so use that instead of the WiMAX stack provided one, which has been removed.
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/Makefile.in25
-rw-r--r--lib/genl.c188
-rw-r--r--lib/internal.h11
-rw-r--r--lib/op-msg.c3
-rw-r--r--lib/op-open.c442
6 files changed, 265 insertions, 405 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2b9d879..4523ce4 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -9,6 +9,7 @@ noinst_HEADERS = debug.h internal.h
lib_LTLIBRARIES = libwimaxll.la
lib_LIBRARIES = libwimaxll.a
libwimaxll_sources = \
+ genl.c \
op-open.c \
op-msg.c \
op-reset.c \
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 37522bb..f90b506 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -56,18 +56,19 @@ LIBRARIES = $(lib_LIBRARIES)
ARFLAGS = cru
libwimaxll_a_AR = $(AR) $(ARFLAGS)
libwimaxll_a_LIBADD =
-am__objects_1 = op-open.$(OBJEXT) op-msg.$(OBJEXT) op-reset.$(OBJEXT) \
- op-rfkill.$(OBJEXT) mc_rx.$(OBJEXT) pipe.$(OBJEXT) \
- re-state-change.$(OBJEXT) wimax.$(OBJEXT)
+am__objects_1 = genl.$(OBJEXT) op-open.$(OBJEXT) op-msg.$(OBJEXT) \
+ op-reset.$(OBJEXT) op-rfkill.$(OBJEXT) mc_rx.$(OBJEXT) \
+ pipe.$(OBJEXT) re-state-change.$(OBJEXT) wimax.$(OBJEXT)
am_libwimaxll_a_OBJECTS = $(am__objects_1)
libwimaxll_a_OBJECTS = $(am_libwimaxll_a_OBJECTS)
libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES)
libwimaxll_la_LIBADD =
-am__objects_2 = libwimaxll_la-op-open.lo libwimaxll_la-op-msg.lo \
- libwimaxll_la-op-reset.lo libwimaxll_la-op-rfkill.lo \
- libwimaxll_la-mc_rx.lo libwimaxll_la-pipe.lo \
- libwimaxll_la-re-state-change.lo libwimaxll_la-wimax.lo
+am__objects_2 = libwimaxll_la-genl.lo libwimaxll_la-op-open.lo \
+ libwimaxll_la-op-msg.lo libwimaxll_la-op-reset.lo \
+ libwimaxll_la-op-rfkill.lo libwimaxll_la-mc_rx.lo \
+ libwimaxll_la-pipe.lo libwimaxll_la-re-state-change.lo \
+ libwimaxll_la-wimax.lo
am_libwimaxll_la_OBJECTS = $(am__objects_2)
libwimaxll_la_OBJECTS = $(am_libwimaxll_la_OBJECTS)
libwimaxll_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -214,6 +215,7 @@ noinst_HEADERS = debug.h internal.h
lib_LTLIBRARIES = libwimaxll.la
lib_LIBRARIES = libwimaxll.a
libwimaxll_sources = \
+ genl.c \
op-open.c \
op-msg.c \
op-reset.c \
@@ -352,6 +354,8 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-genl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-mc_rx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-msg.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-open.Plo@am__quote@
@@ -390,6 +394,13 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+libwimaxll_la-genl.lo: genl.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-genl.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-genl.Tpo -c -o libwimaxll_la-genl.lo `test -f 'genl.c' || echo '$(srcdir)/'`genl.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-genl.Tpo $(DEPDIR)/libwimaxll_la-genl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='genl.c' object='libwimaxll_la-genl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-genl.lo `test -f 'genl.c' || echo '$(srcdir)/'`genl.c
+
libwimaxll_la-op-open.lo: op-open.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-op-open.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-op-open.Tpo -c -o libwimaxll_la-op-open.lo `test -f 'op-open.c' || echo '$(srcdir)/'`op-open.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-op-open.Tpo $(DEPDIR)/libwimaxll_la-op-open.Plo
diff --git a/lib/genl.c b/lib/genl.c
new file mode 100644
index 0000000..3216418
--- /dev/null
+++ b/lib/genl.c
@@ -0,0 +1,188 @@
+/*
+ * Heavily based on code from iw-0.9.6 by Johannes berg
+ *
+ * -- Original license & header --
+ *
+ * Copyright (c) 2007, 2008 Johannes Berg
+ * Copyright (c) 2007 Andy Lutomirski
+ * Copyright (c) 2007 Mike Kershaw
+ * Copyright (c) 2008 Luis R. Rodriguez
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This ought to be provided by libnl
+ *
+ * -- End of original license & header --
+ */
+
+#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>
+#include "internal.h"
+
+struct handler_arg {
+ void (*cb)(void *, const char *, int);
+ void *priv;
+};
+
+
+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_OK;
+}
+
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_OK;
+}
+
+static int family_handler(struct nl_msg *msg, void *_arg)
+{
+ struct handler_arg *arg = _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;
+ arg->cb(arg->priv,
+ nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
+ nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]));
+ }
+ return NL_OK;
+}
+
+/**
+ * Enumerates the list of available multicast groups for a family
+ *
+ * @handle: netlink handle to use for querying the list
+ * @family: name of family to query for multicast groups
+ * @cb: callback function to call with each multicast group's information.
+ * @priv: pointer to pass to the callback function
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Enumerates the multicast groups available for a generic netlink
+ * family and calls the callback with the arguments of each.
+ */
+int nl_get_multicast_groups(struct nl_handle *handle,
+ const char *family,
+ void (*cbf)(void *, const char *, int),
+ void *priv)
+{
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ int ret, ctrlid;
+ struct handler_arg arg = {
+ .priv = priv,
+ .cb = cbf
+ };
+
+ 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, &arg);
+
+ while (ret > 0)
+ nl_recvmsgs(handle, cb);
+ nla_put_failure:
+ out:
+ nl_cb_put(cb);
+ out_fail_cb:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+int genl_ctrl_get_version(struct nl_handle *nlh, const char *name)
+{
+ int result = -ENOENT;
+ struct genl_family *fam;
+ struct nl_cache *cache;
+
+ cache = genl_ctrl_alloc_cache(nlh);
+ if (cache == NULL)
+ return nl_get_errno();
+
+ fam = genl_ctrl_search_by_name(cache, name);
+ if (fam) {
+ result = genl_family_get_version(fam);
+ genl_family_put(fam);
+ }
+ nl_cache_free(cache);
+ return result;
+}
diff --git a/lib/internal.h b/lib/internal.h
index 1f40508..23aa984 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -37,6 +37,8 @@
#ifndef __lib_internal_h__
#define __lib_internal_h__
+#include <wimaxll.h>
+
enum {
#define __WIMAXLL_IFNAME_LEN 32
/**
@@ -104,7 +106,7 @@ struct wimaxll_handle {
unsigned ifidx;
struct nl_handle *nlh_tx;
int gnl_family_id;
- unsigned mc_msg;
+ unsigned mc_msg, mc_n;
char name[__WIMAXLL_IFNAME_LEN];
struct wimaxll_mc_group gnl_mc[WIMAXLL_MC_MAX];
};
@@ -191,4 +193,11 @@ int wimaxll_family_id(struct wimaxll_handle *wmx)
void wimaxll_msg(struct wimaxll_handle *, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
+/* Generic Netlink utilities */
+
+int nl_get_multicast_groups(struct nl_handle *, const char *,
+ void (*cb)(void *, const char *, int),
+ void *);
+int genl_ctrl_get_version(struct nl_handle *, const char *);
+
#endif /* #ifndef __lib_internal_h__ */
diff --git a/lib/op-msg.c b/lib/op-msg.c
index 73a2daa..61576ef 100644
--- a/lib/op-msg.c
+++ b/lib/op-msg.c
@@ -227,8 +227,7 @@ int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *wmx,
goto error_no_attrs;
}
- result = (ssize_t) nla_get_u64(tb[WIMAX_GNL_RESULT_CODE]);
- wimaxll_cb_context_set_result(ctx, result);
+ wimaxll_cb_context_set_result(ctx, 0);
size = nla_len(tb[WIMAX_GNL_MSG_DATA]);
data = nla_data(tb[WIMAX_GNL_MSG_DATA]);
diff --git a/lib/op-open.c b/lib/op-open.c
index 2674d8a..64f568b 100644
--- a/lib/op-open.c
+++ b/lib/op-open.c
@@ -49,11 +49,8 @@
*
* \code
* wimaxll_open()
- * __wimaxll_cmd_open()
- * nl_recvmsgs()
- * wimaxll_gnl_rp_ifinfo_cb()
- * __wimaxll_ifinfo_parse_groups()
- * wimaxll_gnl_error_cb()
+ * wimaxll_gnl_resolve()
+ * wimaxll_mc_rx_open()
*
* wimaxll_close()
* wimaxll_mc_rx_close()
@@ -82,274 +79,56 @@
#include "debug.h"
-/**
- * Generic Netlink: IFINFO message policy
- *
- * \internal
- * \ingroup device_management
- *
- * Authoritative reference for this is in drivers/net/wimax/op-open.c;
- * this is just a copy.
- */
static
-struct nla_policy wimaxll_gnl_ifinfo_policy[WIMAX_GNL_ATTR_MAX + 1] = {
- [WIMAX_GNL_IFINFO_MC_GROUPS] = { .type = NLA_NESTED },
- [WIMAX_GNL_IFINFO_MC_GROUP] = { .type = NLA_NESTED },
- [WIMAX_GNL_IFINFO_MC_NAME] = {
- .type = NLA_STRING,
- .maxlen = GENL_NAMSIZ
- },
- [WIMAX_GNL_IFINFO_MC_ID] = { .type = NLA_U16 },
-};
-
-
-/**
- * Callback context for processing IFINFO messages
- *
- * \ingroup device_management
- * \internal
- *
- * All the callbacks store the information they parse from the
- * messages here; we do it so that only once everything passes with
- * flying colors, then we commit the information the kernel sent.
- *
- * We include a \a struct wimaxll_gnl_cb_context so we can share this
- * same data structure with the error handler and not require to check
- * different data in different places.
- *
- * gnl_mc stands for Generic Netlink MultiCast group
- */
-struct wimaxll_ifinfo_context {
- struct wimaxll_gnl_cb_context gnl;
- struct wimaxll_mc_group gnl_mc[WIMAXLL_MC_MAX];
-};
-
-
-/**
- * Parse the list of multicast groups sent as part of a IFINFO reply
- *
- * \ingroup device_management
- * \internal
- *
- * \param ctx IFINFO context, containing the WiMAX handle
- *
- * \param nla_groups Netlink attribute (type
- * WIMAXLL_GNL_IFINFO_MC_GROUPS) that contains the list of (nested)
- * attributes (type WIMAXLL_GNL_IFINFO_MC_GROUP).
- * Just pass tb[WIMAXLL_GNL_IFINFO_MC_GROUPS]; this function will
- * check for it to be ok (non-NULL).
- *
- * \return 0 if ok, < 0 errno code on error.
- *
- * On success, the \a wmx->mc_group array will be cleared and
- * overwritten with the list of reported groups (and their
- * IDs).
- *
- * On error, nothing is modified.
- *
- * The kernel has sent a list of attributes: a nested attribute
- * (_MC_GROUPS) containing a list of nested attributes (_MC_GROUP)
- * each with a _MC_NAME and _MC_ID attribute].
- *
- * We need to parse it and extract the multicast group data. At least
- * a multicast group ('reports') has to exist; the rest are optional
- * to a maximum of WIMAXLL_MC_MAX (without counting 'reports').
- *
- * \note The private data for this callback is not an \a struct
- * wimaxll_mc_handle as most of the other ones!
- */
-static
-int __wimaxll_ifinfo_parse_groups(struct wimaxll_ifinfo_context *ctx,
- struct nlattr *nla_groups)
+void wimaxll_mc_group_cb(void *_wmx, const char *name, int id)
{
- int result, remaining, cnt = 0;
- struct wimaxll_handle *wmx = ctx->gnl.wmx;
- struct nlattr *nla_group;
+ struct wimaxll_handle *wmx = _wmx;
- d_fnstart(7, wmx, "(ctx %p [wmx %p] nla_groups %p)\n",
- ctx, wmx, nla_groups);
- if (nla_groups == NULL) {
- wimaxll_msg(wmx, "E: %s: the kernel didn't send a "
- "WIMAXLL_GNL_IFINFO_MC_GROUPS attribute\n",
- __func__);
- result = -EBADR;
- goto error_no_groups;
+ if (wmx->mc_n < sizeof(wmx->gnl_mc) / sizeof(wmx->gnl_mc[0])) {
+ struct wimaxll_mc_group *gmc = &wmx->gnl_mc[wmx->mc_n];
+ strncpy(gmc->name, name, sizeof(gmc->name));
+ gmc->id = id;
+ wmx->mc_n++;
}
-
- memset(ctx->gnl_mc, 0, sizeof(ctx->gnl_mc));
- nla_for_each_nested(nla_group, nla_groups, remaining) {
- char *name;
- int id;
- struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
-
- d_printf(8, wmx, "D: group %d, remaining %d\n",
- cnt, remaining);
- result = nla_parse_nested(tb, WIMAX_GNL_ATTR_MAX,
- nla_group,
- wimaxll_gnl_ifinfo_policy);
- if (result < 0) {
- wimaxll_msg(wmx, "E: %s: can't parse "
- "WIMAX_GNL_MC_GROUP attribute: %d\n",
- __func__, result);
- continue;
- }
-
- if (tb[WIMAX_GNL_IFINFO_MC_NAME] == NULL) {
- wimaxll_msg(wmx, "E: %s: multicast group missing "
- "WIMAX_GNL_IFINFO_MC_NAME attribute\n",
- __func__);
- continue;
- }
- name = nla_get_string(tb[WIMAX_GNL_IFINFO_MC_NAME]);
-
- if (tb[WIMAX_GNL_IFINFO_MC_ID] == NULL) {
- wimaxll_msg(wmx, "E: %s: multicast group missing "
- "WIMAX_GNL_IFINFO_MC_ID attribute\n",
- __func__);
- continue;
- }
- id = nla_get_u16(tb[WIMAX_GNL_IFINFO_MC_ID]);
-
- d_printf(6, wmx, "D: MC group %s:%d\n", name, id);
- strncpy(ctx->gnl_mc[cnt].name, name,
- sizeof(ctx->gnl_mc[cnt].name));
- ctx->gnl_mc[cnt].id = id;
- cnt++;
- }
- result = 0;
-error_no_groups:
- d_fnend(7, wmx, "(ctx %p [wmx %p] nla_groups %p) = %d\n",
- ctx, wmx, nla_groups, result);
- return result;
-}
-
-
-/*
- * Same as wimaxll_gnl_error_cb(), but takes a different type of
- * context, so, need another one (fitting an mch in there made little
- * sense).
- */
-int wimaxll_gnl_rp_ifinfo_error_cb(struct sockaddr_nl *nla,
- struct nlmsgerr *nlerr,
- void *_ctx)
-{
- struct wimaxll_ifinfo_context *ctx = _ctx;
- struct wimaxll_handle *wmx = ctx->gnl.wmx;
-
- d_fnstart(7, wmx, "(nla %p nlnerr %p [%d] ctx %p)\n",
- nla, nlerr, nlerr->error, _ctx);
- if (ctx->gnl.result == -EINPROGRESS)
- ctx->gnl.result = nlerr->error;
- ctx->gnl.msg_done = 1;
- d_fnend(7, wmx, "(nla %p nlnerr %p [%d] ctx %p) = NL_STOP\n",
- nla, nlerr, nlerr->error, _ctx);
- return NL_STOP;
-}
-
-
-static
-int wimaxll_gnl_rp_ifinfo_ack_cb(struct nl_msg *msg, void *_ctx)
-{
- int result;
- struct nlmsghdr *nl_hdr;
- struct nlmsgerr *nl_err;
- size_t size = nlmsg_len(nlmsg_hdr(msg));
- struct wimaxll_ifinfo_context *ctx = _ctx;
-
- d_fnstart(7, NULL, "(msg %p ctx %p)\n", msg, ctx);
- nl_hdr = nlmsg_hdr(msg);
- size = nlmsg_len(nl_hdr);
- nl_err = nlmsg_data(nl_hdr);
-
- if (size < sizeof(*nl_err)) {
- wimaxll_msg(NULL, "E: netlink ack: buffer too small "
- "(%zu vs %zu expected)\n",
- size, sizeof(*nl_hdr) + sizeof(*nl_err));
- result = -EIO;
- goto error_ack_short;
- }
- d_printf(4, NULL, "netlink ack: nlmsghdr len %u type %u flags 0x%04x "
- "seq 0x%x pid %u\n", nl_hdr->nlmsg_len, nl_hdr->nlmsg_type,
- nl_hdr->nlmsg_flags, nl_hdr->nlmsg_seq, nl_hdr->nlmsg_pid);
- if (nl_hdr->nlmsg_type != NLMSG_ERROR) {
- wimaxll_msg(NULL, "E: netlink ack: message is not an ack but "
- "type %u\n", nl_hdr->nlmsg_type);
- result = -EBADE;
- goto error_bad_type;
- }
- d_printf(4, NULL, "netlink ack: nlmsgerr error %d for "
- "nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
- nl_err->error,
- nl_err->msg.nlmsg_len, nl_err->msg.nlmsg_type,
- nl_err->msg.nlmsg_flags, nl_err->msg.nlmsg_seq,
- nl_err->msg.nlmsg_pid);
- if (ctx->gnl.result == -EINPROGRESS) {
- ctx->gnl.result = nl_err->error;
- d_printf(4, NULL, "netlink ack: updating gnl.result\n");
- }
- else
- d_printf(4, NULL, "netlink ack: Not updating gnl.result (%d)\n",
- ctx->gnl.result);
-
- if (nl_err->error < 0)
- d_printf(2, NULL, "D: netlink ack: received netlink error %d\n",
- nl_err->error);
- ctx->gnl.msg_done = 1;
-error_ack_short:
-error_bad_type:
- d_fnend(7, NULL, "(msg %p ctx %p) = NL_STOP\n", msg, ctx);
- return NL_STOP;
}
-/**
- * Seek for and process a WIMAX_GNL_RP_IFINFO message from the kernel
- *
- * \ingroup device_management
- * \internal
- *
- * \param msg Netlink message containing the reply
- * \param _ctx Pointer to a \a struct wimaxll_gnl_cb_context where the
- * context will be returned.
- *
- * \return 'enum nl_cb_action', NL_OK if there is no error, NL_STOP on
- * error and _ctx possibly updated.
- *
- * This will take a received netlink message, check it is a \a
- * WIMAX_GNL_RP_IFINFO, parse the contents and store them in an
- * struct wimaxll_ifinfo_context (for the caller to use later on).
- */
static
-int wimaxll_gnl_rp_ifinfo_cb(struct nl_msg *msg, void *_ctx)
+int wimaxll_gnl_resolve(struct wimaxll_handle *wmx)
{
- int result;
- struct wimaxll_ifinfo_context *ctx = _ctx;
- struct wimaxll_handle *wmx = ctx->gnl.wmx;
- struct nlmsghdr *nl_hdr;
- struct genlmsghdr *genl_hdr;
- struct nlattr *tb[WIMAX_GNL_ATTR_MAX + 1];
+ int result, version;
+ char buf[64];
unsigned major, minor;
-
- d_fnstart(7, wmx, "(msg %p ctx %p)\n", msg, ctx);
- nl_hdr = nlmsg_hdr(msg);
- genl_hdr = nlmsg_data(nl_hdr);
-
- if (genl_hdr->cmd != WIMAX_GNL_RP_IFINFO) {
- ctx->gnl.result = -ENXIO;
- result = NL_SKIP;
- d_printf(1, wmx, "D: ignoring unknown reply %d\n",
- genl_hdr->cmd);
- goto error_parse;
+
+ d_fnstart(5, wmx, "(wmx %p)\n", wmx);
+ /* Lookup the generic netlink family */
+ wmx->ifidx = if_nametoindex(wmx->name);
+ if (wmx->ifidx == 0) {
+ wimaxll_msg(wmx, "E: device %s does not exist\n", wmx->name);
+ goto error_no_dev;
+ }
+ snprintf(buf, sizeof(buf), "WiMAX %u", wmx->ifidx);
+ result = genl_ctrl_resolve(wmx->nlh_tx, buf);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: device %s presents no WiMAX interface; "
+ "it might not exist, not be be a WiMAX device or "
+ "support an interface unknown to libwimaxll: %d\n",
+ wmx->name, result);
+ goto error_ctrl_resolve;
}
+ wmx->gnl_family_id = result;
+ d_printf(1, wmx, "D: WiMAX device %s, genl family ID %d\n",
+ wmx->name, wmx->gnl_family_id);
+ nl_get_multicast_groups(wmx->nlh_tx, buf, wimaxll_mc_group_cb, wmx);
+ version = genl_ctrl_get_version(wmx->nlh_tx, buf);
/* Check version compatibility -- check include/linux/wimax.h
* for a complete description. The idea is to allow for good
* expandability of the interface without causing breakage. */
- major = genl_hdr->version / 10;
- minor = genl_hdr->version % 10;
+ major = version / 10;
+ minor = version % 10;
if (major != WIMAX_GNL_VERSION / 10) {
- ctx->gnl.result = -EBADR;
- result = NL_SKIP;
+ result = -EBADR;
wimaxll_msg(wmx, "E: kernel's major WiMAX GNL interface "
"version (%d) is different that supported %d; "
"aborting\n", major, WIMAX_GNL_VERSION / 10);
@@ -359,99 +138,9 @@ int wimaxll_gnl_rp_ifinfo_cb(struct nl_msg *msg, void *_ctx)
wimaxll_msg(wmx, "W: kernel's minor WiMAX GNL interface "
"version (%d) is lower that supported %d; things "
"might not work\n", minor, WIMAX_GNL_VERSION % 10);
-
- /* Parse the attributes */
- result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_IFINFO_MAX,
- wimaxll_gnl_ifinfo_policy);
- if (result < 0) {
- wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %d\n",
- __func__, result);
- ctx->gnl.result = result;
- result = NL_SKIP;
- goto error_parse;
- }
- result = __wimaxll_ifinfo_parse_groups(ctx,
- tb[WIMAX_GNL_IFINFO_MC_GROUPS]);
- if (result < 0) {
- ctx->gnl.result = result;
- result = NL_SKIP;
- } else {
- ctx->gnl.result = 0;
- result = NL_OK;
- }
-error_parse:
error_bad_major:
- d_fnend(7, wmx, "(msg %p ctx %p) = %d\n", msg, ctx, result);
- return result;
-}
-
-
-static
-int __wimaxll_cmd_open(struct wimaxll_handle *wmx)
-{
- int result;
- struct nl_msg *msg;
- struct nl_cb *cb;
- struct wimaxll_ifinfo_context ctx;
-
- d_fnstart(5, wmx, "(wmx %p)\n", wmx);
- msg = nlmsg_new();
- if (msg == NULL) {
- result = -errno;
- wimaxll_msg(wmx, "E: %s: cannot allocate generic netlink "
- "message: %m\n", __func__);
- goto error_msg_alloc;
- }
- if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
- wimaxll_family_id(wmx), 0, 0,
- WIMAX_GNL_OP_OPEN, WIMAX_GNL_VERSION) == NULL) {
- result = -errno;
- wimaxll_msg(wmx, "E: %s: error preparing message: %m\n",
- __func__);
- goto error_msg_prep;
- }
- result = nl_send_auto_complete(wmx->nlh_tx, msg);
- if (result < 0) {
- wimaxll_msg(wmx, "E: %s: error sending message: %d\n",
- __func__, result);
- goto error_msg_send;
- }
-
- /* Read the reply, that includes a WIMAX_GNL_RP_IFINFO message
- *
- * We need to set the call back error handler, so we get the
- * default cb handler and modify it.
- */
- ctx.gnl.wmx = wmx;
- ctx.gnl.result = -EINPROGRESS;
- ctx.gnl.msg_done = 0;
- cb = nl_socket_get_cb(wmx->nlh_tx);
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
- wimaxll_gnl_rp_ifinfo_cb, &ctx);
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
- wimaxll_gnl_rp_ifinfo_ack_cb, &ctx);
- nl_cb_err(cb, NL_CB_CUSTOM, wimaxll_gnl_rp_ifinfo_error_cb, &ctx.gnl);
- do
- result = nl_recvmsgs(wmx->nlh_tx, cb);
- while (ctx.gnl.msg_done == 0 && result >= 0);
- result = ctx.gnl.result;
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
- nl_cb_err(cb, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
- nl_cb_put(cb);
- if (result == -EINPROGRESS)
- wimaxll_msg(wmx, "E: %s: the kernel didn't reply with a "
- "WIMAX_GNL_RP_IFINFO message\n", __func__);
- else if (result >= 0) {
- d_printf(1, wmx, "D: processing result is %d\n", result);
- /* All fine and dandy, commit the data */
- memcpy(wmx->gnl_mc, ctx.gnl_mc, sizeof(ctx.gnl_mc));
- } else
- d_printf(1, wmx, "E: rp_ifinfo failed %d\n", result);
-error_msg_prep:
-error_msg_send:
- nlmsg_free(msg);
-error_msg_alloc:
+error_ctrl_resolve:
+error_no_dev:
d_fnend(5, wmx, "(wmx %p) = %d\n", wmx, result);
return result;
}
@@ -476,8 +165,9 @@ void wimaxll_free(struct wimaxll_handle *wmx)
* versioning will be done. If the kernel interface has a different
* major version, the \c wimaxll_open() call will fail (existing
* interfaces modified or removed). A higher kernel minor version is
- * allowed (new interfaces added); a lower kernel minor version is not
- * (the library needs interfaces that are not in the kernel).
+ * allowed (new interfaces added); a lower kernel minor version is
+ * allowed with a warning (the library might need interfaces that are
+ * not in the kernel).
*
* \ingroup device_management
* \internal
@@ -487,31 +177,14 @@ void wimaxll_free(struct wimaxll_handle *wmx)
* it's not a WiMAX device). This is done by querying generic netlink
* for a family called "WiMAX <DEVNAME>".
*
- * An open command is issued to get and process interface information
- * (like multicast group mappings, etc). This also does an interface
- * versioning verification.
- *
- * The bulk of this code is in the parsing of the generic netlink
- * reply that the \a WIMAX_GNL_OP_OPEN command returns (\a
- * WIMAX_GNL_RP_IFINFO) with information about the WiMAX control
- * interface.
- *
- * We process said reply using the \e libnl callback mechanism,
- * invoked by __wimaxll_cmd_open(). All the information is stored in a
- * struct wimaxll_ifinfo_context by the callbacks. When the callback
- * (and thus message) processing finishes, __wimaxll_cmd_open(), if all
- * successful, will commit the information from the context to the
- * handle. On error, nothing is modified.
- *
- * \note Because events are going to ben processed, sequence checks
- * have to be disabled (as indicated by the generic netlink
- * documentation).
+ * Then the Generic Netlink Controller is used to lookup versioning
+ * and the multicast group list that conform the different pipes
+ * supported by an interface.
*/
struct wimaxll_handle *wimaxll_open(const char *device)
{
int result;
struct wimaxll_handle *wmx;
- char buf[64];
d_fnstart(3, NULL, "(device %s)\n", device);
result = ENOMEM;
@@ -537,28 +210,9 @@ struct wimaxll_handle *wimaxll_open(const char *device)
goto error_nl_connect_tx;
}
- /* Lookup the generic netlink family */
- wmx->ifidx = if_nametoindex(wmx->name);
- if (wmx->ifidx == 0) {
- wimaxll_msg(wmx, "E: device %s does not exist\n", wmx->name);
- goto error_no_dev;
- }
- snprintf(buf, sizeof(buf), "WiMAX %u", wmx->ifidx);
- result = genl_ctrl_resolve(wmx->nlh_tx, buf);
- if (result < 0) {
- wimaxll_msg(wmx, "E: device %s presents no WiMAX interface; "
- "it might not exist, not be be a WiMAX device or "
- "support an interface unknown to libwimaxll: %d\n",
- wmx->name, result);
- goto error_ctrl_resolve;
- }
- wmx->gnl_family_id = result;
- d_printf(1, wmx, "D: WiMAX device %s, genl family ID %d\n",
- wmx->name, wmx->gnl_family_id);
-
- result = __wimaxll_cmd_open(wmx); /* Get interface information */
+ result = wimaxll_gnl_resolve(wmx); /* Get genl information */
if (result < 0)
- goto error_cmd_open;
+ goto error_gnl_resolve;
result = wimaxll_mc_rx_open(wmx, "msg");
if (result == -EPROTONOSUPPORT) /* not open? */
@@ -574,9 +228,7 @@ struct wimaxll_handle *wimaxll_open(const char *device)
wimaxll_mc_rx_close(wmx, wmx->mc_msg);
error_msg_open:
-error_cmd_open:
-error_ctrl_resolve:
-error_no_dev:
+error_gnl_resolve:
nl_close(wmx->nlh_tx);
error_nl_connect_tx:
nl_handle_destroy(wmx->nlh_tx);