
Patrick McHardy reported a problem where pointers to the payload of a netlink message as returned by f.e. the nesting helpers become stale when the payload data chunk is reallocated. In order to avoid further problems, the payload chunk is no longer extended on the fly. Instead the allocation is made during netlink message object allocation time with a default size of a page which should be fine for the majority of all users. Additionally the functions nlmsg_alloc_size() and nlmsg_set_default_size() have been added to allocate messages of a particular length and to modify the default message size.
786 lines
18 KiB
C
786 lines
18 KiB
C
/*
|
|
* lib/attr.c Netlink Attributes
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
|
*/
|
|
|
|
#include <netlink-local.h>
|
|
#include <netlink/netlink.h>
|
|
#include <netlink/utils.h>
|
|
#include <netlink/addr.h>
|
|
#include <netlink/attr.h>
|
|
#include <netlink/msg.h>
|
|
#include <linux/socket.h>
|
|
|
|
/**
|
|
* @ingroup msg
|
|
* @defgroup attr Attributes
|
|
* Netlink Attributes Construction/Parsing Interface
|
|
* @par 0) Introduction
|
|
* Netlink attributes are chained together following each other:
|
|
* @code
|
|
* <------- nla_total_size(payload) ------->
|
|
* <---- nla_attr_size(payload) ----->
|
|
* +----------+- - -+- - - - - - - - - +- - -+-------- - -
|
|
* | Header | Pad | Payload | Pad | Header
|
|
* +----------+- - -+- - - - - - - - - +- - -+-------- - -
|
|
* <- nla_len(nla) -> ^
|
|
* nla_data(nla)----^ |
|
|
* nla_next(nla)-----------------------------'
|
|
* @endcode
|
|
*
|
|
* @par
|
|
* The attribute header and payload must be aligned properly:
|
|
* @code
|
|
* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
|
|
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
|
* | Header | Pad | Payload | Pad |
|
|
* | (struct nlattr) | ing | | ing |
|
|
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
|
* <-------------- nlattr->nla_len -------------->
|
|
* @endcode
|
|
*
|
|
* @par Nested TLVs:
|
|
* Nested TLVs are an array of TLVs nested into another TLV. This can be useful
|
|
* to allow subsystems to have their own formatting rules without the need to
|
|
* make the underlying layer be aware of it. It can also be useful to transfer
|
|
* arrays, lists and flattened trees.
|
|
* \code
|
|
* <-------------------- NLA_ALIGN(...) ------------------->
|
|
* +---------------+- - - - - - - - - - - - - - - - - -+- - -+
|
|
* | |+---------+---------+- - -+-------+| |
|
|
* | TLV Header || TLV 1 | TLV 2 | | TLV n || Pad |
|
|
* | |+---------+---------+- - -+-------+| |
|
|
* +---------------+- - - - - - - - - - - - - - - - - -+- - -+
|
|
* <--------- nla_data(nla) --------->
|
|
* \endcode
|
|
*
|
|
* @par 1) Constructing a message with attributes
|
|
* @code
|
|
* int param1 = 10;
|
|
* char *param2 = "parameter text";
|
|
* struct nlmsghdr hdr = {
|
|
* .nlmsg_type = MY_ACTION,
|
|
* };
|
|
* struct nl_msg *m = nlmsg_build(&hdr);
|
|
* nla_put_u32(m, 1, param1);
|
|
* nla_put_string(m, 2, param2);
|
|
*
|
|
* nl_send_auto_complete(handle, nl_msg_get(m));
|
|
* nlmsg_free(m);
|
|
* @endcode
|
|
*
|
|
* @par 2) Constructing nested attributes
|
|
* @code
|
|
* struct nl_msg * nested_config(void)
|
|
* {
|
|
* int a = 5, int b = 10;
|
|
* struct nl_msg *n = nlmsg_build(NULL);
|
|
* nla_put_u32(n, 10, a);
|
|
* nla_put_u32(n, 20, b);
|
|
* return n;
|
|
* }
|
|
*
|
|
* ...
|
|
* struct nl_msg *m = nlmsg_build(&hdr);
|
|
* struct nl_msg *nest = nested_config();
|
|
* nla_put_nested(m, 1, nest);
|
|
*
|
|
* nl_send_auto_complete(handle, nl_msg_get(m));
|
|
* nlmsg_free(nest);
|
|
* nlmsg_free(m);
|
|
* @endcode
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @name Size Calculations
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* length of attribute not including padding
|
|
* @arg payload length of payload
|
|
*/
|
|
int nla_attr_size(int payload)
|
|
{
|
|
return NLA_HDRLEN + payload;
|
|
}
|
|
|
|
/**
|
|
* total length of attribute including padding
|
|
* @arg payload length of payload
|
|
*/
|
|
int nla_total_size(int payload)
|
|
{
|
|
return NLA_ALIGN(nla_attr_size(payload));
|
|
}
|
|
|
|
/**
|
|
* length of padding at the tail of the attribute
|
|
* @arg payload length of payload
|
|
*/
|
|
int nla_padlen(int payload)
|
|
{
|
|
return nla_total_size(payload) - nla_attr_size(payload);
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Payload Access
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* attribute type
|
|
* @arg nla netlink attribute
|
|
*/
|
|
int nla_type(const struct nlattr *nla)
|
|
{
|
|
return nla->nla_type & NLA_TYPE_MASK;
|
|
}
|
|
|
|
/**
|
|
* head of payload
|
|
* @arg nla netlink attribute
|
|
*/
|
|
void *nla_data(const struct nlattr *nla)
|
|
{
|
|
return (char *) nla + NLA_HDRLEN;
|
|
}
|
|
|
|
/**
|
|
* length of payload
|
|
* @arg nla netlink attribute
|
|
*/
|
|
int nla_len(const struct nlattr *nla)
|
|
{
|
|
return nla->nla_len - NLA_HDRLEN;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Attribute Parsing
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* check if the netlink attribute fits into the remaining bytes
|
|
* @arg nla netlink attribute
|
|
* @arg remaining number of bytes remaining in attribute stream
|
|
*/
|
|
int nla_ok(const struct nlattr *nla, int remaining)
|
|
{
|
|
return remaining >= sizeof(*nla) &&
|
|
nla->nla_len >= sizeof(*nla) &&
|
|
nla->nla_len <= remaining;
|
|
}
|
|
|
|
/**
|
|
* next netlink attribte in attribute stream
|
|
* @arg nla netlink attribute
|
|
* @arg remaining number of bytes remaining in attribute stream
|
|
*
|
|
* @return the next netlink attribute in the attribute stream and
|
|
* decrements remaining by the size of the current attribute.
|
|
*/
|
|
struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
|
|
{
|
|
int totlen = NLA_ALIGN(nla->nla_len);
|
|
|
|
*remaining -= totlen;
|
|
return (struct nlattr *) ((char *) nla + totlen);
|
|
}
|
|
|
|
static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
|
|
[NLA_U8] = sizeof(uint8_t),
|
|
[NLA_U16] = sizeof(uint16_t),
|
|
[NLA_U32] = sizeof(uint32_t),
|
|
[NLA_U64] = sizeof(uint64_t),
|
|
[NLA_STRING] = 1,
|
|
[NLA_NESTED] = NLA_HDRLEN,
|
|
};
|
|
|
|
static int validate_nla(struct nlattr *nla, int maxtype,
|
|
struct nla_policy *policy)
|
|
{
|
|
struct nla_policy *pt;
|
|
int minlen = 0, type = nla_type(nla);
|
|
|
|
if (type <= 0 || type > maxtype)
|
|
return 0;
|
|
|
|
pt = &policy[type];
|
|
|
|
if (pt->type > NLA_TYPE_MAX)
|
|
BUG();
|
|
|
|
if (pt->minlen)
|
|
minlen = pt->minlen;
|
|
else if (pt->type != NLA_UNSPEC)
|
|
minlen = nla_attr_minlen[pt->type];
|
|
|
|
if (pt->type == NLA_FLAG && nla_len(nla) > 0)
|
|
return nl_errno(ERANGE);
|
|
|
|
if (nla_len(nla) < minlen)
|
|
return nl_errno(ERANGE);
|
|
|
|
if (pt->maxlen && nla_len(nla) > pt->maxlen)
|
|
return nl_errno(ERANGE);
|
|
|
|
if (pt->type == NLA_STRING) {
|
|
char *data = nla_data(nla);
|
|
if (data[nla_len(nla) - 1] != '\0')
|
|
return nl_errno(EINVAL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse a stream of attributes into a tb buffer
|
|
* @arg tb destination array with maxtype+1 elements
|
|
* @arg maxtype maximum attribute type to be expected
|
|
* @arg head head of attribute stream
|
|
* @arg len length of attribute stream
|
|
* @arg policy validation policy
|
|
*
|
|
* Parses a stream of attributes and stores a pointer to each attribute in
|
|
* the tb array accessable via the attribute type. Attributes with a type
|
|
* exceeding maxtype will be silently ignored for backwards compatibility
|
|
* reasons. policy may be set to NULL if no validation is required.
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
|
struct nla_policy *policy)
|
|
{
|
|
struct nlattr *nla;
|
|
int rem, err;
|
|
|
|
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
|
|
|
|
nla_for_each_attr(nla, head, len, rem) {
|
|
int type = nla_type(nla);
|
|
|
|
if (type == 0) {
|
|
fprintf(stderr, "Illegal nla->nla_type == 0\n");
|
|
continue;
|
|
}
|
|
|
|
if (type <= maxtype) {
|
|
if (policy) {
|
|
err = validate_nla(nla, maxtype, policy);
|
|
if (err < 0)
|
|
goto errout;
|
|
}
|
|
|
|
tb[type] = nla;
|
|
}
|
|
}
|
|
|
|
if (rem > 0)
|
|
fprintf(stderr, "netlink: %d bytes leftover after parsing "
|
|
"attributes.\n", rem);
|
|
|
|
err = 0;
|
|
errout:
|
|
return err;
|
|
}
|
|
|
|
|
|
/**
|
|
* parse nested attributes
|
|
* @arg tb destination array with maxtype+1 elements
|
|
* @arg maxtype maximum attribute type to be expected
|
|
* @arg nla attribute containing the nested attributes
|
|
* @arg policy validation policy
|
|
*
|
|
* @see nla_parse()
|
|
*/
|
|
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
|
struct nla_policy *policy)
|
|
{
|
|
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
|
|
}
|
|
|
|
/**
|
|
* Validate a stream of attributes
|
|
* @arg head head of attribute stream
|
|
* @arg len length of attribute stream
|
|
* @arg maxtype maximum attribute type to be expected
|
|
* @arg policy validation policy
|
|
*
|
|
* Validates all attributes in the specified attribute stream
|
|
* against the specified policy. Attributes with a type exceeding
|
|
* maxtype will be ignored. See documenation of struct nla_policy
|
|
* for more details.
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int nla_validate(struct nlattr *head, int len, int maxtype,
|
|
struct nla_policy *policy)
|
|
{
|
|
struct nlattr *nla;
|
|
int rem, err;
|
|
|
|
nla_for_each_attr(nla, head, len, rem) {
|
|
err = validate_nla(nla, maxtype, policy);
|
|
if (err < 0)
|
|
goto errout;
|
|
}
|
|
|
|
err = 0;
|
|
errout:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Find a specific attribute in a stream of attributes
|
|
* @arg head head of attribute stream
|
|
* @arg len length of attribute stream
|
|
* @arg attrtype type of attribute to look for
|
|
*
|
|
* @return the first attribute in the stream matching the specified type.
|
|
*/
|
|
struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
|
|
{
|
|
struct nlattr *nla;
|
|
int rem;
|
|
|
|
nla_for_each_attr(nla, head, len, rem)
|
|
if (nla_type(nla) == attrtype)
|
|
return nla;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Utilities
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Copy a netlink attribute into another memory area
|
|
* @arg dest where to copy to memcpy
|
|
* @arg src netlink attribute to copy from
|
|
* @arg count size of the destination area
|
|
*
|
|
* Note: The number of bytes copied is limited by the length of
|
|
* attribute's payload. memcpy
|
|
*
|
|
* @return the number of bytes copied.
|
|
*/
|
|
int nla_memcpy(void *dest, struct nlattr *src, int count)
|
|
{
|
|
int minlen;
|
|
|
|
if (!src)
|
|
return 0;
|
|
|
|
minlen = min_t(int, count, nla_len(src));
|
|
memcpy(dest, nla_data(src), minlen);
|
|
|
|
return minlen;
|
|
}
|
|
|
|
/**
|
|
* Copy string attribute payload into a sized buffer
|
|
* @arg dst where to copy the string to
|
|
* @arg nla attribute to copy the string from
|
|
* @arg dstsize size of destination buffer
|
|
*
|
|
* Copies at most dstsize - 1 bytes into the destination buffer.
|
|
* The result is always a valid NUL-terminated string. Unlike
|
|
* strlcpy the destination buffer is always padded out.
|
|
*
|
|
* @return the length of the source buffer.
|
|
*/
|
|
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
|
|
{
|
|
size_t srclen = nla_len(nla);
|
|
char *src = nla_data(nla);
|
|
|
|
if (srclen > 0 && src[srclen - 1] == '\0')
|
|
srclen--;
|
|
|
|
if (dstsize > 0) {
|
|
size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
|
|
|
|
memset(dst, 0, dstsize);
|
|
memcpy(dst, src, len);
|
|
}
|
|
|
|
return srclen;
|
|
}
|
|
|
|
/**
|
|
* Compare an attribute with sized memory area
|
|
* @arg nla netlink attribute
|
|
* @arg data memory area
|
|
* @arg size size of memory area
|
|
*/
|
|
int nla_memcmp(const struct nlattr *nla, const void *data,
|
|
size_t size)
|
|
{
|
|
int d = nla_len(nla) - size;
|
|
|
|
if (d == 0)
|
|
d = memcmp(nla_data(nla), data, size);
|
|
|
|
return d;
|
|
}
|
|
|
|
/**
|
|
* Compare a string attribute against a string
|
|
* @arg nla netlink string attribute
|
|
* @arg str another string
|
|
*/
|
|
int nla_strcmp(const struct nlattr *nla, const char *str)
|
|
{
|
|
int len = strlen(str) + 1;
|
|
int d = nla_len(nla) - len;
|
|
|
|
if (d == 0)
|
|
d = memcmp(nla_data(nla), str, len);
|
|
|
|
return d;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Attribute Construction
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* reserve room for attribute on the skb
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg attrlen length of attribute payload
|
|
*
|
|
* Adds a netlink attribute header to a netlink message and reserves
|
|
* room for the payload but does not copy it.
|
|
*/
|
|
struct nlattr *nla_reserve(struct nl_msg *n, int attrtype, int attrlen)
|
|
{
|
|
struct nlattr *nla;
|
|
int tlen;
|
|
|
|
tlen = NLMSG_ALIGN(n->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
|
|
|
|
if ((tlen + n->nm_nlh->nlmsg_len) > n->nm_size) {
|
|
nl_errno(ENOBUFS);
|
|
return NULL;
|
|
}
|
|
|
|
nla = (struct nlattr *) nlmsg_tail(n->nm_nlh);
|
|
nla->nla_type = attrtype;
|
|
nla->nla_len = nla_attr_size(attrlen);
|
|
|
|
memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
|
|
n->nm_nlh->nlmsg_len = tlen;
|
|
|
|
NL_DBG(2, "msg %p: Reserved %d bytes at offset +%td for attr %d "
|
|
"nlmsg_len=%d\n", n, attrlen,
|
|
(void *) nla - nlmsg_data(n->nm_nlh),
|
|
attrtype, n->nm_nlh->nlmsg_len);
|
|
|
|
return nla;
|
|
}
|
|
|
|
/**
|
|
* Add a netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg attrlen length of attribute payload
|
|
* @arg data head of attribute payload
|
|
*
|
|
* @return -1 if the tailroom of the skb is insufficient to store
|
|
* the attribute header and payload.
|
|
*/
|
|
int nla_put(struct nl_msg *n, int attrtype, int attrlen, const void *data)
|
|
{
|
|
struct nlattr *nla;
|
|
|
|
nla = nla_reserve(n, attrtype, attrlen);
|
|
if (!nla)
|
|
return nl_errno(ENOMEM);
|
|
|
|
memcpy(nla_data(nla), data, attrlen);
|
|
NL_DBG(2, "msg %p: Wrote %d bytes at offset +%td for attr %d\n",
|
|
n, attrlen, (void *) nla - nlmsg_data(n->nm_nlh), attrtype);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Add a nested netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg nested netlink attribute to nest
|
|
*
|
|
* @return -1 if the tailroom of the skb is insufficient to store
|
|
* the attribute header and payload.
|
|
*/
|
|
int nla_put_nested(struct nl_msg *n, int attrtype, struct nl_msg *nested)
|
|
{
|
|
return nla_put(n, attrtype, nlmsg_len(nested->nm_nlh),
|
|
nlmsg_data(nested->nm_nlh));
|
|
}
|
|
|
|
/**
|
|
* Add a u16 netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg value numeric value
|
|
*/
|
|
int nla_put_u8(struct nl_msg *n, int attrtype, uint8_t value)
|
|
{
|
|
return nla_put(n, attrtype, sizeof(uint8_t), &value);
|
|
}
|
|
|
|
/**
|
|
* Add a u16 netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg value numeric value
|
|
*/
|
|
int nla_put_u16(struct nl_msg *n, int attrtype, uint16_t value)
|
|
{
|
|
return nla_put(n, attrtype, sizeof(uint16_t), &value);
|
|
}
|
|
|
|
/**
|
|
* Add a u32 netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg value numeric value
|
|
*/
|
|
int nla_put_u32(struct nl_msg *n, int attrtype, uint32_t value)
|
|
{
|
|
return nla_put(n, attrtype, sizeof(uint32_t), &value);
|
|
}
|
|
|
|
/**
|
|
* Add a u64 netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg value numeric value
|
|
*/
|
|
int nla_put_u64(struct nl_msg *n, int attrtype, uint64_t value)
|
|
{
|
|
return nla_put(n, attrtype, sizeof(uint64_t), &value);
|
|
}
|
|
|
|
/**
|
|
* Add a string netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg str NUL terminated string
|
|
*/
|
|
int nla_put_string(struct nl_msg *n, int attrtype, const char *str)
|
|
{
|
|
return nla_put(n, attrtype, strlen(str) + 1, str);
|
|
}
|
|
|
|
/**
|
|
* Add a flag netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
*/
|
|
int nla_put_flag(struct nl_msg *n, int attrtype)
|
|
{
|
|
return nla_put(n, attrtype, 0, NULL);
|
|
}
|
|
|
|
/**
|
|
* Add a msecs netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg msecs number of msecs
|
|
*/
|
|
int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
|
|
{
|
|
return nla_put_u64(n, attrtype, msecs);
|
|
}
|
|
|
|
/**
|
|
* Add an abstract data netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg data abstract data
|
|
*/
|
|
int nla_put_data(struct nl_msg *n, int attrtype, struct nl_data *data)
|
|
{
|
|
return nla_put(n, attrtype, nl_data_get_size(data),
|
|
nl_data_get(data));
|
|
}
|
|
|
|
/**
|
|
* Add an abstract address netlink attribute to a netlink message
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type
|
|
* @arg addr abstract address
|
|
*/
|
|
int nla_put_addr(struct nl_msg *n, int attrtype, struct nl_addr *addr)
|
|
{
|
|
return nla_put(n, attrtype, nl_addr_get_len(addr),
|
|
nl_addr_get_binary_addr(addr));
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Attribute Nesting
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Start a new level of nested attributes
|
|
* @arg n netlink message
|
|
* @arg attrtype attribute type of container
|
|
*
|
|
* @return the container attribute
|
|
*/
|
|
struct nlattr *nla_nest_start(struct nl_msg *n, int attrtype)
|
|
{
|
|
struct nlattr *start = (struct nlattr *) nlmsg_tail(n->nm_nlh);
|
|
|
|
if (nla_put(n, attrtype, 0, NULL) < 0)
|
|
return NULL;
|
|
|
|
return start;
|
|
}
|
|
|
|
/**
|
|
* Finalize nesting of attributes
|
|
* @arg n netlink message
|
|
* @arg start container attribute
|
|
*
|
|
* Corrects the container attribute header to include the all
|
|
* appeneded attributes.
|
|
*
|
|
* @return the total data length of the skb.
|
|
*/
|
|
int nla_nest_end(struct nl_msg *n, struct nlattr *start)
|
|
{
|
|
start->nla_len = (unsigned char *) nlmsg_tail(n->nm_nlh) -
|
|
(unsigned char *) start;
|
|
return 0;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Attribute Reading
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Return payload of u32 attribute
|
|
* @arg nla u32 netlink attribute
|
|
*/
|
|
uint32_t nla_get_u32(struct nlattr *nla)
|
|
{
|
|
return *(uint32_t *) nla_data(nla);
|
|
}
|
|
|
|
/**
|
|
* Return payload of u16 attribute
|
|
* @arg nla u16 netlink attribute
|
|
*/
|
|
uint16_t nla_get_u16(struct nlattr *nla)
|
|
{
|
|
return *(uint16_t *) nla_data(nla);
|
|
}
|
|
|
|
/**
|
|
* Return payload of u8 attribute
|
|
* @arg nla u8 netlink attribute
|
|
*/
|
|
uint8_t nla_get_u8(struct nlattr *nla)
|
|
{
|
|
return *(uint8_t *) nla_data(nla);
|
|
}
|
|
|
|
/**
|
|
* Return payload of u64 attribute
|
|
* @arg nla u64 netlink attribute
|
|
*/
|
|
uint64_t nla_get_u64(struct nlattr *nla)
|
|
{
|
|
uint64_t tmp;
|
|
|
|
nla_memcpy(&tmp, nla, sizeof(tmp));
|
|
|
|
return tmp;
|
|
}
|
|
|
|
/**
|
|
* return payload of string attribute
|
|
* @arg nla string netlink attribute
|
|
*/
|
|
char *nla_get_string(struct nlattr *nla)
|
|
{
|
|
return (char *) nla_data(nla);
|
|
}
|
|
|
|
/**
|
|
* Return payload of flag attribute
|
|
* @arg nla flag netlink attribute
|
|
*/
|
|
int nla_get_flag(struct nlattr *nla)
|
|
{
|
|
return !!nla;
|
|
}
|
|
|
|
/**
|
|
* Return payload of msecs attribute
|
|
* @arg nla msecs netlink attribute
|
|
*
|
|
* @return the number of milliseconds.
|
|
*/
|
|
unsigned long nla_get_msecs(struct nlattr *nla)
|
|
{
|
|
return nla_get_u64(nla);
|
|
}
|
|
|
|
/**
|
|
* Return payload of address attribute
|
|
* @arg nla address netlink attribute
|
|
* @arg family address family
|
|
*
|
|
* @return Newly allocated address handle or NULL
|
|
*/
|
|
struct nl_addr *nla_get_addr(struct nlattr *nla, int family)
|
|
{
|
|
return nl_addr_build(family, nla_data(nla), nla_len(nla));
|
|
}
|
|
|
|
/**
|
|
* Return payload of abstract data attribute
|
|
* @arg nla abstract data netlink attribute
|
|
*
|
|
* @return Newly allocated abstract data handle or NULL
|
|
*/
|
|
struct nl_data *nla_get_data(struct nlattr *nla)
|
|
{
|
|
return nl_data_alloc(nla_data(nla), nla_len(nla));
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/** @} */
|