[GENL]: Provide more information to userspace about registered genl families
Additionaly exports the following information when providing the list of registered generic netlink families: - protocol version - header size - maximum number of attributes - list of available operations including - id - flags - avaiability of policy and doit/dumpit function libnl HEAD provides a utility to read this new information: 0x0010 nlctrl version 1 hdrsize 0 maxattr 6 op GETFAMILY (0x03) [POLICY,DOIT,DUMPIT] 0x0011 NLBL_MGMT version 1 hdrsize 0 maxattr 0 op unknown (0x02) [DOIT] op unknown (0x03) [DOIT] .... Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
78e5b8916e
commit
eb328111ef
3 changed files with 58 additions and 2 deletions
|
@ -16,6 +16,8 @@ struct genlmsghdr {
|
||||||
|
|
||||||
#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
|
#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
|
||||||
|
|
||||||
|
#define GENL_ADMIN_PERM 0x01
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of reserved static generic netlink identifiers:
|
* List of reserved static generic netlink identifiers:
|
||||||
*/
|
*/
|
||||||
|
@ -43,9 +45,25 @@ enum {
|
||||||
CTRL_ATTR_UNSPEC,
|
CTRL_ATTR_UNSPEC,
|
||||||
CTRL_ATTR_FAMILY_ID,
|
CTRL_ATTR_FAMILY_ID,
|
||||||
CTRL_ATTR_FAMILY_NAME,
|
CTRL_ATTR_FAMILY_NAME,
|
||||||
|
CTRL_ATTR_VERSION,
|
||||||
|
CTRL_ATTR_HDRSIZE,
|
||||||
|
CTRL_ATTR_MAXATTR,
|
||||||
|
CTRL_ATTR_OPS,
|
||||||
__CTRL_ATTR_MAX,
|
__CTRL_ATTR_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
|
#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CTRL_ATTR_OP_UNSPEC,
|
||||||
|
CTRL_ATTR_OP_ID,
|
||||||
|
CTRL_ATTR_OP_FLAGS,
|
||||||
|
CTRL_ATTR_OP_POLICY,
|
||||||
|
CTRL_ATTR_OP_DOIT,
|
||||||
|
CTRL_ATTR_OP_DUMPIT,
|
||||||
|
__CTRL_ATTR_OP_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
|
||||||
|
|
||||||
#endif /* __LINUX_GENERIC_NETLINK_H */
|
#endif /* __LINUX_GENERIC_NETLINK_H */
|
||||||
|
|
|
@ -27,8 +27,6 @@ struct genl_family
|
||||||
struct list_head family_list; /* private */
|
struct list_head family_list; /* private */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GENL_ADMIN_PERM 0x01
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct genl_info - receiving information
|
* struct genl_info - receiving information
|
||||||
* @snd_seq: sending sequence number
|
* @snd_seq: sending sequence number
|
||||||
|
|
|
@ -387,7 +387,10 @@ static void genl_rcv(struct sock *sk, int len)
|
||||||
static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
|
static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
|
||||||
u32 flags, struct sk_buff *skb, u8 cmd)
|
u32 flags, struct sk_buff *skb, u8 cmd)
|
||||||
{
|
{
|
||||||
|
struct nlattr *nla_ops;
|
||||||
|
struct genl_ops *ops;
|
||||||
void *hdr;
|
void *hdr;
|
||||||
|
int idx = 1;
|
||||||
|
|
||||||
hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd,
|
hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd,
|
||||||
family->version);
|
family->version);
|
||||||
|
@ -396,6 +399,37 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
|
||||||
|
|
||||||
NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
|
NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
|
||||||
NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
|
NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
|
||||||
|
NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version);
|
||||||
|
NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize);
|
||||||
|
NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr);
|
||||||
|
|
||||||
|
nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
|
||||||
|
if (nla_ops == NULL)
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
list_for_each_entry(ops, &family->ops_list, ops_list) {
|
||||||
|
struct nlattr *nest;
|
||||||
|
|
||||||
|
nest = nla_nest_start(skb, idx++);
|
||||||
|
if (nest == NULL)
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
|
||||||
|
NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
|
||||||
|
|
||||||
|
if (ops->policy)
|
||||||
|
NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY);
|
||||||
|
|
||||||
|
if (ops->doit)
|
||||||
|
NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT);
|
||||||
|
|
||||||
|
if (ops->dumpit)
|
||||||
|
NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT);
|
||||||
|
|
||||||
|
nla_nest_end(skb, nest);
|
||||||
|
}
|
||||||
|
|
||||||
|
nla_nest_end(skb, nla_ops);
|
||||||
|
|
||||||
return genlmsg_end(skb, hdr);
|
return genlmsg_end(skb, hdr);
|
||||||
|
|
||||||
|
@ -411,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
int chains_to_skip = cb->args[0];
|
int chains_to_skip = cb->args[0];
|
||||||
int fams_to_skip = cb->args[1];
|
int fams_to_skip = cb->args[1];
|
||||||
|
|
||||||
|
if (chains_to_skip != 0)
|
||||||
|
genl_lock();
|
||||||
|
|
||||||
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
|
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
|
||||||
if (i < chains_to_skip)
|
if (i < chains_to_skip)
|
||||||
continue;
|
continue;
|
||||||
|
@ -428,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
|
if (chains_to_skip != 0)
|
||||||
|
genl_unlock();
|
||||||
|
|
||||||
cb->args[0] = i;
|
cb->args[0] = i;
|
||||||
cb->args[1] = n;
|
cb->args[1] = n;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue