diff options
author | Inaky Perez-Gonzalez <inaky.perez-gonzalez> | 2008-12-05 10:36:28 -0800 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2008-12-05 10:36:28 -0800 |
commit | db3556cf952c4b319afbaa9f5179d109e628ef43 (patch) | |
tree | bbde583102ffcbd6dad87fc8a1866023eb4c1d46 | |
parent | 4552dbe5c165c73b8831ac4bd5bbbf387b6bb567 (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.am | 1 | ||||
-rw-r--r-- | lib/Makefile.in | 25 | ||||
-rw-r--r-- | lib/genl.c | 188 | ||||
-rw-r--r-- | lib/internal.h | 11 | ||||
-rw-r--r-- | lib/op-msg.c | 3 | ||||
-rw-r--r-- | lib/op-open.c | 442 |
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); |