/* * 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 #include #include #include #include #include #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 * * \param handle netlink handle to use for querying the list * \param family name of family to query for multicast groups * \param cbf callback function to call with each multicast group's information. * \param 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) ret = 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; }