genl: updates to API reference documentation
This commit is contained in:
parent
d733f8a0a6
commit
0b70de5155
8 changed files with 486 additions and 265 deletions
|
@ -6,7 +6,7 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_GENL_CTRL_H_
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_GENL_FAMILY_H_
|
||||
|
@ -25,25 +25,19 @@ extern struct genl_family * genl_family_alloc(void);
|
|||
extern void genl_family_put(struct genl_family *);
|
||||
|
||||
extern unsigned int genl_family_get_id(struct genl_family *);
|
||||
extern void genl_family_set_id(struct genl_family *,
|
||||
unsigned int);
|
||||
extern void genl_family_set_id(struct genl_family *, unsigned int);
|
||||
extern char * genl_family_get_name(struct genl_family *);
|
||||
extern void genl_family_set_name(struct genl_family *,
|
||||
const char *name);
|
||||
extern void genl_family_set_name(struct genl_family *, const char *);
|
||||
extern uint8_t genl_family_get_version(struct genl_family *);
|
||||
extern void genl_family_set_version(struct genl_family *,
|
||||
uint8_t);
|
||||
extern void genl_family_set_version(struct genl_family *, uint8_t);
|
||||
extern uint32_t genl_family_get_hdrsize(struct genl_family *);
|
||||
extern void genl_family_set_hdrsize(struct genl_family *,
|
||||
uint32_t);
|
||||
extern void genl_family_set_hdrsize(struct genl_family *, uint32_t);
|
||||
extern uint32_t genl_family_get_maxattr(struct genl_family *);
|
||||
extern void genl_family_set_maxattr(struct genl_family *,
|
||||
uint32_t);
|
||||
extern void genl_family_set_maxattr(struct genl_family *, uint32_t);
|
||||
|
||||
extern int genl_family_add_op(struct genl_family *,
|
||||
int, int);
|
||||
extern int genl_family_add_grp(struct genl_family *,
|
||||
uint32_t , const char *);
|
||||
extern int genl_family_add_op(struct genl_family *, int, int);
|
||||
extern int genl_family_add_grp(struct genl_family *, uint32_t ,
|
||||
const char *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_GENL_H_
|
||||
|
@ -32,6 +32,8 @@ extern int genlmsg_validate(struct nlmsghdr *, int, int,
|
|||
struct nla_policy *);
|
||||
extern int genlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
|
||||
int, struct nla_policy *);
|
||||
extern struct genlmsghdr *
|
||||
genlmsg_hdr(struct nlmsghdr *);
|
||||
extern void * genlmsg_data(const struct genlmsghdr *);
|
||||
extern int genlmsg_len(const struct genlmsghdr *);
|
||||
extern struct nlattr * genlmsg_attrdata(const struct genlmsghdr *, int);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_GENL_MNGT_H_
|
||||
|
@ -22,57 +22,124 @@ extern "C" {
|
|||
|
||||
struct nl_cache_ops;
|
||||
|
||||
/**
|
||||
* @ingroup genl_mngt
|
||||
* @struct genl_info netlink/genl/mngt.h
|
||||
*
|
||||
* Informative structure passed on to message parser callbacks
|
||||
*
|
||||
* This structure is passed on to all message parser callbacks and contains
|
||||
* information about the sender of the message as well as pointers to all
|
||||
* relevant sections of the parsed message.
|
||||
*
|
||||
* @see genl_cmd::c_msg_parser
|
||||
*/
|
||||
struct genl_info
|
||||
{
|
||||
/** Socket address of sender */
|
||||
struct sockaddr_nl * who;
|
||||
|
||||
/** Pointer to Netlink message header */
|
||||
struct nlmsghdr * nlh;
|
||||
|
||||
/** Pointer to Generic Netlink message header */
|
||||
struct genlmsghdr * genlhdr;
|
||||
|
||||
/** Pointer to user header */
|
||||
void * userhdr;
|
||||
|
||||
/** Pointer to array of parsed attributes */
|
||||
struct nlattr ** attrs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup genl_mngt
|
||||
* Generic Netlink Command
|
||||
* @struct genl_cmd netlink/genl/mngt.h
|
||||
*
|
||||
* Definition of a Generic Netlink command.
|
||||
*
|
||||
* This structure is used to define the list of available commands on the
|
||||
* receiving side.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* static struct genl_cmd foo_cmds[] = {
|
||||
* {
|
||||
* .c_id = FOO_CMD_NEW,
|
||||
* .c_name = "NEWFOO" ,
|
||||
* .c_maxattr = FOO_ATTR_MAX,
|
||||
* .c_attr_policy = foo_policy,
|
||||
* .c_msg_parser = foo_msg_parser,
|
||||
* },
|
||||
* {
|
||||
* .c_id = FOO_CMD_DEL,
|
||||
* .c_name = "DELFOO" ,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* static struct genl_ops my_genl_ops = {
|
||||
* [...]
|
||||
* .o_cmds = foo_cmds,
|
||||
* .o_ncmds = ARRAY_SIZE(foo_cmds),
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
struct genl_cmd
|
||||
{
|
||||
/** Unique command identifier */
|
||||
/** Numeric command identifier (required) */
|
||||
int c_id;
|
||||
|
||||
/** Name/description of command */
|
||||
/** Human readable name (required) */
|
||||
char * c_name;
|
||||
|
||||
/**
|
||||
* Maximum attribute identifier, must be provided if
|
||||
* a message parser is available.
|
||||
*/
|
||||
/** Maximum attribute identifier that the command is prepared to handle. */
|
||||
int c_maxattr;
|
||||
|
||||
/** Called whenever a message for this command is received */
|
||||
int (*c_msg_parser)(struct nl_cache_ops *,
|
||||
struct genl_cmd *,
|
||||
struct genl_info *, void *);
|
||||
|
||||
/**
|
||||
* Attribute validation policy (optional)
|
||||
*/
|
||||
/** Attribute validation policy, enforced before the callback is called */
|
||||
struct nla_policy * c_attr_policy;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup genl_mngt
|
||||
* Generic Netlink Operations
|
||||
* @struct genl_ops netlink/genl/mngt.h
|
||||
*
|
||||
* Definition of a Generic Netlink family
|
||||
*
|
||||
* @see genl_cmd
|
||||
*/
|
||||
struct genl_ops
|
||||
{
|
||||
int o_family;
|
||||
|
||||
/** Numeric identifier, automatically resolved by genl_mngt_resolve() */
|
||||
int o_id;
|
||||
|
||||
/** Human readable name, used to resolve to numeric identifier */
|
||||
char * o_name;
|
||||
|
||||
/**
|
||||
* If registered via genl_register(), will point to the related
|
||||
* cache operations.
|
||||
*/
|
||||
struct nl_cache_ops * o_cache_ops;
|
||||
|
||||
/**
|
||||
* Can point to an array of generic netlink commands definitions.
|
||||
*/
|
||||
struct genl_cmd * o_cmds;
|
||||
|
||||
/** Size of \c o_cmds array */
|
||||
int o_ncmds;
|
||||
|
||||
/* linked list of all genl cache operations */
|
||||
/**
|
||||
* @private
|
||||
* Used internally to link together all registered operations.
|
||||
*/
|
||||
struct nl_list_head o_list;
|
||||
};
|
||||
|
||||
|
|
129
lib/genl/ctrl.c
129
lib/genl/ctrl.c
|
@ -6,14 +6,18 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup genl_mngt
|
||||
* @defgroup ctrl Controller
|
||||
* @brief
|
||||
* @ingroup genl
|
||||
* @defgroup genl_ctrl Controller (Resolver)
|
||||
*
|
||||
* Resolves Generic Netlink family names to numeric identifiers.
|
||||
*
|
||||
* The controller is a component in the kernel that resolves Generic Netlink
|
||||
* family names to their numeric identifiers. This module provides functions
|
||||
* to query the controller to access the resolving functionality.
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
@ -29,7 +33,6 @@
|
|||
#define CTRL_VERSION 0x0001
|
||||
|
||||
static struct nl_cache_ops genl_ctrl_ops;
|
||||
/** @endcond */
|
||||
|
||||
static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
|
||||
{
|
||||
|
@ -173,27 +176,51 @@ errout:
|
|||
return err;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @name Cache Management
|
||||
* @name Controller Cache
|
||||
*
|
||||
* The controller cache allows to keep a local copy of the list of all
|
||||
* kernel side registered Generic Netlink families to quickly resolve
|
||||
* multiple Generic Netlink family names without requiring to communicate
|
||||
* with the kernel for each resolving iteration.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
|
||||
/**
|
||||
* Allocate a new controller cache
|
||||
* @arg sk Generic Netlink socket
|
||||
* @arg result Pointer to store resulting cache
|
||||
*
|
||||
* Allocates a new cache mirroring the state of the controller and stores it
|
||||
* in \c *result. The allocated cache will contain a list of all currently
|
||||
* registered kernel side Generic Netlink families. The cache is meant to be
|
||||
* used to resolve family names locally.
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genl_ctrl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
|
||||
{
|
||||
return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
|
||||
return nl_cache_alloc_and_fill(&genl_ctrl_ops, sk, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up generic netlink family by id in the provided cache.
|
||||
* @arg cache Generic netlink family cache.
|
||||
* @arg id Family identifier.
|
||||
* Search controller cache for a numeric address match
|
||||
* @arg cache Controller cache
|
||||
* @arg id Numeric family identifier.
|
||||
*
|
||||
* Searches through the cache looking for a registered family
|
||||
* matching the specified identifier. The caller will own a
|
||||
* reference on the returned object which needs to be given
|
||||
* back after usage using genl_family_put().
|
||||
* Searches a previously allocated controller cache and looks for an entry
|
||||
* that matches the specified numeric family identifier \c id. If a match
|
||||
* is found successfully, the reference count of the matching object is
|
||||
* increased by one before the objet is returned.
|
||||
*
|
||||
* @return Generic netlink family object or NULL if no match was found.
|
||||
* @see genl_ctrl_alloc_cache()
|
||||
* @see genl_ctrl_search_by_name()
|
||||
* @see genl_family_put()
|
||||
*
|
||||
* @return Generic Netlink family object or NULL if no match was found.
|
||||
*/
|
||||
struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
|
||||
{
|
||||
|
@ -213,24 +240,23 @@ struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
|
|||
}
|
||||
|
||||
/**
|
||||
* @name Resolver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Look up generic netlink family by family name in the provided cache.
|
||||
* @arg cache Generic netlink family cache.
|
||||
* @arg name Family name.
|
||||
* Search controller cache for a family name match
|
||||
* @arg cache Controller cache
|
||||
* @arg name Name of Generic Netlink family
|
||||
*
|
||||
* Searches through the cache looking for a registered family
|
||||
* matching the specified name. The caller will own a reference
|
||||
* on the returned object which needs to be given back after
|
||||
* usage using genl_family_put().
|
||||
* Searches a previously allocated controller cache and looks for an entry
|
||||
* that matches the specified family \c name. If a match is found successfully,
|
||||
* the reference count of the matching object is increased by one before the
|
||||
* objet is returned.
|
||||
*
|
||||
* @return Generic netlink family object or NULL if no match was found.
|
||||
* @see genl_ctrl_alloc_cache()
|
||||
* @see genl_ctrl_search()
|
||||
* @see genl_family_put()
|
||||
*
|
||||
* @return Generic Netlink family object or NULL if no match was found.
|
||||
*/
|
||||
struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
struct genl_family *fam;
|
||||
|
||||
|
@ -250,14 +276,26 @@ struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* Resolve generic netlink family name to its identifier
|
||||
* @arg sk Netlink socket.
|
||||
* @arg name Name of generic netlink family
|
||||
* @name Direct Resolvers
|
||||
*
|
||||
* Resolves the generic netlink family name to its identifer and returns
|
||||
* it.
|
||||
* These functions communicate directly with the kernel and do not require
|
||||
* a cache to be kept up to date.
|
||||
*
|
||||
* @return A positive identifier or a negative error code.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolve Generic Netlink family name to numeric identifier
|
||||
* @arg sk Generic Netlink socket.
|
||||
* @arg name Name of Generic Netlink family
|
||||
*
|
||||
* Resolves the Generic Netlink family name to the corresponding numeric
|
||||
* family identifier. This function queries the kernel directly, use
|
||||
* genl_ctrl_search_by_name() if you need to resolve multiple names.
|
||||
*
|
||||
* @see genl_ctrl_search_by_name()
|
||||
*
|
||||
* @return The numeric family identifier or a negative error code.
|
||||
*/
|
||||
int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
|
||||
{
|
||||
|
@ -283,7 +321,7 @@ errout:
|
|||
}
|
||||
|
||||
static int genl_ctrl_grp_by_name(const struct genl_family *family,
|
||||
const char *grp_name)
|
||||
const char *grp_name)
|
||||
{
|
||||
struct genl_family_grp *grp;
|
||||
|
||||
|
@ -296,8 +334,19 @@ static int genl_ctrl_grp_by_name(const struct genl_family *family,
|
|||
return -NLE_OBJ_NOTFOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve Generic Netlink family group name
|
||||
* @arg sk Generic Netlink socket
|
||||
* @arg family_name Name of Generic Netlink family
|
||||
* @arg grp_name Name of group to resolve
|
||||
*
|
||||
* Looks up the family object and resolves the group name to the numeric
|
||||
* group identifier.
|
||||
*
|
||||
* @return Numeric group identifier or a negative error code.
|
||||
*/
|
||||
int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
|
||||
const char *grp_name)
|
||||
const char *grp_name)
|
||||
{
|
||||
struct nl_cache *cache;
|
||||
struct genl_family *family;
|
||||
|
@ -322,6 +371,7 @@ errout:
|
|||
|
||||
/** @} */
|
||||
|
||||
/** @cond SKIP */
|
||||
static struct genl_cmd genl_cmds[] = {
|
||||
{
|
||||
.c_id = CTRL_CMD_NEWFAMILY,
|
||||
|
@ -353,9 +403,7 @@ static struct genl_ops genl_ops = {
|
|||
.o_ncmds = ARRAY_SIZE(genl_cmds),
|
||||
};
|
||||
|
||||
/** @cond SKIP */
|
||||
extern struct nl_object_ops genl_family_ops;
|
||||
/** @endcond */
|
||||
|
||||
static struct nl_cache_ops genl_ctrl_ops = {
|
||||
.co_name = "genl/family",
|
||||
|
@ -376,5 +424,6 @@ static void __exit ctrl_exit(void)
|
|||
{
|
||||
genl_unregister(&genl_ctrl_ops);
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup genl
|
||||
* @defgroup genl_family Generic Netlink Family
|
||||
* @brief
|
||||
* @ingroup genl_ctrl
|
||||
* @defgroup genl_family Generic Netlink Family Object
|
||||
*
|
||||
* Object representing a kernel side registered Generic Netlink family
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
@ -32,7 +33,6 @@
|
|||
#define FAMILY_ATTR_OPS 0x20
|
||||
|
||||
struct nl_object_ops genl_family_ops;
|
||||
/** @endcond */
|
||||
|
||||
static void family_constructor(struct nl_object *c)
|
||||
{
|
||||
|
@ -166,18 +166,32 @@ static int family_compare(struct nl_object *_a, struct nl_object *_b,
|
|||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @name Family Object
|
||||
* @name Object Allocation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocate new Generic Netlink family object
|
||||
*
|
||||
* @return Newly allocated Generic Netlink family object or NULL.
|
||||
*/
|
||||
struct genl_family *genl_family_alloc(void)
|
||||
{
|
||||
return (struct genl_family *) nl_object_alloc(&genl_family_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release reference on Generic Netlink family object
|
||||
* @arg family Generic Netlink family object
|
||||
*
|
||||
* Reduces the reference counter of a Generic Netlink family object by one.
|
||||
* The object is freed after the last user has returned its reference.
|
||||
*
|
||||
* @see nl_object_put()
|
||||
*/
|
||||
void genl_family_put(struct genl_family *family)
|
||||
{
|
||||
nl_object_put((struct nl_object *) family);
|
||||
|
@ -186,10 +200,16 @@ void genl_family_put(struct genl_family *family)
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Attributes
|
||||
* @name Numeric Identifier
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return numeric identifier
|
||||
* @arg family Generic Netlink family object
|
||||
*
|
||||
* @return Numeric identifier or 0 if not available.
|
||||
*/
|
||||
unsigned int genl_family_get_id(struct genl_family *family)
|
||||
{
|
||||
if (family->ce_mask & FAMILY_ATTR_ID)
|
||||
|
@ -198,12 +218,30 @@ unsigned int genl_family_get_id(struct genl_family *family)
|
|||
return GENL_ID_GENERATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the numeric identifier
|
||||
* @arg family Generic Netlink family object
|
||||
* @arg id New numeric identifier
|
||||
*/
|
||||
void genl_family_set_id(struct genl_family *family, unsigned int id)
|
||||
{
|
||||
family->gf_id = id;
|
||||
family->ce_mask |= FAMILY_ATTR_ID;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Human Readable Name
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return human readable name
|
||||
* @arg family Generic Netlink family object
|
||||
*
|
||||
* @return Name of family or NULL if not available
|
||||
*/
|
||||
char *genl_family_get_name(struct genl_family *family)
|
||||
{
|
||||
if (family->ce_mask & FAMILY_ATTR_NAME)
|
||||
|
@ -212,12 +250,28 @@ char *genl_family_get_name(struct genl_family *family)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set human readable name
|
||||
* @arg family Generic Netlink family object
|
||||
* @arg name New human readable name
|
||||
*/
|
||||
void genl_family_set_name(struct genl_family *family, const char *name)
|
||||
{
|
||||
strncpy(family->gf_name, name, GENL_NAMSIZ-1);
|
||||
family->ce_mask |= FAMILY_ATTR_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Interface Version
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return interface version
|
||||
* @arg family Generic Netlink family object
|
||||
*
|
||||
* @return Interface version or 0 if not available.
|
||||
*/
|
||||
uint8_t genl_family_get_version(struct genl_family *family)
|
||||
{
|
||||
if (family->ce_mask & FAMILY_ATTR_VERSION)
|
||||
|
@ -226,12 +280,30 @@ uint8_t genl_family_get_version(struct genl_family *family)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set interface version
|
||||
* @arg family Generic Netlink family object
|
||||
* @arg version New interface version
|
||||
*/
|
||||
void genl_family_set_version(struct genl_family *family, uint8_t version)
|
||||
{
|
||||
family->gf_version = version;
|
||||
family->ce_mask |= FAMILY_ATTR_VERSION;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Header Size
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return user header size expected by kernel component
|
||||
* @arg family Generic Netlink family object
|
||||
*
|
||||
* @return Expected header length or 0 if not available.
|
||||
*/
|
||||
uint32_t genl_family_get_hdrsize(struct genl_family *family)
|
||||
{
|
||||
if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
|
||||
|
@ -246,6 +318,13 @@ void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
|
|||
family->ce_mask |= FAMILY_ATTR_HDRSIZE;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Maximum Expected Attribute
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint32_t genl_family_get_maxattr(struct genl_family *family)
|
||||
{
|
||||
if (family->ce_mask & FAMILY_ATTR_MAXATTR)
|
||||
|
@ -260,6 +339,13 @@ void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
|
|||
family->ce_mask |= FAMILY_ATTR_MAXATTR;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
int genl_family_add_op(struct genl_family *family, int id, int flags)
|
||||
{
|
||||
struct genl_family_op *op;
|
||||
|
|
279
lib/genl/genl.c
279
lib/genl/genl.c
|
@ -12,80 +12,6 @@
|
|||
/**
|
||||
* @defgroup genl Generic Netlink Library (libnl-genl)
|
||||
*
|
||||
* @par Message Format
|
||||
* @code
|
||||
* <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
|
||||
* +----------------------------+- - -+- - - - - - - - - - -+- - -+
|
||||
* | Header | Pad | Payload | Pad |
|
||||
* | struct nlmsghdr | | | |
|
||||
* +----------------------------+- - -+- - - - - - - - - - -+- - -+
|
||||
* @endcode
|
||||
* @code
|
||||
* <-------- GENL_HDRLEN -------> <--- hdrlen -->
|
||||
* <------- genlmsg_len(ghdr) ------>
|
||||
* +------------------------+- - -+---------------+- - -+------------+
|
||||
* | Generic Netlink Header | Pad | Family Header | Pad | Attributes |
|
||||
* | struct genlmsghdr | | | | |
|
||||
* +------------------------+- - -+---------------+- - -+------------+
|
||||
* genlmsg_data(ghdr)--------------^ ^
|
||||
* genlmsg_attrdata(ghdr, hdrlen)-------------------------
|
||||
* @endcode
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* #include <netlink/netlink.h>
|
||||
* #include <netlink/genl/genl.h>
|
||||
* #include <netlink/genl/ctrl.h>
|
||||
*
|
||||
* struct nl_sock *sock;
|
||||
* struct nl_msg *msg;
|
||||
* int family;
|
||||
*
|
||||
* // Allocate a new netlink socket
|
||||
* sock = nl_socket_alloc();
|
||||
*
|
||||
* // Connect to generic netlink socket on kernel side
|
||||
* genl_connect(sock);
|
||||
*
|
||||
* // Ask kernel to resolve family name to family id
|
||||
* family = genl_ctrl_resolve(sock, "generic_netlink_family_name");
|
||||
*
|
||||
* // Construct a generic netlink by allocating a new message, fill in
|
||||
* // the header and append a simple integer attribute.
|
||||
* msg = nlmsg_alloc();
|
||||
* genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO,
|
||||
* CMD_FOO_GET, FOO_VERSION);
|
||||
* nla_put_u32(msg, ATTR_FOO, 123);
|
||||
*
|
||||
* // Send message over netlink socket
|
||||
* nl_send_auto_complete(sock, msg);
|
||||
*
|
||||
* // Free message
|
||||
* nlmsg_free(msg);
|
||||
*
|
||||
* // Prepare socket to receive the answer by specifying the callback
|
||||
* // function to be called for valid messages.
|
||||
* nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
|
||||
*
|
||||
* // Wait for the answer and receive it
|
||||
* nl_recvmsgs_default(sock);
|
||||
*
|
||||
* static int parse_cb(struct nl_msg *msg, void *arg)
|
||||
* {
|
||||
* struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
* struct nlattr *attrs[ATTR_MAX+1];
|
||||
*
|
||||
* // Validate message and parse attributes
|
||||
* genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy);
|
||||
*
|
||||
* if (attrs[ATTR_FOO]) {
|
||||
* uint32_t value = nla_get_u32(attrs[ATTR_FOO]);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
@ -95,10 +21,27 @@
|
|||
#include <netlink/utils.h>
|
||||
|
||||
/**
|
||||
* @name Socket Creating
|
||||
* @name Generic Netlink Socket
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Connect a Generic Netlink socket
|
||||
* @arg sk Unconnected Netlink socket
|
||||
*
|
||||
* This function expects a struct nl_socket object previously allocated via
|
||||
* nl_socket_alloc(). It calls nl_connect() to create the local socket file
|
||||
* descriptor and binds the socket to the \c NETLINK_GENERIC Netlink protocol.
|
||||
*
|
||||
* Using this function is equivalent to:
|
||||
* @code
|
||||
* nl_connect(sk, NETLINK_GENERIC);
|
||||
* @endcode
|
||||
*
|
||||
* @see nl_connect()
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genl_connect(struct nl_sock *sk)
|
||||
{
|
||||
return nl_connect(sk, NETLINK_GENERIC);
|
||||
|
@ -107,20 +50,34 @@ int genl_connect(struct nl_sock *sk)
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Sending
|
||||
* @name Sending Data
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send trivial generic netlink message
|
||||
* @arg sk Netlink socket.
|
||||
* @arg family Generic netlink family
|
||||
* @arg cmd Command
|
||||
* @arg version Version
|
||||
* @arg flags Additional netlink message flags.
|
||||
* Send a Generic Netlink message consisting only of a header
|
||||
* @arg sk Generic Netlink socket
|
||||
* @arg family Numeric family identifier
|
||||
* @arg cmd Numeric command identifier
|
||||
* @arg version Interface version
|
||||
* @arg flags Additional Netlink message flags (optional)
|
||||
*
|
||||
* Fills out a routing netlink request message and sends it out
|
||||
* using nl_send_simple().
|
||||
* This function is a shortcut for sending a Generic Netlink message without
|
||||
* any message payload. The message will only consist of the Netlink and
|
||||
* Generic Netlink headers. The header is constructed based on the specified
|
||||
* parameters and passed on to nl_send_simple() to send it on the specified
|
||||
* socket.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* #include <netlink/genl/genl.h>
|
||||
* #include <linux/genetlink.h>
|
||||
*
|
||||
* err = genl_send_simple(sk, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, CTRL_VERSION,
|
||||
* NLM_F_DUMP);
|
||||
* @endcode
|
||||
*
|
||||
* @see nl_send_simple()
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
|
@ -137,12 +94,26 @@ int genl_send_simple(struct nl_sock *sk, int family, int cmd,
|
|||
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @name Message Parsing
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validate Generic Netlink message headers
|
||||
* @arg nlh Pointer to Netlink message header
|
||||
* @arg hdrlen Length of user header
|
||||
*
|
||||
* Verifies the integrity of the Netlink and Generic Netlink headers by
|
||||
* enforcing the following requirements:
|
||||
* - Valid Netlink message header (nlmsg_valid_hdr())
|
||||
* - Presence of a complete Generic Netlink header
|
||||
* - At least \c hdrlen bytes of payload included after the generic
|
||||
* netlink header.
|
||||
*
|
||||
* @return A positive integer (true) if the headers are valid or
|
||||
* 0 (false) if not.
|
||||
*/
|
||||
int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
@ -157,8 +128,28 @@ int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Generic Netlink message including attributes
|
||||
* @arg nlh Pointer to Netlink message header
|
||||
* @arg hdrlen Length of user header
|
||||
* @arg maxtype Maximum attribtue id expected
|
||||
* @arg policy Attribute validation policy
|
||||
*
|
||||
* Verifies the validity of the Netlink and Generic Netlink headers using
|
||||
* genlmsg_valid_hdr() and calls nla_validate() on the message payload to
|
||||
* verify the integrity of eventual attributes.
|
||||
*
|
||||
* @note You may call genlmsg_parse() directly to perform validation and
|
||||
* parsing in a single step.
|
||||
*
|
||||
* @see genlmsg_valid_hdr()
|
||||
* @see nla_validate()
|
||||
* @see genlmsg_parse()
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
|
||||
struct nla_policy *policy)
|
||||
struct nla_policy *policy)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
|
@ -170,6 +161,33 @@ int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
|
|||
genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Generic Netlink message including attributes
|
||||
* @arg nlh Pointer to Netlink message header
|
||||
* @arg hdrlen Length of user header
|
||||
* @arg tb Array to store parsed attributes
|
||||
* @arg maxtype Maximum attribute id expected
|
||||
* @arg policy Attribute validation policy
|
||||
*
|
||||
* Verifies the validity of the Netlink and Generic Netlink headers using
|
||||
* genlmsg_valid_hdr() and calls nla_parse() on the message payload to
|
||||
* parse eventual attributes.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* struct nlattr *attrs[MY_TYPE_MAX+1];
|
||||
*
|
||||
* if ((err = genlsmg_parse(nlmsg_nlh(msg), sizeof(struct my_hdr), attrs,
|
||||
* MY_TYPE_MAX, attr_policy)) < 0)
|
||||
* // ERROR
|
||||
* @endcode
|
||||
*
|
||||
* @see genlmsg_valid_hdr()
|
||||
* @see genlmsg_validate()
|
||||
* @see nla_parse()
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, struct nla_policy *policy)
|
||||
{
|
||||
|
@ -184,29 +202,44 @@ int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
|||
}
|
||||
|
||||
/**
|
||||
* Get head of message payload
|
||||
* @arg gnlh genetlink messsage header
|
||||
* Return pointer to message payload
|
||||
* @arg gnlh Generic Netlink message header
|
||||
*
|
||||
* Calculates the pointer to the message payload based on the pointer
|
||||
* to the generic netlink message header.
|
||||
*
|
||||
* @note Depending on whether your own message format uses a header, the
|
||||
* returned pointer may in fact point to the user header.
|
||||
*
|
||||
* @return Pointer to generic netlink message
|
||||
*/
|
||||
void *genlmsg_data(const struct genlmsghdr *gnlh)
|
||||
{
|
||||
return ((unsigned char *) gnlh + GENL_HDRLEN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get lenght of message payload
|
||||
* @arg gnlh genetlink message header
|
||||
* Return length of message payload
|
||||
* @arg gnlh Generic Netlink message header
|
||||
*
|
||||
* @return Length of user payload including an eventual user header in
|
||||
* number of bytes.
|
||||
*/
|
||||
int genlmsg_len(const struct genlmsghdr *gnlh)
|
||||
{
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
|
||||
NLMSG_HDRLEN);
|
||||
struct nlmsghdr *nlh;
|
||||
|
||||
nlh = (struct nlmsghdr *)((unsigned char *) gnlh - NLMSG_HDRLEN);
|
||||
return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get head of attribute data
|
||||
* @arg gnlh generic netlink message header
|
||||
* @arg hdrlen length of family specific header
|
||||
* Return pointer to message attributes
|
||||
* @arg gnlh Generic Netlink message header
|
||||
* @arg hdrlen Length of user header
|
||||
*
|
||||
* @return Pointer to the start of the message's attributes section.
|
||||
*/
|
||||
struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
|
@ -214,9 +247,12 @@ struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
|
|||
}
|
||||
|
||||
/**
|
||||
* Get length of attribute data
|
||||
* @arg gnlh generic netlink message header
|
||||
* @arg hdrlen length of family specific header
|
||||
* Return length of message attributes
|
||||
* @arg gnlh Generic Netlink message header
|
||||
* @arg hdrlen Length of user header
|
||||
*
|
||||
* @return Length of the message section containing attributes in number
|
||||
* of bytes.
|
||||
*/
|
||||
int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
|
@ -226,24 +262,45 @@ int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Message Building
|
||||
* @name Message Construction
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add generic netlink header to netlink message
|
||||
* @arg msg netlink message
|
||||
* @arg pid netlink process id or NL_AUTO_PID
|
||||
* @arg seq sequence number of message or NL_AUTO_SEQ
|
||||
* @arg family generic netlink family
|
||||
* @arg hdrlen length of user specific header
|
||||
* @arg flags message flags
|
||||
* @arg cmd generic netlink command
|
||||
* @arg version protocol version
|
||||
* Add Generic Netlink headers to Netlink message
|
||||
* @arg msg Netlink message object
|
||||
* @arg port Netlink port or NL_AUTO_PORT
|
||||
* @arg seq Sequence number of message or NL_AUTO_SEQ
|
||||
* @arg family Numeric family identifier
|
||||
* @arg hdrlen Length of user header
|
||||
* @arg flags Additional Netlink message flags (optional)
|
||||
* @arg cmd Numeric command identifier
|
||||
* @arg version Interface version
|
||||
*
|
||||
* Returns pointer to user specific header.
|
||||
* Calls nlmsg_put() on the specified message object to reserve space for
|
||||
* the Netlink header, the Generic Netlink header, and a user header of
|
||||
* specified length. Fills out the header fields with the specified
|
||||
* parameters.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* struct nl_msg *msg;
|
||||
* struct my_hdr *user_hdr;
|
||||
*
|
||||
* if (!(msg = nlmsg_alloc()))
|
||||
* // ERROR
|
||||
*
|
||||
* user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id,
|
||||
* sizeof(struct my_hdr), 0, MY_CMD_FOO, 0);
|
||||
* if (!user_hdr)
|
||||
* // ERROR
|
||||
* @endcode
|
||||
*
|
||||
* @see nlmsg_put()
|
||||
*
|
||||
* Returns Pointer to user header or NULL if an error occurred.
|
||||
*/
|
||||
void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
|
||||
void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
|
||||
int hdrlen, int flags, uint8_t cmd, uint8_t version)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
|
@ -252,7 +309,7 @@ void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
|
|||
.version = version,
|
||||
};
|
||||
|
||||
nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
|
||||
nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
|
||||
if (nlh == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
118
lib/genl/mngt.c
118
lib/genl/mngt.c
|
@ -6,77 +6,15 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup genl
|
||||
* @defgroup genl_mngt Management
|
||||
* @defgroup genl_mngt Family and Operations Management
|
||||
*
|
||||
* @par 1) Registering a generic netlink module
|
||||
* @code
|
||||
* #include <netlink/genl/mngt.h>
|
||||
* Registering Generic Netlink Families and Commands
|
||||
*
|
||||
* // First step is to define all the commands being used in
|
||||
* // particular generic netlink family. The ID and name are
|
||||
* // mandatory to be filled out. A callback function and
|
||||
* // most the attribute policy that comes with it must be
|
||||
* // defined for commands expected to be issued towards
|
||||
* // userspace.
|
||||
* static struct genl_cmd foo_cmds[] = {
|
||||
* {
|
||||
* .c_id = FOO_CMD_NEW,
|
||||
* .c_name = "NEWFOO" ,
|
||||
* .c_maxattr = FOO_ATTR_MAX,
|
||||
* .c_attr_policy = foo_policy,
|
||||
* .c_msg_parser = foo_msg_parser,
|
||||
* },
|
||||
* {
|
||||
* .c_id = FOO_CMD_DEL,
|
||||
* .c_name = "DELFOO" ,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* // The list of commands must then be integrated into a
|
||||
* // struct genl_ops serving as handle for this particular
|
||||
* // family.
|
||||
* static struct genl_ops my_genl_ops = {
|
||||
* .o_cmds = foo_cmds,
|
||||
* .o_ncmds = ARRAY_SIZE(foo_cmds),
|
||||
* };
|
||||
*
|
||||
* // Using the above struct genl_ops an arbitary number of
|
||||
* // cache handles can be associated to it.
|
||||
* //
|
||||
* // The macro GENL_HDRSIZE() must be used to specify the
|
||||
* // length of the header to automatically take headers on
|
||||
* // generic layers into account.
|
||||
* //
|
||||
* // The macro GENL_FAMILY() is used to represent the generic
|
||||
* // netlink family id.
|
||||
* static struct nl_cache_ops genl_foo_ops = {
|
||||
* .co_name = "genl/foo",
|
||||
* .co_hdrsize = GENL_HDRSIZE(sizeof(struct my_hdr)),
|
||||
* .co_msgtypes = GENL_FAMILY(GENL_ID_GENERATE, "foo"),
|
||||
* .co_genl = &my_genl_ops,
|
||||
* .co_protocol = NETLINK_GENERIC,
|
||||
* .co_request_update = foo_request_update,
|
||||
* .co_obj_ops = &genl_foo_ops,
|
||||
* };
|
||||
*
|
||||
* // Finally each cache handle for a generic netlink family
|
||||
* // must be registered using genl_register().
|
||||
* static void __init foo_init(void)
|
||||
* {
|
||||
* genl_register(&genl_foo_ops);
|
||||
* }
|
||||
*
|
||||
* // ... respectively unregsted again.
|
||||
* static void __exit foo_exit(void)
|
||||
* {
|
||||
* genl_unregister(&genl_foo_ops);
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
@ -88,6 +26,8 @@
|
|||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/utils.h>
|
||||
|
||||
/** @cond SKIP */
|
||||
|
||||
static NL_LIST_HEAD(genl_ops_list);
|
||||
|
||||
static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
|
||||
|
@ -159,15 +99,18 @@ char *genl_op2name(int family, int op, char *buf, size_t len)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @name Register/Unregister
|
||||
* @name Registration (Cache Based)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register generic netlink operations
|
||||
* @arg ops cache operations
|
||||
* Register Generic Netlink family backed cache
|
||||
* @arg ops Cache operations definition
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genl_register(struct nl_cache_ops *ops)
|
||||
{
|
||||
|
@ -203,8 +146,8 @@ errout:
|
|||
}
|
||||
|
||||
/**
|
||||
* Unregister generic netlink operations
|
||||
* @arg ops cache operations
|
||||
* Unregister cache based Generic Netlink family
|
||||
* @arg ops Cache operations definition
|
||||
*/
|
||||
void genl_unregister(struct nl_cache_ops *ops)
|
||||
{
|
||||
|
@ -217,11 +160,7 @@ void genl_unregister(struct nl_cache_ops *ops)
|
|||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Resolving ID/Name
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @cond SKIP */
|
||||
static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
|
||||
{
|
||||
struct genl_family *family;
|
||||
|
@ -236,7 +175,22 @@ static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
|
|||
|
||||
return -NLE_OBJ_NOTFOUND;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @name Resolving the name of registered families
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolve a single Generic Netlink family
|
||||
* @arg sk Generic Netlink socket
|
||||
* @arg ops Generic Netlink family definition
|
||||
*
|
||||
* Resolves the family name to its numeric identifier.
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops)
|
||||
{
|
||||
struct nl_cache *ctrl;
|
||||
|
@ -252,6 +206,19 @@ errout:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all registered Generic Netlink families
|
||||
* @arg sk Generic Netlink socket
|
||||
*
|
||||
* Walks through all local Generic Netlink families that have been registered
|
||||
* using genl_register() and resolves the name of each family to the
|
||||
* corresponding numeric identifier.
|
||||
*
|
||||
* @see genl_register()
|
||||
* @see genl_ops_resolve()
|
||||
*
|
||||
* @return 0 on success or a negative error code.
|
||||
*/
|
||||
int genl_mngt_resolve(struct nl_sock *sk)
|
||||
{
|
||||
struct nl_cache *ctrl;
|
||||
|
@ -272,5 +239,4 @@ errout:
|
|||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @} */
|
||||
|
|
Loading…
Add table
Reference in a new issue