You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.4 KiB
117 lines
2.4 KiB
/* |
|
* 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> |
|
#include <linux/genetlink.h> |
|
|
|
#include "iw.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 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_sock *sock, 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(sock, "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(sock, msg); |
|
if (ret < 0) |
|
goto out; |
|
|
|
ret = 1; |
|
|
|
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret); |
|
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(sock, cb); |
|
|
|
if (ret == 0) |
|
ret = grp.id; |
|
nla_put_failure: |
|
out: |
|
nl_cb_put(cb); |
|
out_fail_cb: |
|
nlmsg_free(msg); |
|
return ret; |
|
}
|
|
|