Revert "netifd: bump to latest version"

This reverts commit d6ce485de7.
This commit is contained in:
LEAN-ESX 2019-11-24 19:57:24 -08:00
parent 3d29f8e1ee
commit 3376f50203
51 changed files with 9032 additions and 210 deletions

View File

@ -8,20 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libnl-tiny
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libnl-tiny.git
PKG_SOURCE_DATE:=2019-10-29
PKG_SOURCE_VERSION:=0219008cc8767655d7e747497e8e1133a3e8f840
PKG_MIRROR_HASH:=b84fab21374c6ddbf992acc4ec1c9c6896b32af97603027ca5c866d69d95780f
CMAKE_INSTALL:=1
PKG_VERSION:=0.1
PKG_RELEASE:=5
PKG_LICENSE:=LGPL-2.1
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/libnl-tiny
SECTION:=libs
@ -33,16 +26,25 @@ define Package/libnl-tiny/description
This package contains a stripped down version of libnl
endef
TARGET_CFLAGS += $(FPIC)
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS)" \
all
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig $(1)/usr/include/libnl-tiny
$(CP) $(PKG_INSTALL_DIR)/usr/include/libnl-tiny/* $(1)/usr/include/libnl-tiny
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libnl-tiny.so $(1)/usr/lib/
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libnl-tiny.pc $(1)/usr/lib/pkgconfig
$(CP) $(PKG_BUILD_DIR)/include/* $(1)/usr/include/libnl-tiny
$(CP) $(PKG_BUILD_DIR)/libnl-tiny.so $(1)/usr/lib/
$(CP) ./files/libnl-tiny.pc $(1)/usr/lib/pkgconfig
endef
define Package/libnl-tiny/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libnl-tiny.so $(1)/usr/lib/
$(CP) $(PKG_BUILD_DIR)/libnl-tiny.so $(1)/usr/lib/
endef
$(eval $(call BuildPackage,libnl-tiny))

View File

@ -0,0 +1,10 @@
prefix=/usr
exec_prefix=/usr
libdir=${exec_prefix}/lib
includedir=${prefix}/include/libnl-tiny
Name: libnl-tiny
Description: Convenience library for netlink sockets
Version: 2.0
Libs: -L${libdir} -lnl-tiny
Cflags: -I${includedir}

View File

@ -0,0 +1,17 @@
CC=gcc
WFLAGS=-Wall
CFLAGS=-O2
INCLUDES=-Iinclude
LIBNAME=libnl-tiny.so
all: $(LIBNAME)
%.o: %.c
$(CC) $(WFLAGS) -c -o $@ $(INCLUDES) $(CFLAGS) $<
LIBNL_OBJ=nl.o handlers.o msg.o attr.o cache.o cache_mngt.o object.o socket.o error.o
GENL_OBJ=genl.o genl_family.o genl_ctrl.o genl_mngt.o unl.o
$(LIBNAME): $(LIBNL_OBJ) $(GENL_OBJ)
$(CC) $(CFLAGS) -Wl,-Bsymbolic-functions -shared -o $@ $^

View File

@ -0,0 +1,668 @@
/*
* 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-2008 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
*
* \section attr_sec Netlink Attributes
* Netlink attributes allow for data chunks of arbitary length to be
* attached to a netlink message. Each attribute is encoded with a
* type and length field, both 16 bits, stored in the attribute header
* preceding the attribute data. The main advantage of using attributes
* over packing everything into the family header is that the interface
* stays extendable as new attributes can supersede old attributes while
* remaining backwards compatible. Also attributes can be defined optional
* thus avoiding the transmission of unnecessary empty data blocks.
* Special nested attributes allow for more complex data structures to
* be transmitted, e.g. trees, lists, etc.
*
* While not required, netlink attributes typically follow the family
* header of a netlink message and must be properly aligned to NLA_ALIGNTO:
* @code
* +----------------+- - -+---------------+- - -+------------+- - -+
* | Netlink Header | Pad | Family Header | Pad | Attributes | Pad |
* +----------------+- - -+---------------+- - -+------------+- - -+
* @endcode
*
* The actual attributes are chained together each separately aligned to
* NLA_ALIGNTO. The position of an attribute is defined based on the
* length field of the preceding attributes:
* @code
* +-------------+- - -+-------------+- - -+------
* | Attribute 1 | Pad | Attribute 2 | Pad | ...
* +-------------+- - -+-------------+- - -+------
* nla_next(attr1)------^
* @endcode
*
* The attribute itself consists of the attribute header followed by
* the actual payload also aligned to NLA_ALIGNTO. The function nla_data()
* returns a pointer to the start of the payload while nla_len() returns
* the length of the payload in bytes.
*
* \b Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not
* safe to dereference any 64 bit data types directly.
*
* @code
* <----------- nla_total_size(payload) ----------->
* <-------- nla_attr_size(payload) --------->
* +------------------+- - -+- - - - - - - - - +- - -+
* | Attribute Header | Pad | Payload | Pad |
* +------------------+- - -+- - - - - - - - - +- - -+
* nla_data(nla)-------------^
* <- nla_len(nla) ->
* @endcode
*
* @subsection attr_datatypes Attribute Data Types
* A number of basic data types are supported to simplify access and
* validation of netlink attributes. This data type information is
* not encoded in the attribute, both the kernel and userspace part
* are required to share this information on their own.
*
* One of the major advantages of these basic types is the automatic
* validation of each attribute based on an attribute policy. The
* validation covers most of the checks required to safely use
* attributes and thus keeps the individual sanity check to a minimum.
*
* Never access attribute payload without ensuring basic validation
* first, attributes may:
* - not be present even though required
* - contain less actual payload than expected
* - fake a attribute length which exceeds the end of the message
* - contain unterminated character strings
*
* Policies are defined as array of the struct nla_policy. The array is
* indexed with the attribute type, therefore the array must be sized
* accordingly.
* @code
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... },
* };
*
* err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy);
* @endcode
*
* Some basic validations are performed on every attribute, regardless of type.
* - If the attribute type exceeds the maximum attribute type specified or
* the attribute type is lesser-or-equal than zero, the attribute will
* be silently ignored.
* - If the payload length falls below the \a minlen value the attribute
* will be rejected.
* - If \a maxlen is non-zero and the payload length exceeds the \a maxlen
* value the attribute will be rejected.
*
*
* @par Unspecific Attribute (NLA_UNSPEC)
* This is the standard type if no type is specified. It is used for
* binary data of arbitary length. Typically this attribute carries
* a binary structure or a stream of bytes.
* @par
* @code
* // In this example, we will assume a binary structure requires to
* // be transmitted. The definition of the structure will typically
* // go into a header file available to both the kernel and userspace
* // side.
* //
* // Note: Be careful when putting 64 bit data types into a structure.
* // The attribute payload is only aligned to 4 bytes, dereferencing
* // the member may fail.
* struct my_struct {
* int a;
* int b;
* };
*
* // The validation function will not enforce an exact length match to
* // allow structures to grow as required. Note: While it is allowed
* // to add members to the end of the structure, changing the order or
* // inserting members in the middle of the structure will break your
* // binary interface.
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_MY_STRICT] = { .type = NLA_UNSPEC,
* .minlen = sizeof(struct my_struct) },
*
* // The binary structure is appened to the message using nla_put()
* struct my_struct foo = { .a = 1, .b = 2 };
* nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo);
*
* // On the receiving side, a pointer to the structure pointing inside
* // the message payload is returned by nla_get().
* if (attrs[ATTR_MY_STRUCT])
* struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]);
* @endcode
*
* @par Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64)
* Integers come in different sizes from 8 bit to 64 bit. However, since the
* payload length is aligned to 4 bytes, integers smaller than 32 bit are
* only useful to enforce the maximum range of values.
* @par
* \b Note: There is no difference made between signed and unsigned integers.
* The validation only enforces the minimal payload length required to store
* an integer of specified type.
* @par
* @code
* // Even though possible, it does not make sense to specify .minlen or
* // .maxlen for integer types. The data types implies the corresponding
* // minimal payload length.
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_FOO] = { .type = NLA_U32 },
*
* // Numeric values can be appended directly using the respective
* // nla_put_uxxx() function
* nla_put_u32(msg, ATTR_FOO, 123);
*
* // Same for the receiving side.
* if (attrs[ATTR_FOO])
* uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
* @endcode
*
* @par Character string (NLA_STRING)
* This data type represents a NUL terminated character string of variable
* length. For binary data streams the type NLA_UNSPEC is recommended.
* @par
* @code
* // Enforce a NUL terminated character string of at most 4 characters
* // including the NUL termination.
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 },
*
* // nla_put_string() creates a string attribute of the necessary length
* // and appends it to the message including the NUL termination.
* nla_put_string(msg, ATTR_BAR, "some text");
*
* // It is safe to use the returned character string directly if the
* // attribute has been validated as the validation enforces the proper
* // termination of the string.
* if (attrs[ATTR_BAR])
* char *text = nla_get_string(attrs[ATTR_BAR]);
* @endcode
*
* @par Flag (NLA_FLAG)
* This attribute type may be used to indicate the presence of a flag. The
* attribute is only valid if the payload length is zero. The presence of
* the attribute header indicates the presence of the flag.
* @par
* @code
* // This attribute type is special as .minlen and .maxlen have no effect.
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_FLAG] = { .type = NLA_FLAG },
*
* // nla_put_flag() appends a zero sized attribute to the message.
* nla_put_flag(msg, ATTR_FLAG);
*
* // There is no need for a receival function, the presence is the value.
* if (attrs[ATTR_FLAG])
* // flag is present
* @endcode
*
* @par Micro Seconds (NLA_MSECS)
*
* @par Nested Attribute (NLA_NESTED)
* Attributes can be nested and put into a container to create groups, lists
* or to construct trees of attributes. Nested attributes are often used to
* pass attributes to a subsystem where the top layer has no knowledge of the
* configuration possibilities of each subsystem.
* @par
* \b Note: When validating the attributes using nlmsg_validate() or
* nlmsg_parse() it will only affect the top level attributes. Each
* level of nested attributes must be validated seperately using
* nla_parse_nested() or nla_validate().
* @par
* @code
* // The minimal length policy may be used to enforce the presence of at
* // least one attribute.
* static struct nla_policy my_policy[ATTR_MAX+1] = {
* [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN },
*
* // Nested attributes are constructed by enclosing the attributes
* // to be nested with calls to nla_nest_start() respetively nla_nest_end().
* struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS);
* nla_put_u32(msg, ATTR_FOO, 123);
* nla_put_string(msg, ATTR_BAR, "some text");
* nla_nest_end(msg, opts);
*
* // Various methods exist to parse nested attributes, the easiest being
* // nla_parse_nested() which also allows validation in the same step.
* if (attrs[ATTR_OPTS]) {
* struct nlattr *nested[ATTR_MAX+1];
*
* nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy);
*
* if (nested[ATTR_FOO])
* uint32_t foo = nla_get_u32(nested[ATTR_FOO]);
* }
* @endcode
*
* @subsection attr_exceptions Exception Based Attribute Construction
* Often a large number of attributes are added to a message in a single
* function. In order to simplify error handling, a second set of
* construction functions exist which jump to a error label when they
* fail instead of returning an error code. This second set consists
* of macros which are named after their error code based counterpart
* except that the name is written all uppercase.
*
* All of the macros jump to the target \c nla_put_failure if they fail.
* @code
* void my_func(struct nl_msg *msg)
* {
* NLA_PUT_U32(msg, ATTR_FOO, 10);
* NLA_PUT_STRING(msg, ATTR_BAR, "bar");
*
* return 0;
*
* nla_put_failure:
* return -NLE_NOMEM;
* }
* @endcode
*
* @subsection attr_examples Examples
* @par Example 1.1 Constructing a netlink message with attributes.
* @code
* struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu)
* {
* struct nl_msg *msg;
* struct nlattr *info, *vlan;
* struct ifinfomsg ifi = {
* .ifi_family = AF_INET,
* .ifi_index = ifindex,
* };
*
* // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO
* if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO)))
* return NULL;
*
* // Append the family specific header (struct ifinfomsg)
* if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
* goto nla_put_failure
*
* // Append a 32 bit integer attribute to carry the MTU
* NLA_PUT_U32(msg, IFLA_MTU, mtu);
*
* // Append a unspecific attribute to carry the link layer address
* NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr);
*
* // Append a container for nested attributes to carry link information
* if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
* goto nla_put_failure;
*
* // Put a string attribute into the container
* NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan");
*
* // Append another container inside the open container to carry
* // vlan specific attributes
* if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA)))
* goto nla_put_failure;
*
* // add vlan specific info attributes here...
*
* // Finish nesting the vlan attributes and close the second container.
* nla_nest_end(msg, vlan);
*
* // Finish nesting the link info attribute and close the first container.
* nla_nest_end(msg, info);
*
* return msg;
*
* // If any of the construction macros fails, we end up here.
* nla_put_failure:
* nlmsg_free(msg);
* return NULL;
* }
* @endcode
*
* @par Example 2.1 Parsing a netlink message with attributes.
* @code
* int parse_message(struct nl_msg *msg)
* {
* // The policy defines two attributes: a 32 bit integer and a container
* // for nested attributes.
* struct nla_policy attr_policy[ATTR_MAX+1] = {
* [ATTR_FOO] = { .type = NLA_U32 },
* [ATTR_BAR] = { .type = NLA_NESTED },
* };
* struct nlattr *attrs[ATTR_MAX+1];
* int err;
*
* // The nlmsg_parse() function will make sure that the message contains
* // enough payload to hold the header (struct my_hdr), validates any
* // attributes attached to the messages and stores a pointer to each
* // attribute in the attrs[] array accessable by attribute type.
* if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
* ATTR_MAX, attr_policy)) < 0)
* goto errout;
*
* if (attrs[ATTR_FOO]) {
* // It is safe to directly access the attribute payload without
* // any further checks since nlmsg_parse() enforced the policy.
* uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
* }
*
* if (attrs[ATTR_BAR]) {
* struct nlattr *nested[NESTED_MAX+1];
*
* // Attributes nested in a container can be parsed the same way
* // as top level attributes.
* if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR],
* nested_policy)) < 0)
* goto errout;
*
* // Process nested attributes here.
* }
*
* err = 0;
* errout:
* return err;
* }
* @endcode
*
* @{
*/
/**
* @name Attribute Size Calculation
* @{
*/
/** @} */
/**
* @name Parsing Attributes
* @{
*/
/**
* Check if the attribute header and payload can be accessed safely.
* @arg nla Attribute of any kind.
* @arg remaining Number of bytes remaining in attribute stream.
*
* Verifies that the header and payload do not exceed the number of
* bytes left in the attribute stream. This function must be called
* before access the attribute header or payload when iterating over
* the attribute stream using nla_next().
*
* @return True if the attribute can be accessed safely, false otherwise.
*/
int nla_ok(const struct nlattr *nla, int remaining)
{
return remaining >= sizeof(*nla) &&
nla->nla_len >= sizeof(*nla) &&
nla->nla_len <= remaining;
}
/**
* Return next attribute in a stream of attributes.
* @arg nla Attribute of any kind.
* @arg remaining Variable to count remaining bytes in stream.
*
* Calculates the offset to the next attribute based on the attribute
* given. The attribute provided is assumed to be accessible, the
* caller is responsible to use nla_ok() beforehand. The offset (length
* of specified attribute including padding) is then subtracted from
* the remaining bytes variable and a pointer to the next attribute is
* returned.
*
* nla_next() can be called as long as remainig is >0.
*
* @return Pointer to next 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,
};
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 -NLE_RANGE;
if (nla_len(nla) < minlen)
return -NLE_RANGE;
if (pt->maxlen && nla_len(nla) > pt->maxlen)
return -NLE_RANGE;
if (pt->type == NLA_STRING) {
char *data = nla_data(nla);
if (data[nla_len(nla) - 1] != '\0')
return -NLE_INVAL;
}
return 0;
}
/**
* Create attribute index based on a stream of attributes.
* @arg tb Index array to be filled (maxtype+1 elements).
* @arg maxtype Maximum attribute type expected and accepted.
* @arg head Head of attribute stream.
* @arg len Length of attribute stream.
* @arg policy Attribute validation policy.
*
* Iterates over the stream of attributes and stores a pointer to each
* attribute in the index array using the attribute type as index to
* the array. Attribute with a type greater than the maximum type
* specified will be silently ignored in order to maintain backwards
* compatibility. If \a policy is not NULL, the attribute will be
* validated using the specified policy.
*
* @see nla_validate
* @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;
}
/**
* Validate a stream of attributes.
* @arg head Head of attributes stream.
* @arg len Length of attributes stream.
* @arg maxtype Maximum attribute type expected and accepted.
* @arg policy Validation policy.
*
* Iterates over the stream of attributes and validates each attribute
* one by one using the specified policy. Attributes with a type greater
* than the maximum type specified will be silently ignored in order to
* maintain backwards compatibility.
*
* See \ref attr_datatypes for more details on what kind of validation
* checks are performed on each attribute data type.
*
* @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 single attribute in a stream of attributes.
* @arg head Head of attributes stream.
* @arg len Length of attributes stream.
* @arg attrtype Attribute type to look for.
*
* Iterates over the stream of attributes and compares each type with
* the type specified. Returns the first attribute which matches the
* type.
*
* @return Pointer to attribute found or NULL.
*/
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 Unspecific Attribute
* @{
*/
/**
* Reserve space for a attribute.
* @arg msg Netlink Message.
* @arg attrtype Attribute Type.
* @arg attrlen Length of payload.
*
* Reserves room for a attribute in the specified netlink message and
* fills in the attribute header (type, length). Returns NULL if there
* is unsuficient space for the attribute.
*
* Any padding between payload and the start of the next attribute is
* zeroed out.
*
* @return Pointer to start of attribute or NULL on failure.
*/
struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
{
struct nlattr *nla;
int tlen;
tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size)
return NULL;
nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
nla->nla_type = attrtype;
nla->nla_len = nla_attr_size(attrlen);
memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
msg->nm_nlh->nlmsg_len = tlen;
NL_DBG(2, "msg %p: Reserved %d bytes at offset +%td for attr %d "
"nlmsg_len=%d\n", msg, attrlen,
(void *) nla - nlmsg_data(msg->nm_nlh),
attrtype, msg->nm_nlh->nlmsg_len);
return nla;
}
/**
* Add a unspecific attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg datalen Length of data to be used as payload.
* @arg data Pointer to data to be used as attribute payload.
*
* Reserves room for a unspecific attribute and copies the provided data
* into the message as payload of the attribute. Returns an error if there
* is insufficient space for the attribute.
*
* @see nla_reserve
* @return 0 on success or a negative error code.
*/
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
{
struct nlattr *nla;
nla = nla_reserve(msg, attrtype, datalen);
if (!nla)
return -NLE_NOMEM;
memcpy(nla_data(nla), data, datalen);
NL_DBG(2, "msg %p: Wrote %d bytes at offset +%td for attr %d\n",
msg, datalen, (void *) nla - nlmsg_data(msg->nm_nlh), attrtype);
return 0;
}
/** @} */

View File

@ -0,0 +1,376 @@
/*
* lib/cache.c Caching Module
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cache_mngt
* @defgroup cache Cache
*
* @code
* Cache Management | | Type Specific Cache Operations
*
* | | +----------------+ +------------+
* | request update | | msg_parser |
* | | +----------------+ +------------+
* +- - - - -^- - - - - - - -^- -|- - - -
* nl_cache_update: | | | |
* 1) --------- co_request_update ------+ | |
* | | |
* 2) destroy old cache +----------- pp_cb ---------|---+
* | | |
* 3) ---------- nl_recvmsgs ----------+ +- cb_valid -+
* +--------------+ | | | |
* | nl_cache_add |<-----+ + - - -v- -|- - - - - - - - - - -
* +--------------+ | | +-------------+
* | nl_recvmsgs |
* | | +-----|-^-----+
* +---v-|---+
* | | | nl_recv |
* +---------+
* | | Core Netlink
* @endcode
*
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/object.h>
#include <netlink/utils.h>
/**
* @name Cache Creation/Deletion
* @{
*/
/**
* Allocate an empty cache
* @arg ops cache operations to base the cache on
*
* @return A newly allocated and initialized cache.
*/
struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
{
struct nl_cache *cache;
cache = calloc(1, sizeof(*cache));
if (!cache)
return NULL;
nl_init_list_head(&cache->c_items);
cache->c_ops = ops;
NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
return cache;
}
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
struct nl_cache **result)
{
struct nl_cache *cache;
int err;
if (!(cache = nl_cache_alloc(ops)))
return -NLE_NOMEM;
if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
nl_cache_free(cache);
return err;
}
*result = cache;
return 0;
}
/**
* Clear a cache.
* @arg cache cache to clear
*
* Removes all elements of a cache.
*/
void nl_cache_clear(struct nl_cache *cache)
{
struct nl_object *obj, *tmp;
NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
nl_cache_remove(obj);
}
/**
* Free a cache.
* @arg cache Cache to free.
*
* Removes all elements of a cache and frees all memory.
*
* @note Use this function if you are working with allocated caches.
*/
void nl_cache_free(struct nl_cache *cache)
{
if (!cache)
return;
nl_cache_clear(cache);
NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
free(cache);
}
/** @} */
/**
* @name Cache Modifications
* @{
*/
static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
{
obj->ce_cache = cache;
nl_list_add_tail(&obj->ce_list, &cache->c_items);
cache->c_nitems++;
NL_DBG(1, "Added %p to cache %p <%s>.\n",
obj, cache, nl_cache_name(cache));
return 0;
}
/**
* Add object to a cache.
* @arg cache Cache to add object to
* @arg obj Object to be added to the cache
*
* Adds the given object to the specified cache. The object is cloned
* if it has been added to another cache already.
*
* @return 0 or a negative error code.
*/
int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
{
struct nl_object *new;
if (cache->c_ops->co_obj_ops != obj->ce_ops)
return -NLE_OBJ_MISMATCH;
if (!nl_list_empty(&obj->ce_list)) {
new = nl_object_clone(obj);
if (!new)
return -NLE_NOMEM;
} else {
nl_object_get(obj);
new = obj;
}
return __cache_add(cache, new);
}
/**
* Removes an object from a cache.
* @arg obj Object to remove from its cache
*
* Removes the object \c obj from the cache it is assigned to, since
* an object can only be assigned to one cache at a time, the cache
* must ne be passed along with it.
*/
void nl_cache_remove(struct nl_object *obj)
{
struct nl_cache *cache = obj->ce_cache;
if (cache == NULL)
return;
nl_list_del(&obj->ce_list);
obj->ce_cache = NULL;
nl_object_put(obj);
cache->c_nitems--;
NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
obj, cache, nl_cache_name(cache));
}
/** @} */
/**
* @name Synchronization
* @{
*/
/**
* Request a full dump from the kernel to fill a cache
* @arg sk Netlink socket.
* @arg cache Cache subjected to be filled.
*
* Send a dumping request to the kernel causing it to dump all objects
* related to the specified cache to the netlink socket.
*
* Use nl_cache_pickup() to read the objects from the socket and fill them
* into a cache.
*/
int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache)
{
NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
cache, nl_cache_name(cache));
if (cache->c_ops->co_request_update == NULL)
return -NLE_OPNOTSUPP;
return cache->c_ops->co_request_update(cache, sk);
}
/** @cond SKIP */
struct update_xdata {
struct nl_cache_ops *ops;
struct nl_parser_param *params;
};
static int update_msg_parser(struct nl_msg *msg, void *arg)
{
struct update_xdata *x = arg;
return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
}
/** @endcond */
int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
struct nl_parser_param *param)
{
int err;
struct nl_cb *cb;
struct update_xdata x = {
.ops = cache->c_ops,
.params = param,
};
NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
cache, nl_cache_name(cache));
cb = nl_cb_clone(sk->s_cb);
if (cb == NULL)
return -NLE_NOMEM;
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
err = nl_recvmsgs(sk, cb);
if (err < 0)
NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
"%d: %s", cache, nl_cache_name(cache),
err, nl_geterror(err));
nl_cb_put(cb);
return err;
}
static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
{
return nl_cache_add((struct nl_cache *) p->pp_arg, c);
}
/**
* Pickup a netlink dump response and put it into a cache.
* @arg sk Netlink socket.
* @arg cache Cache to put items into.
*
* Waits for netlink messages to arrive, parses them and puts them into
* the specified cache.
*
* @return 0 on success or a negative error code.
*/
int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
{
struct nl_parser_param p = {
.pp_cb = pickup_cb,
.pp_arg = cache,
};
return __cache_pickup(sk, cache, &p);
}
/** @} */
/**
* @name Parsing
* @{
*/
/** @cond SKIP */
int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *params)
{
int i, err;
if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
return -NLE_MSG_TOOSHORT;
for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
err = ops->co_msg_parser(ops, who, nlh, params);
if (err != -NLE_OPNOTSUPP)
goto errout;
}
}
err = -NLE_MSGTYPE_NOSUPPORT;
errout:
return err;
}
/** @endcond */
/**
* Parse a netlink message and add it to the cache.
* @arg cache cache to add element to
* @arg msg netlink message
*
* Parses a netlink message by calling the cache specific message parser
* and adds the new element to the cache.
*
* @return 0 or a negative error code.
*/
int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
{
struct nl_parser_param p = {
.pp_cb = pickup_cb,
.pp_arg = cache,
};
return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
}
/**
* (Re)fill a cache with the contents in the kernel.
* @arg sk Netlink socket.
* @arg cache cache to update
*
* Clears the specified cache and fills it with the current state in
* the kernel.
*
* @return 0 or a negative error code.
*/
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
{
int err;
err = nl_cache_request_full_dump(sk, cache);
if (err < 0)
return err;
NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
cache, nl_cache_name(cache));
nl_cache_clear(cache);
return nl_cache_pickup(sk, cache);
}
/** @} */

View File

@ -0,0 +1,131 @@
/*
* lib/cache_mngt.c Cache Management
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup core
* @defgroup cache_mngt Caching
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
static struct nl_cache_ops *cache_ops;
/**
* @name Cache Operations Sets
* @{
*/
/**
* Lookup the set cache operations of a certain cache type
* @arg name name of the cache type
*
* @return The cache operations or NULL if no operations
* have been registered under the specified name.
*/
struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
{
struct nl_cache_ops *ops;
for (ops = cache_ops; ops; ops = ops->co_next)
if (!strcmp(ops->co_name, name))
return ops;
return NULL;
}
/**
* Associate a message type to a set of cache operations
* @arg protocol netlink protocol
* @arg msgtype netlink message type
*
* Associates the specified netlink message type with
* a registered set of cache operations.
*
* @return The cache operations or NULL if no association
* could be made.
*/
struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
{
int i;
struct nl_cache_ops *ops;
for (ops = cache_ops; ops; ops = ops->co_next) {
if (ops->co_protocol != protocol)
continue;
for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
if (ops->co_msgtypes[i].mt_id == msgtype)
return ops;
}
return NULL;
}
/**
* Register a set of cache operations
* @arg ops cache operations
*
* Called by users of caches to announce the avaibility of
* a certain cache type.
*
* @return 0 on success or a negative error code.
*/
int nl_cache_mngt_register(struct nl_cache_ops *ops)
{
if (!ops->co_name || !ops->co_obj_ops)
return -NLE_INVAL;
if (nl_cache_ops_lookup(ops->co_name))
return -NLE_EXIST;
ops->co_next = cache_ops;
cache_ops = ops;
NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
return 0;
}
/**
* Unregister a set of cache operations
* @arg ops cache operations
*
* Called by users of caches to announce a set of
* cache operations is no longer available. The
* specified cache operations must have been registered
* previously using nl_cache_mngt_register()
*
* @return 0 on success or a negative error code
*/
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
{
struct nl_cache_ops *t, **tp;
for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
if (t == ops)
break;
if (!t)
return -NLE_NOCACHE;
NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
*tp = t->co_next;
return 0;
}
/** @} */
/** @} */

View File

@ -0,0 +1,116 @@
/*
* lib/error.c Error Handling
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
static const char *errmsg[NLE_MAX+1] = {
[NLE_SUCCESS] = "Success",
[NLE_FAILURE] = "Unspecific failure",
[NLE_INTR] = "Interrupted system call",
[NLE_BAD_SOCK] = "Bad socket",
[NLE_AGAIN] = "Try again",
[NLE_NOMEM] = "Out of memory",
[NLE_EXIST] = "Object exists",
[NLE_INVAL] = "Invalid input data or parameter",
[NLE_RANGE] = "Input data out of range",
[NLE_MSGSIZE] = "Message size not sufficient",
[NLE_OPNOTSUPP] = "Operation not supported",
[NLE_AF_NOSUPPORT] = "Address family not supported",
[NLE_OBJ_NOTFOUND] = "Object not found",
[NLE_NOATTR] = "Attribute not available",
[NLE_MISSING_ATTR] = "Missing attribute",
[NLE_AF_MISMATCH] = "Address family mismatch",
[NLE_SEQ_MISMATCH] = "Message sequence number mismatch",
[NLE_MSG_OVERFLOW] = "Kernel reported message overflow",
[NLE_MSG_TRUNC] = "Kernel reported truncated message",
[NLE_NOADDR] = "Invalid address for specified address family",
[NLE_SRCRT_NOSUPPORT] = "Source based routing not supported",
[NLE_MSG_TOOSHORT] = "Netlink message is too short",
[NLE_MSGTYPE_NOSUPPORT] = "Netlink message type is not supported",
[NLE_OBJ_MISMATCH] = "Object type does not match cache",
[NLE_NOCACHE] = "Unknown or invalid cache type",
[NLE_BUSY] = "Object busy",
[NLE_PROTO_MISMATCH] = "Protocol mismatch",
[NLE_NOACCESS] = "No Access",
[NLE_PERM] = "Operation not permitted",
[NLE_PKTLOC_FILE] = "Unable to open packet location file",
[NLE_PARSE_ERR] = "Unable to parse object",
[NLE_NODEV] = "No such device",
[NLE_IMMUTABLE] = "Immutable attribute",
[NLE_DUMP_INTR] = "Dump inconsistency detected, interrupted",
};
/**
* Return error message for an error code
* @return error message
*/
const char *nl_geterror(int error)
{
error = abs(error);
if (error > NLE_MAX)
error = NLE_FAILURE;
return errmsg[error];
}
/**
* Print a libnl error message
* @arg s error message prefix
*
* Prints the error message of the call that failed last.
*
* If s is not NULL and *s is not a null byte the argument
* string is printed, followed by a colon and a blank. Then
* the error message and a new-line.
*/
void nl_perror(int error, const char *s)
{
if (s && *s)
fprintf(stderr, "%s: %s\n", s, nl_geterror(error));
else
fprintf(stderr, "%s\n", nl_geterror(error));
}
int nl_syserr2nlerr(int error)
{
error = abs(error);
switch (error) {
case EBADF: return NLE_BAD_SOCK;
case EADDRINUSE: return NLE_EXIST;
case EEXIST: return NLE_EXIST;
case EADDRNOTAVAIL: return NLE_NOADDR;
case ESRCH: /* fall through */
case ENOENT: return NLE_OBJ_NOTFOUND;
case EINTR: return NLE_INTR;
case EAGAIN: return NLE_AGAIN;
case ENOTSOCK: return NLE_BAD_SOCK;
case ENOPROTOOPT: return NLE_INVAL;
case EFAULT: return NLE_INVAL;
case EACCES: return NLE_NOACCESS;
case EINVAL: return NLE_INVAL;
case ENOBUFS: return NLE_NOMEM;
case ENOMEM: return NLE_NOMEM;
case EAFNOSUPPORT: return NLE_AF_NOSUPPORT;
case EPROTONOSUPPORT: return NLE_PROTO_MISMATCH;
case EOPNOTSUPP: return NLE_OPNOTSUPP;
case EPERM: return NLE_PERM;
case EBUSY: return NLE_BUSY;
case ERANGE: return NLE_RANGE;
case ENODEV: return NLE_NODEV;
default: return NLE_FAILURE;
}
}
/** @} */

View File

@ -0,0 +1,268 @@
/*
* lib/genl/genl.c Generic Netlink
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @defgroup genl Generic Netlink
*
* @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
* @{
*/
#include <netlink-generic.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/utils.h>
/**
* @name Socket Creating
* @{
*/
int genl_connect(struct nl_sock *sk)
{
return nl_connect(sk, NETLINK_GENERIC);
}
/** @} */
/**
* @name Sending
* @{
*/
/**
* 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.
*
* Fills out a routing netlink request message and sends it out
* using nl_send_simple().
*
* @return 0 on success or a negative error code.
*/
int genl_send_simple(struct nl_sock *sk, int family, int cmd,
int version, int flags)
{
struct genlmsghdr hdr = {
.cmd = cmd,
.version = version,
};
return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
}
/** @} */
/**
* @name Message Parsing
* @{
*/
int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
{
struct genlmsghdr *ghdr;
if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
return 0;
ghdr = nlmsg_data(nlh);
if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
return 0;
return 1;
}
int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
struct nla_policy *policy)
{
struct genlmsghdr *ghdr;
if (!genlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
ghdr = nlmsg_data(nlh);
return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
}
int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
int maxtype, struct nla_policy *policy)
{
struct genlmsghdr *ghdr;
if (!genlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
ghdr = nlmsg_data(nlh);
return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
genlmsg_attrlen(ghdr, hdrlen), policy);
}
/**
* Get head of message payload
* @arg gnlh genetlink messsage header
*/
void *genlmsg_data(const struct genlmsghdr *gnlh)
{
return ((unsigned char *) gnlh + GENL_HDRLEN);
}
/**
* Get lenght of message payload
* @arg gnlh genetlink message header
*/
int genlmsg_len(const struct genlmsghdr *gnlh)
{
struct nlmsghdr *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
*/
struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
{
return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen);
}
/**
* Get length of attribute data
* @arg gnlh generic netlink message header
* @arg hdrlen length of family specific header
*/
int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
{
return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
}
/** @} */
/**
* @name Message Building
* @{
*/
/**
* 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
*
* Returns pointer to user specific header.
*/
void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
int hdrlen, int flags, uint8_t cmd, uint8_t version)
{
struct nlmsghdr *nlh;
struct genlmsghdr hdr = {
.cmd = cmd,
.version = version,
};
nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
if (nlh == NULL)
return NULL;
memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
msg, cmd, version);
return nlmsg_data(nlh) + GENL_HDRLEN;
}
/** @} */
/** @} */

View File

@ -0,0 +1,380 @@
/*
* lib/genl/ctrl.c Generic Netlink Controller
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup genl_mngt
* @defgroup ctrl Controller
* @brief
*
* @{
*/
#include <netlink-generic.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/mngt.h>
#include <netlink/genl/ctrl.h>
#include <netlink/utils.h>
/** @cond SKIP */
#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)
{
return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
CTRL_VERSION, NLM_F_DUMP);
}
static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
.maxlen = GENL_NAMSIZ },
[CTRL_ATTR_VERSION] = { .type = NLA_U32 },
[CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
[CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
[CTRL_ATTR_OPS] = { .type = NLA_NESTED },
[CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
};
static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
[CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
[CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
};
static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
[CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
[CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 },
};
static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
struct genl_info *info, void *arg)
{
struct genl_family *family;
struct nl_parser_param *pp = arg;
int err;
family = genl_family_alloc();
if (family == NULL) {
err = -NLE_NOMEM;
goto errout;
}
if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
err = -NLE_MISSING_ATTR;
goto errout;
}
if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
err = -NLE_MISSING_ATTR;
goto errout;
}
family->ce_msgtype = info->nlh->nlmsg_type;
genl_family_set_id(family,
nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
genl_family_set_name(family,
nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
if (info->attrs[CTRL_ATTR_VERSION]) {
uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
genl_family_set_version(family, version);
}
if (info->attrs[CTRL_ATTR_HDRSIZE]) {
uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
genl_family_set_hdrsize(family, hdrsize);
}
if (info->attrs[CTRL_ATTR_MAXATTR]) {
uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
genl_family_set_maxattr(family, maxattr);
}
if (info->attrs[CTRL_ATTR_OPS]) {
struct nlattr *nla, *nla_ops;
int remaining;
nla_ops = info->attrs[CTRL_ATTR_OPS];
nla_for_each_nested(nla, nla_ops, remaining) {
struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
int flags = 0, id;
err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
family_op_policy);
if (err < 0)
goto errout;
if (tb[CTRL_ATTR_OP_ID] == NULL) {
err = -NLE_MISSING_ATTR;
goto errout;
}
id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
if (tb[CTRL_ATTR_OP_FLAGS])
flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
err = genl_family_add_op(family, id, flags);
if (err < 0)
goto errout;
}
}
if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
struct nlattr *nla, *nla_grps;
int remaining;
nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS];
nla_for_each_nested(nla, nla_grps, remaining) {
struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
int id;
const char * name;
err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
family_grp_policy);
if (err < 0)
goto errout;
if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
err = -NLE_MISSING_ATTR;
goto errout;
}
id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
err = -NLE_MISSING_ATTR;
goto errout;
}
name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
err = genl_family_add_grp(family, id, name);
if (err < 0)
goto errout;
}
}
err = pp->pp_cb((struct nl_object *) family, pp);
errout:
genl_family_put(family);
return err;
}
/**
* @name Cache Management
* @{
*/
int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
{
return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
}
/**
* Look up generic netlink family by id in the provided cache.
* @arg cache Generic netlink family cache.
* @arg id 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().
*
* @return Generic netlink family object or NULL if no match was found.
*/
struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
{
struct genl_family *fam;
if (cache->c_ops != &genl_ctrl_ops)
BUG();
nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
if (fam->gf_id == id) {
nl_object_get((struct nl_object *) fam);
return fam;
}
}
return NULL;
}
/**
* @name Resolver
* @{
*/
/**
* Look up generic netlink family by family name in the provided cache.
* @arg cache Generic netlink family cache.
* @arg name Family name.
*
* 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().
*
* @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)
{
struct genl_family *fam;
if (cache->c_ops != &genl_ctrl_ops)
BUG();
nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
if (!strcmp(name, fam->gf_name)) {
nl_object_get((struct nl_object *) fam);
return fam;
}
}
return NULL;
}
/** @} */
/**
* Resolve generic netlink family name to its identifier
* @arg sk Netlink socket.
* @arg name Name of generic netlink family
*
* Resolves the generic netlink family name to its identifer and returns
* it.
*
* @return A positive identifier or a negative error code.
*/
int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
{
struct nl_cache *cache;
struct genl_family *family;
int err;
if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
return err;
family = genl_ctrl_search_by_name(cache, name);
if (family == NULL) {
err = -NLE_OBJ_NOTFOUND;
goto errout;
}
err = genl_family_get_id(family);
genl_family_put(family);
errout:
nl_cache_free(cache);
return err;
}
static int genl_ctrl_grp_by_name(const struct genl_family *family,
const char *grp_name)
{
struct genl_family_grp *grp;
nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
if (!strcmp(grp->name, grp_name)) {
return grp->id;
}
}
return -NLE_OBJ_NOTFOUND;
}
int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
const char *grp_name)
{
struct nl_cache *cache;
struct genl_family *family;
int err;
if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
return err;
family = genl_ctrl_search_by_name(cache, family_name);
if (family == NULL) {
err = -NLE_OBJ_NOTFOUND;
goto errout;
}
err = genl_ctrl_grp_by_name(family, grp_name);
genl_family_put(family);
errout:
nl_cache_free(cache);
return err;
}
/** @} */
static struct genl_cmd genl_cmds[] = {
{
.c_id = CTRL_CMD_NEWFAMILY,
.c_name = "NEWFAMILY" ,
.c_maxattr = CTRL_ATTR_MAX,
.c_attr_policy = ctrl_policy,
.c_msg_parser = ctrl_msg_parser,
},
{
.c_id = CTRL_CMD_DELFAMILY,
.c_name = "DELFAMILY" ,
},
{
.c_id = CTRL_CMD_GETFAMILY,
.c_name = "GETFAMILY" ,
},
{
.c_id = CTRL_CMD_NEWOPS,
.c_name = "NEWOPS" ,
},
{
.c_id = CTRL_CMD_DELOPS,
.c_name = "DELOPS" ,
},
};
static struct genl_ops genl_ops = {
.o_cmds = genl_cmds,
.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",
.co_hdrsize = GENL_HDRSIZE(0),
.co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
.co_genl = &genl_ops,
.co_protocol = NETLINK_GENERIC,
.co_request_update = ctrl_request_update,
.co_obj_ops = &genl_family_ops,
};
static void __init ctrl_init(void)
{
genl_register(&genl_ctrl_ops);
}
static void __exit ctrl_exit(void)
{
genl_unregister(&genl_ctrl_ops);
}
/** @} */

View File

@ -0,0 +1,169 @@
/*
* lib/genl/family.c Generic Netlink Family
*
* 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>
*/
/**
* @ingroup genl
* @defgroup genl_family Generic Netlink Family
* @brief
*
* @{
*/
#include <netlink-generic.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/utils.h>
struct nl_object_ops genl_family_ops;
/** @endcond */
static void family_constructor(struct nl_object *c)
{
struct genl_family *family = (struct genl_family *) c;
nl_init_list_head(&family->gf_ops);
nl_init_list_head(&family->gf_mc_grps);
}
static void family_free_data(struct nl_object *c)
{
struct genl_family *family = (struct genl_family *) c;
struct genl_family_op *ops, *tmp;
struct genl_family_grp *grp, *t_grp;
if (family == NULL)
return;
nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
nl_list_del(&ops->o_list);
free(ops);
}
nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) {
nl_list_del(&grp->list);
free(grp);
}
}
static int family_clone(struct nl_object *_dst, struct nl_object *_src)
{
struct genl_family *dst = nl_object_priv(_dst);
struct genl_family *src = nl_object_priv(_src);
struct genl_family_op *ops;
struct genl_family_grp *grp;
int err;
nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
if (err < 0)
return err;
}
nl_list_for_each_entry(grp, &src->gf_mc_grps, list) {
err = genl_family_add_grp(dst, grp->id, grp->name);
if (err < 0)
return err;
}
return 0;
}
static int family_compare(struct nl_object *_a, struct nl_object *_b,
uint32_t attrs, int flags)
{
struct genl_family *a = (struct genl_family *) _a;
struct genl_family *b = (struct genl_family *) _b;
int diff = 0;
#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
diff |= FAM_DIFF(ID, a->gf_id != b->gf_id);
diff |= FAM_DIFF(VERSION, a->gf_version != b->gf_version);
diff |= FAM_DIFF(HDRSIZE, a->gf_hdrsize != b->gf_hdrsize);
diff |= FAM_DIFF(MAXATTR, a->gf_maxattr != b->gf_maxattr);
diff |= FAM_DIFF(NAME, strcmp(a->gf_name, b->gf_name));
#undef FAM_DIFF
return diff;
}
/**
* @name Family Object
* @{
*/
struct genl_family *genl_family_alloc(void)
{
return (struct genl_family *) nl_object_alloc(&genl_family_ops);
}
void genl_family_put(struct genl_family *family)
{
nl_object_put((struct nl_object *) family);
}
/** @} */
int genl_family_add_op(struct genl_family *family, int id, int flags)
{
struct genl_family_op *op;
op = calloc(1, sizeof(*op));
if (op == NULL)
return -NLE_NOMEM;
op->o_id = id;
op->o_flags = flags;
nl_list_add_tail(&op->o_list, &family->gf_ops);
family->ce_mask |= FAMILY_ATTR_OPS;
return 0;
}
int genl_family_add_grp(struct genl_family *family, uint32_t id,
const char *name)
{
struct genl_family_grp *grp;
grp = calloc(1, sizeof(*grp));
if (grp == NULL)
return -NLE_NOMEM;
grp->id = id;
strncpy(grp->name, name, GENL_NAMSIZ - 1);
nl_list_add_tail(&grp->list, &family->gf_mc_grps);
return 0;
}
/** @} */
/** @cond SKIP */
struct nl_object_ops genl_family_ops = {
.oo_name = "genl/family",
.oo_size = sizeof(struct genl_family),
.oo_constructor = family_constructor,
.oo_free_data = family_free_data,
.oo_clone = family_clone,
.oo_compare = family_compare,
.oo_id_attrs = FAMILY_ATTR_ID,
};
/** @endcond */
/** @} */

View File

@ -0,0 +1,193 @@
/*
* lib/genl/mngt.c Generic Netlink Management
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup genl
* @defgroup genl_mngt Management
*
* @par 1) Registering a generic netlink module
* @code
* #include <netlink/genl/mngt.h>
*
* // 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
* @{
*/
#include <netlink-generic.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/mngt.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/utils.h>
static NL_LIST_HEAD(genl_ops_list);
static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
int i, err;
struct genlmsghdr *ghdr;
struct genl_cmd *cmd;
ghdr = nlmsg_data(nlh);
if (ops->co_genl == NULL)
BUG();
for (i = 0; i < ops->co_genl->o_ncmds; i++) {
cmd = &ops->co_genl->o_cmds[i];
if (cmd->c_id == ghdr->cmd)
goto found;
}
err = -NLE_MSGTYPE_NOSUPPORT;
goto errout;
found:
if (cmd->c_msg_parser == NULL)
err = -NLE_OPNOTSUPP;
else {
struct nlattr *tb[cmd->c_maxattr + 1];
struct genl_info info = {
.who = who,
.nlh = nlh,
.genlhdr = ghdr,
.userhdr = genlmsg_data(ghdr),
.attrs = tb,
};
err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr,
cmd->c_attr_policy);
if (err < 0)
goto errout;
err = cmd->c_msg_parser(ops, cmd, &info, pp);
}
errout:
return err;
}
/**
* @name Register/Unregister
* @{
*/
/**
* Register generic netlink operations
* @arg ops cache operations
*/
int genl_register(struct nl_cache_ops *ops)
{
int err;
if (ops->co_protocol != NETLINK_GENERIC) {
err = -NLE_PROTO_MISMATCH;
goto errout;
}
if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
err = -NLE_INVAL;
goto errout;
}
if (ops->co_genl == NULL) {
err = -NLE_INVAL;
goto errout;
}
ops->co_genl->o_cache_ops = ops;
ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
ops->co_genl->o_family = ops->co_msgtypes[0].mt_id;
ops->co_msg_parser = genl_msg_parser;
/* FIXME: check for dup */
nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list);
err = nl_cache_mngt_register(ops);
errout:
return err;
}
/**
* Unregister generic netlink operations
* @arg ops cache operations
*/
void genl_unregister(struct nl_cache_ops *ops)
{
nl_cache_mngt_unregister(ops);
nl_list_del(&ops->co_genl->o_list);
}
/** @} */
/** @} */

View File

@ -0,0 +1,162 @@
/*
* lib/handlers.c default netlink message handlers
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup core
* @defgroup cb Callbacks/Customization
*
* @details
* @par 1) Setting up a callback set
* @code
* // Allocate a callback set and initialize it to the verbose default set
* struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
*
* // Modify the set to call my_func() for all valid messages
* nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
*
* // Set the error message handler to the verbose default implementation
* // and direct it to print all errors to the given file descriptor.
* FILE *file = fopen(...);
* nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
* @endcode
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/msg.h>
#include <netlink/handlers.h>
/**
* @name Callback Handle Management
* @{
*/
/**
* Allocate a new callback handle
* @arg kind callback kind to be used for initialization
* @return Newly allocated callback handle or NULL
*/
struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
{
int i;
struct nl_cb *cb;
if (kind < 0 || kind > NL_CB_KIND_MAX)
return NULL;
cb = calloc(1, sizeof(*cb));
if (!cb)
return NULL;
cb->cb_refcnt = 1;
for (i = 0; i <= NL_CB_TYPE_MAX; i++)
nl_cb_set(cb, i, kind, NULL, NULL);
nl_cb_err(cb, kind, NULL, NULL);
return cb;
}
/**
* Clone an existing callback handle
* @arg orig original callback handle
* @return Newly allocated callback handle being a duplicate of
* orig or NULL
*/
struct nl_cb *nl_cb_clone(struct nl_cb *orig)
{
struct nl_cb *cb;
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb)
return NULL;
memcpy(cb, orig, sizeof(*orig));
cb->cb_refcnt = 1;
return cb;
}
void nl_cb_put(struct nl_cb *cb)
{
if (!cb)
return;
cb->cb_refcnt--;
if (cb->cb_refcnt < 0)
BUG();
if (cb->cb_refcnt <= 0)
free(cb);
}
/** @} */
/**
* @name Callback Setup
* @{
*/
/**
* Set up a callback
* @arg cb callback set
* @arg type callback to modify
* @arg kind kind of implementation
* @arg func callback function (NL_CB_CUSTOM)
* @arg arg argument passed to callback
*
* @return 0 on success or a negative error code
*/
int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
nl_recvmsg_msg_cb_t func, void *arg)
{
if (type < 0 || type > NL_CB_TYPE_MAX)
return -NLE_RANGE;
if (kind < 0 || kind > NL_CB_KIND_MAX)
return -NLE_RANGE;
if (kind == NL_CB_CUSTOM) {
cb->cb_set[type] = func;
cb->cb_args[type] = arg;
}
return 0;
}
/**
* Set up an error callback
* @arg cb callback set
* @arg kind kind of callback
* @arg func callback function
* @arg arg argument to be passed to callback function
*/
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
nl_recvmsg_err_cb_t func, void *arg)
{
if (kind < 0 || kind > NL_CB_KIND_MAX)
return -NLE_RANGE;
if (kind == NL_CB_CUSTOM) {
cb->cb_err = func;
cb->cb_err_arg = arg;
}
return 0;
}
/** @} */
/** @} */

View File

@ -0,0 +1,20 @@
/*
* netlink-generic.h Local Generic Netlink Interface
*
* 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>
*/
#ifndef NETLINK_GENL_PRIV_H_
#define NETLINK_GENL_PRIV_H_
#include <netlink-local.h>
#include <netlink/netlink.h>
#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen))
#endif

View File

@ -0,0 +1,160 @@
/*
* netlink-local.h Local Netlink Interface
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_LOCAL_H_
#define NETLINK_LOCAL_H_
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <inttypes.h>
#include <assert.h>
#include <limits.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#include <linux/types.h>
/* local header copies */
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/pkt_sched.h>
#include <linux/pkt_cls.h>
#include <linux/gen_stats.h>
#include <netlink/netlink.h>
#include <netlink/handlers.h>
#include <netlink/cache.h>
#include <netlink/object-api.h>
#include <netlink/cache-api.h>
#include <netlink-types.h>
struct trans_tbl {
int i;
const char *a;
};
#define __ADD(id, name) { .i = id, .a = #name },
struct trans_list {
int i;
char *a;
struct nl_list_head list;
};
#define NL_DEBUG 1
#define NL_DBG(LVL,FMT,ARG...) \
do {} while (0)
#define BUG() \
do { \
fprintf(stderr, "BUG: %s:%d\n", \
__FILE__, __LINE__); \
assert(0); \
} while (0)
extern int __nl_read_num_str_file(const char *path,
int (*cb)(long, const char *));
extern int __trans_list_add(int, const char *, struct nl_list_head *);
extern void __trans_list_clear(struct nl_list_head *);
extern char *__type2str(int, char *, size_t, struct trans_tbl *, size_t);
extern int __str2type(const char *, struct trans_tbl *, size_t);
extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
extern int __list_str2type(const char *, struct nl_list_head *);
extern char *__flags2str(int, char *, size_t, struct trans_tbl *, size_t);
extern int __str2flags(const char *, struct trans_tbl *, size_t);
extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
#ifdef disabled
static inline struct nl_cache *dp_cache(struct nl_object *obj)
{
if (obj->ce_cache == NULL)
return nl_cache_mngt_require(obj->ce_ops->oo_name);
return obj->ce_cache;
}
#endif
static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
{
return cb->cb_set[type](msg, cb->cb_args[type]);
}
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define __init __attribute__ ((constructor))
#define __exit __attribute__ ((destructor))
#undef __deprecated
#define __deprecated __attribute__ ((deprecated))
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
#define max(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
struct nlmsghdr *, struct nl_parser_param *);
static inline char *nl_cache_name(struct nl_cache *cache)
{
return cache->c_ops ? cache->c_ops->co_name : "unknown";
}
#define GENL_FAMILY(id, name) \
{ \
{ id, NL_ACT_UNSPEC, name }, \
END_OF_MSGTYPES_LIST, \
}
static inline int wait_for_ack(struct nl_sock *sk)
{
if (sk->s_flags & NL_NO_AUTO_ACK)
return 0;
else
return nl_wait_for_ack(sk);
}
#endif

View File

@ -0,0 +1,88 @@
/*
* netlink-types.h Netlink Types (Private)
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_LOCAL_TYPES_H_
#define NETLINK_LOCAL_TYPES_H_
#include <netlink/list.h>
struct nl_cache_ops;
struct nl_sock;
struct nl_object;
struct nl_cache
{
struct nl_list_head c_items;
int c_nitems;
int c_iarg1;
int c_iarg2;
struct nl_cache_ops * c_ops;
};
struct nl_cache_assoc
{
struct nl_cache * ca_cache;
change_func_t ca_change;
};
struct nl_cache_mngr
{
int cm_protocol;
int cm_flags;
int cm_nassocs;
struct nl_sock * cm_handle;
struct nl_cache_assoc * cm_assocs;
};
struct nl_parser_param;
#define LOOSE_COMPARISON 1
struct nl_data
{
size_t d_size;
void * d_data;
};
struct nl_addr
{
int a_family;
unsigned int a_maxsize;
unsigned int a_len;
int a_prefixlen;
int a_refcnt;
char a_addr[0];
};
#define IFQDISCSIZ 32
#define GENL_OP_HAS_POLICY 1
#define GENL_OP_HAS_DOIT 2
#define GENL_OP_HAS_DUMPIT 4
struct genl_family_grp {
struct genl_family *family; /* private */
struct nl_list_head list; /* private */
char name[GENL_NAMSIZ];
u_int32_t id;
};
struct genl_family_op
{
uint32_t o_id;
uint32_t o_flags;
struct nl_list_head o_list;
};
#endif

View File

@ -0,0 +1,69 @@
/*
* netlink/addr.h Abstract Address
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_ADDR_H_
#define NETLINK_ADDR_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_addr;
/* Creation */
extern struct nl_addr * nl_addr_alloc(size_t);
extern struct nl_addr * nl_addr_alloc_attr(struct nlattr *, int);
extern struct nl_addr * nl_addr_build(int, void *, size_t);
extern int nl_addr_parse(const char *, int, struct nl_addr **);
extern struct nl_addr * nl_addr_clone(struct nl_addr *);
/* Destroyage */
extern void nl_addr_destroy(struct nl_addr *);
/* Usage Management */
extern struct nl_addr * nl_addr_get(struct nl_addr *);
extern void nl_addr_put(struct nl_addr *);
extern int nl_addr_shared(struct nl_addr *);
extern int nl_addr_cmp(struct nl_addr *, struct nl_addr *);
extern int nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
extern int nl_addr_iszero(struct nl_addr *);
extern int nl_addr_valid(char *, int);
extern int nl_addr_guess_family(struct nl_addr *);
extern int nl_addr_fill_sockaddr(struct nl_addr *,
struct sockaddr *, socklen_t *);
extern int nl_addr_info(struct nl_addr *, struct addrinfo **);
extern int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
/* Access Functions */
extern void nl_addr_set_family(struct nl_addr *, int);
extern int nl_addr_get_family(struct nl_addr *);
extern int nl_addr_set_binary_addr(struct nl_addr *, void *,
size_t);
extern void * nl_addr_get_binary_addr(struct nl_addr *);
extern unsigned int nl_addr_get_len(struct nl_addr *);
extern void nl_addr_set_prefixlen(struct nl_addr *, int);
extern unsigned int nl_addr_get_prefixlen(struct nl_addr *);
/* Address Family Translations */
extern char * nl_af2str(int, char *, size_t);
extern int nl_str2af(const char *);
/* Translations to Strings */
extern char * nl_addr2str(struct nl_addr *, char *, size_t);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,726 @@
/*
* netlink/attr.h 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_ATTR_H_
#define NETLINK_ATTR_H_
#include <netlink/netlink.h>
#include <netlink/object.h>
#include <netlink/addr.h>
#include <netlink/data.h>
#include <netlink/msg.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_msg;
/**
* @name Basic Attribute Data Types
* @{
*/
/**
* @ingroup attr
* Basic attribute data types
*
* See \ref attr_datatypes for more details.
*/
enum {
NLA_UNSPEC, /**< Unspecified type, binary data chunk */
NLA_U8, /**< 8 bit integer */
NLA_U16, /**< 16 bit integer */
NLA_U32, /**< 32 bit integer */
NLA_U64, /**< 64 bit integer */
NLA_STRING, /**< NUL terminated character string */
NLA_FLAG, /**< Flag */
NLA_MSECS, /**< Micro seconds (64bit) */
NLA_NESTED, /**< Nested attributes */
__NLA_TYPE_MAX,
};
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
/** @} */
/**
* @ingroup attr
* Attribute validation policy.
*
* See \ref attr_datatypes for more details.
*/
struct nla_policy {
/** Type of attribute or NLA_UNSPEC */
uint16_t type;
/** Minimal length of payload required */
uint16_t minlen;
/** Maximal length of payload allowed */
uint16_t maxlen;
};
/* Attribute parsing */
extern int nla_ok(const struct nlattr *, int);
extern struct nlattr * nla_next(const struct nlattr *, int *);
extern int nla_parse(struct nlattr **, int, struct nlattr *,
int, struct nla_policy *);
extern int nla_validate(struct nlattr *, int, int,
struct nla_policy *);
extern struct nlattr * nla_find(struct nlattr *, int, int);
/* Unspecific attribute */
extern struct nlattr * nla_reserve(struct nl_msg *, int, int);
extern int nla_put(struct nl_msg *, int, int, const void *);
/**
* nlmsg_find_attr - find a specific attribute in a netlink message
* @arg nlh netlink message header
* @arg hdrlen length of familiy specific header
* @arg attrtype type of attribute to look for
*
* Returns the first attribute which matches the specified type.
*/
static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
{
return nla_find(nlmsg_attrdata(nlh, hdrlen),
nlmsg_attrlen(nlh, hdrlen), attrtype);
}
/**
* Return size of attribute whithout padding.
* @arg payload Payload length of attribute.
*
* @code
* <-------- nla_attr_size(payload) --------->
* +------------------+- - -+- - - - - - - - - +- - -+
* | Attribute Header | Pad | Payload | Pad |
* +------------------+- - -+- - - - - - - - - +- - -+
* @endcode
*
* @return Size of attribute in bytes without padding.
*/
static inline int nla_attr_size(int payload)
{
return NLA_HDRLEN + payload;
}
/**
* Return size of attribute including padding.
* @arg payload Payload length of attribute.
*
* @code
* <----------- nla_total_size(payload) ----------->
* +------------------+- - -+- - - - - - - - - +- - -+
* | Attribute Header | Pad | Payload | Pad |
* +------------------+- - -+- - - - - - - - - +- - -+
* @endcode
*
* @return Size of attribute in bytes.
*/
static inline int nla_total_size(int payload)
{
return NLA_ALIGN(nla_attr_size(payload));
}
/**
* Return length of padding at the tail of the attribute.
* @arg payload Payload length of attribute.
*
* @code
* +------------------+- - -+- - - - - - - - - +- - -+
* | Attribute Header | Pad | Payload | Pad |
* +------------------+- - -+- - - - - - - - - +- - -+
* <--->
* @endcode
*
* @return Length of padding in bytes.
*/
static inline int nla_padlen(int payload)
{
return nla_total_size(payload) - nla_attr_size(payload);
}
/**
* Return type of the attribute.
* @arg nla Attribute.
*
* @return Type of attribute.
*/
static inline int nla_type(const struct nlattr *nla)
{
return nla->nla_type & NLA_TYPE_MASK;
}
/**
* Return pointer to the payload section.
* @arg nla Attribute.
*
* @return Pointer to start of payload section.
*/
static inline void *nla_data(const struct nlattr *nla)
{
return (char *) nla + NLA_HDRLEN;
}
/**
* Return length of the payload .
* @arg nla Attribute
*
* @return Length of payload in bytes.
*/
static inline int nla_len(const struct nlattr *nla)
{
return nla->nla_len - NLA_HDRLEN;
}
/**
* Copy attribute payload to another memory area.
* @arg dest Pointer to destination memory area.
* @arg src Attribute
* @arg count Number of bytes to copy at most.
*
* Note: The number of bytes copied is limited by the length of
* the attribute payload.
*
* @return The number of bytes copied to dest.
*/
static inline 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;
}
/**
* Add abstract data as unspecific attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg data Abstract data object.
*
* Equivalent to nla_put() except that the length of the payload is
* derived from the abstract data object.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data)
{
return nla_put(msg, attrtype, nl_data_get_size(data),
nl_data_get(data));
}
/**
* Add abstract address as unspecific attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg addr Abstract address object.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr)
{
return nla_put(msg, attrtype, nl_addr_get_len(addr),
nl_addr_get_binary_addr(addr));
}
/** @} */
/**
* @name Integer Attributes
*/
/**
* Add 8 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value to store as payload.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
{
return nla_put(msg, attrtype, sizeof(uint8_t), &value);
}
/**
* Return value of 8 bit integer attribute.
* @arg nla 8 bit integer attribute
*
* @return Payload as 8 bit integer.
*/
static inline uint8_t nla_get_u8(struct nlattr *nla)
{
return *(uint8_t *) nla_data(nla);
}
/**
* Add 16 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value to store as payload.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
{
return nla_put(msg, attrtype, sizeof(uint16_t), &value);
}
/**
* Return payload of 16 bit integer attribute.
* @arg nla 16 bit integer attribute
*
* @return Payload as 16 bit integer.
*/
static inline uint16_t nla_get_u16(struct nlattr *nla)
{
return *(uint16_t *) nla_data(nla);
}
/**
* Add 32 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value to store as payload.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
{
return nla_put(msg, attrtype, sizeof(uint32_t), &value);
}
/**
* Return payload of 32 bit integer attribute.
* @arg nla 32 bit integer attribute.
*
* @return Payload as 32 bit integer.
*/
static inline uint32_t nla_get_u32(struct nlattr *nla)
{
return *(uint32_t *) nla_data(nla);
}
/**
* Add 64 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value to store as payload.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
{
return nla_put(msg, attrtype, sizeof(uint64_t), &value);
}
/**
* Return payload of u64 attribute
* @arg nla u64 netlink attribute
*
* @return Payload as 64 bit integer.
*/
static inline uint64_t nla_get_u64(struct nlattr *nla)
{
uint64_t tmp;
nla_memcpy(&tmp, nla, sizeof(tmp));
return tmp;
}
/**
* Add string attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg str NUL terminated string.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
{
return nla_put(msg, attrtype, strlen(str) + 1, str);
}
/**
* Return payload of string attribute.
* @arg nla String attribute.
*
* @return Pointer to attribute payload.
*/
static inline char *nla_get_string(struct nlattr *nla)
{
return (char *) nla_data(nla);
}
static inline char *nla_strdup(struct nlattr *nla)
{
return strdup(nla_get_string(nla));
}
/** @} */
/**
* @name Flag Attribute
*/
/**
* Add flag netlink attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_flag(struct nl_msg *msg, int attrtype)
{
return nla_put(msg, attrtype, 0, NULL);
}
/**
* Return true if flag attribute is set.
* @arg nla Flag netlink attribute.
*
* @return True if flag is set, otherwise false.
*/
static inline int nla_get_flag(struct nlattr *nla)
{
return !!nla;
}
/** @} */
/**
* @name Microseconds Attribute
*/
/**
* Add a msecs netlink attribute to a netlink message
* @arg n netlink message
* @arg attrtype attribute type
* @arg msecs number of msecs
*/
static inline int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
{
return nla_put_u64(n, attrtype, msecs);
}
/**
* Return payload of msecs attribute
* @arg nla msecs netlink attribute
*
* @return the number of milliseconds.
*/
static inline unsigned long nla_get_msecs(struct nlattr *nla)
{
return nla_get_u64(nla);
}
/**
* Add nested attributes to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg nested Message containing attributes to be nested.
*
* Takes the attributes found in the \a nested message and appends them
* to the message \a msg nested in a container of the type \a attrtype.
* The \a nested message may not have a family specific header.
*
* @see nla_put
* @return 0 on success or a negative error code.
*/
static inline int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
{
return nla_put(msg, attrtype, nlmsg_len(nested->nm_nlh),
nlmsg_data(nested->nm_nlh));
}
/**
* Start a new level of nested attributes.
* @arg msg Netlink message.
* @arg attrtype Attribute type of container.
*
* @return Pointer to container attribute.
*/
static inline struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
{
struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
if (nla_put(msg, attrtype, 0, NULL) < 0)
return NULL;
return start;
}
/**
* Finalize nesting of attributes.
* @arg msg Netlink message.
* @arg start Container attribute as returned from nla_nest_start().
*
* Corrects the container attribute header to include the appeneded attributes.
*
* @return 0
*/
static inline int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
{
start->nla_len = (unsigned char *) nlmsg_tail(msg->nm_nlh) -
(unsigned char *) start;
return 0;
}
/**
* Create attribute index based on nested attribute
* @arg tb Index array to be filled (maxtype+1 elements).
* @arg maxtype Maximum attribute type expected and accepted.
* @arg nla Nested Attribute.
* @arg policy Attribute validation policy.
*
* Feeds the stream of attributes nested into the specified attribute
* to nla_parse().
*
* @see nla_parse
* @return 0 on success or a negative error code.
*/
static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
struct nla_policy *policy)
{
return nla_parse(tb, maxtype, (struct nlattr *)nla_data(nla), nla_len(nla), policy);
}
/**
* Compare attribute payload with memory area.
* @arg nla Attribute.
* @arg data Memory area to compare to.
* @arg size Number of bytes to compare.
*
* @see memcmp(3)
* @return An integer less than, equal to, or greater than zero.
*/
static inline 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 string attribute payload with string
* @arg nla Attribute of type NLA_STRING.
* @arg str NUL terminated string.
*
* @see strcmp(3)
* @return An integer less than, equal to, or greater than zero.
*/
static inline 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;
}
/**
* Copy string attribute payload to a buffer.
* @arg dst Pointer to destination buffer.
* @arg nla Attribute of type NLA_STRING.
* @arg dstsize Size of destination buffer in bytes.
*
* Copies at most dstsize - 1 bytes to 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 string attribute without the terminating NUL.
*/
static inline size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
{
size_t srclen = (size_t)nla_len(nla);
char *src = (char*)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;
}
/**
* @name Attribute Construction (Exception Based)
* @{
*/
/**
* @ingroup attr
* Add unspecific attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg attrlen Length of attribute payload.
* @arg data Head of attribute payload.
*/
#define NLA_PUT(msg, attrtype, attrlen, data) \
do { \
if (nla_put(msg, attrtype, attrlen, data) < 0) \
goto nla_put_failure; \
} while(0)
/**
* @ingroup attr
* Add atomic type attribute to netlink message.
* @arg msg Netlink message.
* @arg type Atomic type.
* @arg attrtype Attribute type.
* @arg value Head of attribute payload.
*/
#define NLA_PUT_TYPE(msg, type, attrtype, value) \
do { \
type __tmp = value; \
NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
} while(0)
/**
* Add 8 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value.
*/
#define NLA_PUT_U8(msg, attrtype, value) \
NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
/**
* Add 16 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value.
*/
#define NLA_PUT_U16(msg, attrtype, value) \
NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
/**
* Add 32 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value.
*/
#define NLA_PUT_U32(msg, attrtype, value) \
NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
/**
* Add 64 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value Numeric value.
*/
#define NLA_PUT_U64(msg, attrtype, value) \
NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
/**
* Add string attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg value NUL terminated character string.
*/
#define NLA_PUT_STRING(msg, attrtype, value) \
NLA_PUT(msg, attrtype, strlen(value) + 1, value)
/**
* Add flag attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
*/
#define NLA_PUT_FLAG(msg, attrtype) \
NLA_PUT(msg, attrtype, 0, NULL)
/**
* Add msecs attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg msecs Numeric value in micro seconds.
*/
#define NLA_PUT_MSECS(msg, attrtype, msecs) \
NLA_PUT_U64(msg, attrtype, msecs)
/**
* Add address attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
* @arg addr Abstract address object.
*/
#define NLA_PUT_ADDR(msg, attrtype, addr) \
NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \
nl_addr_get_binary_addr(addr))
/** @} */
/**
* @name Iterators
* @{
*/
/**
* @ingroup attr
* Iterate over a stream of attributes
* @arg pos loop counter, set to current attribute
* @arg head head of attribute stream
* @arg len length of attribute stream
* @arg rem initialized to len, holds bytes currently remaining in stream
*/
#define nla_for_each_attr(pos, head, len, rem) \
for (pos = head, rem = len; \
nla_ok(pos, rem); \
pos = nla_next(pos, &(rem)))
/**
* @ingroup attr
* Iterate over a stream of nested attributes
* @arg pos loop counter, set to current attribute
* @arg nla attribute containing the nested attributes
* @arg rem initialized to len, holds bytes currently remaining in stream
*/
#define nla_for_each_nested(pos, nla, rem) \
for (pos = (struct nlattr *)nla_data(nla), rem = nla_len(nla); \
nla_ok(pos, rem); \
pos = nla_next(pos, &(rem)))
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,199 @@
/*
* netlink/cache-api.h Caching API
*
* 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>
*/
#ifndef NETLINK_CACHE_API_H_
#define NETLINK_CACHE_API_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup cache
* @defgroup cache_api Cache Implementation
* @brief
*
* @par 1) Cache Definition
* @code
* struct nl_cache_ops my_cache_ops = {
* .co_name = "route/link",
* .co_protocol = NETLINK_ROUTE,
* .co_hdrsize = sizeof(struct ifinfomsg),
* .co_obj_ops = &my_obj_ops,
* };
* @endcode
*
* @par 2)
* @code
* // The simplest way to fill a cache is by providing a request-update
* // function which must trigger a complete dump on the kernel-side of
* // whatever the cache covers.
* static int my_request_update(struct nl_cache *cache,
* struct nl_sock *socket)
* {
* // In this example, we request a full dump of the interface table
* return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
* }
*
* // The resulting netlink messages sent back will be fed into a message
* // parser one at a time. The message parser has to extract all relevant
* // information from the message and create an object reflecting the
* // contents of the message and pass it on to the parser callback function
* // provide which will add the object to the cache.
* static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
* struct nlmsghdr *nlh, struct nl_parser_param *pp)
* {
* struct my_obj *obj;
*
* obj = my_obj_alloc();
* obj->ce_msgtype = nlh->nlmsg_type;
*
* // Parse the netlink message and continue creating the object.
*
* err = pp->pp_cb((struct nl_object *) obj, pp);
* if (err < 0)
* goto errout;
* }
*
* struct nl_cache_ops my_cache_ops = {
* ...
* .co_request_update = my_request_update,
* .co_msg_parser = my_msg_parser,
* };
* @endcode
*
* @par 3) Notification based Updates
* @code
* // Caches can be kept up-to-date based on notifications if the kernel
* // sends out notifications whenever an object is added/removed/changed.
* //
* // It is trivial to support this, first a list of groups needs to be
* // defined which are required to join in order to receive all necessary
* // notifications. The groups are separated by address family to support
* // the common situation where a separate group is used for each address
* // family. If there is only one group, simply specify AF_UNSPEC.
* static struct nl_af_group addr_groups[] = {
* { AF_INET, RTNLGRP_IPV4_IFADDR },
* { AF_INET6, RTNLGRP_IPV6_IFADDR },
* { END_OF_GROUP_LIST },
* };
*
* // In order for the caching system to know the meaning of each message
* // type it requires a table which maps each supported message type to
* // a cache action, e.g. RTM_NEWADDR means address has been added or
* // updated, RTM_DELADDR means address has been removed.
* static struct nl_cache_ops rtnl_addr_ops = {
* ...
* .co_msgtypes = {
* { RTM_NEWADDR, NL_ACT_NEW, "new" },
* { RTM_DELADDR, NL_ACT_DEL, "del" },
* { RTM_GETADDR, NL_ACT_GET, "get" },
* END_OF_MSGTYPES_LIST,
* },
* .co_groups = addr_groups,
* };
*
* // It is now possible to keep the cache up-to-date using the cache manager.
* @endcode
* @{
*/
enum {
NL_ACT_UNSPEC,
NL_ACT_NEW,
NL_ACT_DEL,
NL_ACT_GET,
NL_ACT_SET,
NL_ACT_CHANGE,
__NL_ACT_MAX,
};
#define NL_ACT_MAX (__NL_ACT_MAX - 1)
#define END_OF_MSGTYPES_LIST { -1, -1, NULL }
/**
* Message type to cache action association
*/
struct nl_msgtype
{
/** Netlink message type */
int mt_id;
/** Cache action to take */
int mt_act;
/** Name of operation for human-readable printing */
char * mt_name;
};
/**
* Address family to netlink group association
*/
struct nl_af_group
{
/** Address family */
int ag_family;
/** Netlink group identifier */
int ag_group;
};
#define END_OF_GROUP_LIST AF_UNSPEC, 0
struct nl_parser_param
{
int (*pp_cb)(struct nl_object *, struct nl_parser_param *);
void * pp_arg;
};
/**
* Cache Operations
*/
struct nl_cache_ops
{
char * co_name;
int co_hdrsize;
int co_protocol;
struct nl_af_group * co_groups;
/**
* Called whenever an update of the cache is required. Must send
* a request message to the kernel requesting a complete dump.
*/
int (*co_request_update)(struct nl_cache *, struct nl_sock *);
/**
* Called whenever a message was received that needs to be parsed.
* Must parse the message and call the paser callback function
* (nl_parser_param) provided via the argument.
*/
int (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *,
struct nlmsghdr *, struct nl_parser_param *);
struct nl_object_ops * co_obj_ops;
struct nl_cache_ops *co_next;
struct nl_cache *co_major_cache;
struct genl_ops * co_genl;
struct nl_msgtype co_msgtypes[];
};
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,128 @@
/*
* netlink/cache.h Caching Module
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CACHE_H_
#define NETLINK_CACHE_H_
#include <netlink/netlink.h>
#include <netlink/msg.h>
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/cache-api.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_cache;
typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int);
/* Access Functions */
extern int nl_cache_nitems(struct nl_cache *);
extern int nl_cache_nitems_filter(struct nl_cache *,
struct nl_object *);
extern struct nl_cache_ops * nl_cache_get_ops(struct nl_cache *);
extern struct nl_object * nl_cache_get_first(struct nl_cache *);
extern struct nl_object * nl_cache_get_last(struct nl_cache *);
extern struct nl_object * nl_cache_get_next(struct nl_object *);
extern struct nl_object * nl_cache_get_prev(struct nl_object *);
extern struct nl_cache * nl_cache_alloc(struct nl_cache_ops *);
extern int nl_cache_alloc_and_fill(struct nl_cache_ops *,
struct nl_sock *,
struct nl_cache **);
extern int nl_cache_alloc_name(const char *,
struct nl_cache **);
extern struct nl_cache * nl_cache_subset(struct nl_cache *,
struct nl_object *);
extern void nl_cache_clear(struct nl_cache *);
extern void nl_cache_free(struct nl_cache *);
/* Cache modification */
extern int nl_cache_add(struct nl_cache *,
struct nl_object *);
extern int nl_cache_parse_and_add(struct nl_cache *,
struct nl_msg *);
extern void nl_cache_remove(struct nl_object *);
extern int nl_cache_refill(struct nl_sock *,
struct nl_cache *);
extern int nl_cache_pickup(struct nl_sock *,
struct nl_cache *);
extern int nl_cache_resync(struct nl_sock *,
struct nl_cache *,
change_func_t);
extern int nl_cache_include(struct nl_cache *,
struct nl_object *,
change_func_t);
/* General */
extern int nl_cache_is_empty(struct nl_cache *);
extern void nl_cache_mark_all(struct nl_cache *);
/* Dumping */
extern void nl_cache_dump(struct nl_cache *,
struct nl_dump_params *);
extern void nl_cache_dump_filter(struct nl_cache *,
struct nl_dump_params *,
struct nl_object *);
/* Iterators */
#ifdef disabled
extern void nl_cache_foreach(struct nl_cache *,
void (*cb)(struct nl_object *,
void *),
void *arg);
extern void nl_cache_foreach_filter(struct nl_cache *,
struct nl_object *,
void (*cb)(struct
nl_object *,
void *),
void *arg);
#endif
/* --- cache management --- */
/* Cache type management */
extern struct nl_cache_ops * nl_cache_ops_lookup(const char *);
extern struct nl_cache_ops * nl_cache_ops_associate(int, int);
extern struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *, int);
extern void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
extern int nl_cache_mngt_register(struct nl_cache_ops *);
extern int nl_cache_mngt_unregister(struct nl_cache_ops *);
/* Global cache provisioning/requiring */
extern void nl_cache_mngt_provide(struct nl_cache *);
extern void nl_cache_mngt_unprovide(struct nl_cache *);
extern struct nl_cache * nl_cache_mngt_require(const char *);
struct nl_cache_mngr;
#define NL_AUTO_PROVIDE 1
extern int nl_cache_mngr_alloc(struct nl_sock *,
int, int,
struct nl_cache_mngr **);
extern int nl_cache_mngr_add(struct nl_cache_mngr *,
const char *,
change_func_t,
struct nl_cache **);
extern int nl_cache_mngr_get_fd(struct nl_cache_mngr *);
extern int nl_cache_mngr_poll(struct nl_cache_mngr *,
int);
extern int nl_cache_mngr_data_ready(struct nl_cache_mngr *);
extern void nl_cache_mngr_free(struct nl_cache_mngr *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,41 @@
/*
* netlink/data.h Abstract Data
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_DATA_H_
#define NETLINK_DATA_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_data;
/* General */
extern struct nl_data * nl_data_alloc(void *, size_t);
extern struct nl_data * nl_data_alloc_attr(struct nlattr *);
extern struct nl_data * nl_data_clone(struct nl_data *);
extern int nl_data_append(struct nl_data *, void *, size_t);
extern void nl_data_free(struct nl_data *);
/* Access Functions */
extern void * nl_data_get(struct nl_data *);
extern size_t nl_data_get_size(struct nl_data *);
/* Misc */
extern int nl_data_cmp(struct nl_data *, struct nl_data *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,64 @@
/*
* netlink/errno.h Error Numbers
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_ERRNO_H_
#define NETLINK_ERRNO_H_
#ifdef __cplusplus
extern "C" {
#endif
#define NLE_SUCCESS 0
#define NLE_FAILURE 1
#define NLE_INTR 2
#define NLE_BAD_SOCK 3
#define NLE_AGAIN 4
#define NLE_NOMEM 5
#define NLE_EXIST 6
#define NLE_INVAL 7
#define NLE_RANGE 8
#define NLE_MSGSIZE 9
#define NLE_OPNOTSUPP 10
#define NLE_AF_NOSUPPORT 11
#define NLE_OBJ_NOTFOUND 12
#define NLE_NOATTR 13
#define NLE_MISSING_ATTR 14
#define NLE_AF_MISMATCH 15
#define NLE_SEQ_MISMATCH 16
#define NLE_MSG_OVERFLOW 17
#define NLE_MSG_TRUNC 18
#define NLE_NOADDR 19
#define NLE_SRCRT_NOSUPPORT 20
#define NLE_MSG_TOOSHORT 21
#define NLE_MSGTYPE_NOSUPPORT 22
#define NLE_OBJ_MISMATCH 23
#define NLE_NOCACHE 24
#define NLE_BUSY 25
#define NLE_PROTO_MISMATCH 26
#define NLE_NOACCESS 27
#define NLE_PERM 28
#define NLE_PKTLOC_FILE 29
#define NLE_PARSE_ERR 30
#define NLE_NODEV 31
#define NLE_IMMUTABLE 32
#define NLE_DUMP_INTR 33
#define NLE_MAX NLE_DUMP_INTR
extern const char * nl_geterror(int);
extern void nl_perror(int, const char *);
extern int nl_syserr2nlerr(int);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,40 @@
/*
* netlink/genl/ctrl.h Generic Netlink Controller
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_GENL_CTRL_H_
#define NETLINK_GENL_CTRL_H_
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/addr.h>
#ifdef __cplusplus
extern "C" {
#endif
struct genl_family;
extern int genl_ctrl_alloc_cache(struct nl_sock *,
struct nl_cache **);
extern struct genl_family * genl_ctrl_search(struct nl_cache *, int);
extern struct genl_family * genl_ctrl_search_by_name(struct nl_cache *,
const char *);
extern int genl_ctrl_resolve(struct nl_sock *,
const char *);
extern int genl_ctrl_resolve_grp(struct nl_sock *sk,
const char *family,
const char *grp);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,134 @@
/*
* netlink/genl/family.h Generic Netlink Family
*
* 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>
*/
#ifndef NETLINK_GENL_FAMILY_H_
#define NETLINK_GENL_FAMILY_H_
#include <netlink/netlink.h>
#include <netlink/cache.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @cond SKIP */
#define FAMILY_ATTR_ID 0x01
#define FAMILY_ATTR_NAME 0x02
#define FAMILY_ATTR_VERSION 0x04
#define FAMILY_ATTR_HDRSIZE 0x08
#define FAMILY_ATTR_MAXATTR 0x10
#define FAMILY_ATTR_OPS 0x20
struct genl_family
{
NLHDR_COMMON
uint16_t gf_id;
char gf_name[GENL_NAMSIZ];
uint32_t gf_version;
uint32_t gf_hdrsize;
uint32_t gf_maxattr;
struct nl_list_head gf_ops;
struct nl_list_head gf_mc_grps;
};
extern struct genl_family * genl_family_alloc(void);
extern void genl_family_put(struct genl_family *);
extern int genl_family_add_op(struct genl_family *,
int, int);
extern int genl_family_add_grp(struct genl_family *,
uint32_t , const char *);
/**
* @name Attributes
* @{
*/
static inline unsigned int genl_family_get_id(struct genl_family *family)
{
if (family->ce_mask & FAMILY_ATTR_ID)
return family->gf_id;
else
return 0;
}
static inline void genl_family_set_id(struct genl_family *family, unsigned int id)
{
family->gf_id = id;
family->ce_mask |= FAMILY_ATTR_ID;
}
static inline char *genl_family_get_name(struct genl_family *family)
{
if (family->ce_mask & FAMILY_ATTR_NAME)
return family->gf_name;
else
return NULL;
}
static inline 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;
}
static inline uint8_t genl_family_get_version(struct genl_family *family)
{
if (family->ce_mask & FAMILY_ATTR_VERSION)
return family->gf_version;
else
return 0;
}
static inline void genl_family_set_version(struct genl_family *family, uint8_t version)
{
family->gf_version = version;
family->ce_mask |= FAMILY_ATTR_VERSION;
}
static inline uint32_t genl_family_get_hdrsize(struct genl_family *family)
{
if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
return family->gf_hdrsize;
else
return 0;
}
static inline void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
{
family->gf_hdrsize = hdrsize;
family->ce_mask |= FAMILY_ATTR_HDRSIZE;
}
static inline uint32_t genl_family_get_maxattr(struct genl_family *family)
{
if (family->ce_mask & FAMILY_ATTR_MAXATTR)
return family->gf_maxattr;
else
return family->gf_maxattr;
}
static inline void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
{
family->gf_maxattr = maxattr;
family->ce_mask |= FAMILY_ATTR_MAXATTR;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,47 @@
/*
* netlink/genl/genl.h Generic Netlink
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_GENL_H_
#define NETLINK_GENL_H_
#include <netlink/netlink.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int genl_connect(struct nl_sock *);
extern int genl_send_simple(struct nl_sock *, int, int,
int, int);
extern void * genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
int, int, int, uint8_t, uint8_t);
extern int genlmsg_valid_hdr(struct nlmsghdr *, int);
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 void * genlmsg_data(const struct genlmsghdr *);
extern int genlmsg_len(const struct genlmsghdr *);
extern struct nlattr * genlmsg_attrdata(const struct genlmsghdr *, int);
extern int genlmsg_attrlen(const struct genlmsghdr *, int);
extern char * genl_op2name(int, int, char *, size_t);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,87 @@
/*
* netlink/genl/mngt.h Generic Netlink Management
*
* 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>
*/
#ifndef NETLINK_GENL_MNGT_H_
#define NETLINK_GENL_MNGT_H_
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/list.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_cache_ops;
struct genl_info
{
struct sockaddr_nl * who;
struct nlmsghdr * nlh;
struct genlmsghdr * genlhdr;
void * userhdr;
struct nlattr ** attrs;
};
/**
* @ingroup genl_mngt
* Generic Netlink Command
*/
struct genl_cmd
{
/** Unique command identifier */
int c_id;
/** Name/description of command */
char * c_name;
/**
* Maximum attribute identifier, must be provided if
* a message parser is available.
*/
int c_maxattr;
int (*c_msg_parser)(struct nl_cache_ops *,
struct genl_cmd *,
struct genl_info *, void *);
/**
* Attribute validation policy (optional)
*/
struct nla_policy * c_attr_policy;
};
/**
* @ingroup genl_mngt
* Generic Netlink Operations
*/
struct genl_ops
{
int o_family;
int o_id;
char * o_name;
struct nl_cache_ops * o_cache_ops;
struct genl_cmd * o_cmds;
int o_ncmds;
/* linked list of all genl cache operations */
struct nl_list_head o_list;
};
extern int genl_register(struct nl_cache_ops *);
extern void genl_unregister(struct nl_cache_ops *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,231 @@
/*
* netlink/handlers.c default netlink message handlers
*
* 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>
*/
#ifndef NETLINK_HANDLERS_H_
#define NETLINK_HANDLERS_H_
#include <stdio.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netlink/netlink-compat.h>
#include <netlink/netlink-kernel.h>
#include <netlink/types.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nl_sock;
struct nl_msg;
struct nl_cb;
/**
* @name Callback Typedefs
* @{
*/
/**
* nl_recvmsgs() callback for message processing customization
* @ingroup cb
* @arg msg netlink message being processed
* @arg arg argument passwd on through caller
*/
typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
/**
* nl_recvmsgs() callback for error message processing customization
* @ingroup cb
* @arg nla netlink address of the peer
* @arg nlerr netlink error message being processed
* @arg arg argument passed on through caller
*/
typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla,
struct nlmsgerr *nlerr, void *arg);
/** @} */
/**
* Callback actions
* @ingroup cb
*/
enum nl_cb_action {
/** Proceed with wathever would come next */
NL_OK,
/** Skip this message */
NL_SKIP,
/** Stop parsing altogether and discard remaining messages */
NL_STOP,
};
/**
* Callback kinds
* @ingroup cb
*/
enum nl_cb_kind {
/** Default handlers (quiet) */
NL_CB_DEFAULT,
/** Verbose default handlers (error messages printed) */
NL_CB_VERBOSE,
/** Debug handlers for debugging */
NL_CB_DEBUG,
/** Customized handler specified by the user */
NL_CB_CUSTOM,
__NL_CB_KIND_MAX,
};
#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
/**
* Callback types
* @ingroup cb
*/
enum nl_cb_type {
/** Message is valid */
NL_CB_VALID,
/** Last message in a series of multi part messages received */
NL_CB_FINISH,
/** Report received that data was lost */
NL_CB_OVERRUN,
/** Message wants to be skipped */
NL_CB_SKIPPED,
/** Message is an acknowledge */
NL_CB_ACK,
/** Called for every message received */
NL_CB_MSG_IN,
/** Called for every message sent out except for nl_sendto() */
NL_CB_MSG_OUT,
/** Message is malformed and invalid */
NL_CB_INVALID,
/** Called instead of internal sequence number checking */
NL_CB_SEQ_CHECK,
/** Sending of an acknowledge message has been requested */
NL_CB_SEND_ACK,
__NL_CB_TYPE_MAX,
};
#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
struct nl_cb
{
nl_recvmsg_msg_cb_t cb_set[NL_CB_TYPE_MAX+1];
void * cb_args[NL_CB_TYPE_MAX+1];
nl_recvmsg_err_cb_t cb_err;
void * cb_err_arg;
/** May be used to replace nl_recvmsgs with your own implementation
* in all internal calls to nl_recvmsgs. */
int (*cb_recvmsgs_ow)(struct nl_sock *,
struct nl_cb *);
/** Overwrite internal calls to nl_recv, must return the number of
* octets read and allocate a buffer for the received data. */
int (*cb_recv_ow)(struct nl_sock *,
struct sockaddr_nl *,
unsigned char **,
struct ucred **);
/** Overwrites internal calls to nl_send, must send the netlink
* message. */
int (*cb_send_ow)(struct nl_sock *,
struct nl_msg *);
int cb_refcnt;
};
extern struct nl_cb * nl_cb_alloc(enum nl_cb_kind);
extern struct nl_cb * nl_cb_clone(struct nl_cb *);
extern void nl_cb_put(struct nl_cb *);
extern int nl_cb_set(struct nl_cb *, enum nl_cb_type, enum nl_cb_kind,
nl_recvmsg_msg_cb_t, void *);
extern int nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t,
void *);
static inline struct nl_cb *nl_cb_get(struct nl_cb *cb)
{
cb->cb_refcnt++;
return cb;
}
/**
* Set up a all callbacks
* @arg cb callback set
* @arg kind kind of callback
* @arg func callback function
* @arg arg argument to be passwd to callback function
*
* @return 0 on success or a negative error code
*/
static inline int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
nl_recvmsg_msg_cb_t func, void *arg)
{
int i, err;
for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
err = nl_cb_set(cb,(enum nl_cb_type)i, kind, func, arg);
if (err < 0)
return err;
}
return 0;
}
/**
* @name Overwriting
* @{
*/
/**
* Overwrite internal calls to nl_recvmsgs()
* @arg cb callback set
* @arg func replacement callback for nl_recvmsgs()
*/
static inline void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
int (*func)(struct nl_sock *, struct nl_cb *))
{
cb->cb_recvmsgs_ow = func;
}
/**
* Overwrite internal calls to nl_recv()
* @arg cb callback set
* @arg func replacement callback for nl_recv()
*/
static inline void nl_cb_overwrite_recv(struct nl_cb *cb,
int (*func)(struct nl_sock *, struct sockaddr_nl *,
unsigned char **, struct ucred **))
{
cb->cb_recv_ow = func;
}
/**
* Overwrite internal calls to nl_send()
* @arg cb callback set
* @arg func replacement callback for nl_send()
*/
static inline void nl_cb_overwrite_send(struct nl_cb *cb,
int (*func)(struct nl_sock *, struct nl_msg *))
{
cb->cb_send_ow = func;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,88 @@
/*
* netlink/list.h Netlink List Utilities
*
* 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>
*/
#ifndef NETLINK_LIST_H_
#define NETLINK_LIST_H_
struct nl_list_head
{
struct nl_list_head * next;
struct nl_list_head * prev;
};
static inline void __nl_list_add(struct nl_list_head *obj,
struct nl_list_head *prev,
struct nl_list_head *next)
{
prev->next = obj;
obj->prev = prev;
next->prev = obj;
obj->next = next;
}
static inline void nl_list_add_tail(struct nl_list_head *obj,
struct nl_list_head *head)
{
__nl_list_add(obj, head->prev, head);
}
static inline void nl_list_add_head(struct nl_list_head *obj,
struct nl_list_head *head)
{
__nl_list_add(obj, head, head->next);
}
static inline void nl_list_del(struct nl_list_head *obj)
{
obj->next->prev = obj->prev;
obj->prev->next = obj->next;
}
static inline int nl_list_empty(struct nl_list_head *head)
{
return head->next == head;
}
#define nl_container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
#define nl_list_entry(ptr, type, member) \
nl_container_of(ptr, type, member)
#define nl_list_at_tail(pos, head, member) \
((pos)->member.next == (head))
#define nl_list_at_head(pos, head, member) \
((pos)->member.prev == (head))
#define NL_LIST_HEAD(name) \
struct nl_list_head name = { &(name), &(name) }
#define nl_list_first_entry(head, type, member) \
nl_list_entry((head)->next, type, member)
#define nl_list_for_each_entry(pos, head, member) \
for (pos = nl_list_entry((head)->next, typeof(*pos), member); \
&(pos)->member != (head); \
(pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member))
#define nl_list_for_each_entry_safe(pos, n, head, member) \
for (pos = nl_list_entry((head)->next, typeof(*pos), member), \
n = nl_list_entry(pos->member.next, typeof(*pos), member); \
&(pos)->member != (head); \
pos = n, n = nl_list_entry(n->member.next, typeof(*n), member))
#define nl_init_list_head(head) \
do { (head)->next = (head); (head)->prev = (head); } while (0)
#endif

View File

@ -0,0 +1,308 @@
/*
* netlink/msg.c Netlink Messages Interface
*
* 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>
*/
#ifndef NETLINK_MSG_H_
#define NETLINK_MSG_H_
#include <netlink/netlink.h>
#include <netlink/object.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nla_policy;
#define NL_DONTPAD 0
/**
* @ingroup msg
* @brief
* Will cause the netlink pid to be set to the pid assigned to
* the netlink handle (socket) just before sending the message off.
* @note Requires the use of nl_send_auto_complete()!
*/
#define NL_AUTO_PID 0
/**
* @ingroup msg
* @brief
* May be used to refer to a sequence number which should be
* automatically set just before sending the message off.
* @note Requires the use of nl_send_auto_complete()!
*/
#define NL_AUTO_SEQ 0
#define NL_MSG_CRED_PRESENT 1
struct nl_msg
{
int nm_protocol;
int nm_flags;
struct sockaddr_nl nm_src;
struct sockaddr_nl nm_dst;
struct ucred nm_creds;
struct nlmsghdr * nm_nlh;
size_t nm_size;
int nm_refcnt;
};
struct nl_msg;
struct nl_tree;
struct ucred;
/* message parsing */
extern int nlmsg_ok(const struct nlmsghdr *, int);
extern struct nlmsghdr * nlmsg_next(struct nlmsghdr *, int *);
extern int nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
int, struct nla_policy *);
extern int nlmsg_validate(struct nlmsghdr *, int, int,
struct nla_policy *);
extern struct nl_msg * nlmsg_alloc(void);
extern struct nl_msg * nlmsg_alloc_size(size_t);
extern struct nl_msg * nlmsg_alloc_simple(int, int);
extern void nlmsg_set_default_size(size_t);
extern struct nl_msg * nlmsg_inherit(struct nlmsghdr *);
extern struct nl_msg * nlmsg_convert(struct nlmsghdr *);
extern void * nlmsg_reserve(struct nl_msg *, size_t, int);
extern int nlmsg_append(struct nl_msg *, void *, size_t, int);
extern struct nlmsghdr * nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
int, int, int);
extern void nlmsg_free(struct nl_msg *);
extern int nl_msg_parse(struct nl_msg *,
void (*cb)(struct nl_object *, void *),
void *);
extern void nl_msg_dump(struct nl_msg *, FILE *);
/**
* length of netlink message not including padding
* @arg payload length of message payload
*/
static inline int nlmsg_msg_size(int payload)
{
return NLMSG_HDRLEN + payload;
}
/**
* length of netlink message including padding
* @arg payload length of message payload
*/
static inline int nlmsg_total_size(int payload)
{
return NLMSG_ALIGN(nlmsg_msg_size(payload));
}
/**
* length of padding at the message's tail
* @arg payload length of message payload
*/
static inline int nlmsg_padlen(int payload)
{
return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
}
/**
* head of message payload
* @arg nlh netlink messsage header
*/
static inline void *nlmsg_data(const struct nlmsghdr *nlh)
{
return (unsigned char *) nlh + NLMSG_HDRLEN;
}
static inline void *nlmsg_tail(const struct nlmsghdr *nlh)
{
return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
}
/**
* length of message payload
* @arg nlh netlink message header
*/
static inline int nlmsg_len(const struct nlmsghdr *nlh)
{
return nlh->nlmsg_len - NLMSG_HDRLEN;
}
/**
* head of attributes data
* @arg nlh netlink message header
* @arg hdrlen length of family specific header
*/
static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
{
unsigned char *data = (unsigned char*)nlmsg_data(nlh);
return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
}
/**
* length of attributes data
* @arg nlh netlink message header
* @arg hdrlen length of family specific header
*/
static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
{
return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
}
static inline int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
{
if (nlh->nlmsg_len < (uint)nlmsg_msg_size(hdrlen))
return 0;
return 1;
}
static inline void nlmsg_set_proto(struct nl_msg *msg, int protocol)
{
msg->nm_protocol = protocol;
}
static inline int nlmsg_get_proto(struct nl_msg *msg)
{
return msg->nm_protocol;
}
static inline size_t nlmsg_get_max_size(struct nl_msg *msg)
{
return msg->nm_size;
}
static inline void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
{
memcpy(&msg->nm_src, addr, sizeof(*addr));
}
static inline struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
{
return &msg->nm_src;
}
static inline void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
{
memcpy(&msg->nm_dst, addr, sizeof(*addr));
}
static inline struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
{
return &msg->nm_dst;
}
static inline void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
{
memcpy(&msg->nm_creds, creds, sizeof(*creds));
msg->nm_flags |= NL_MSG_CRED_PRESENT;
}
static inline struct ucred *nlmsg_get_creds(struct nl_msg *msg)
{
if (msg->nm_flags & NL_MSG_CRED_PRESENT)
return &msg->nm_creds;
return NULL;
}
/**
* Return actual netlink message
* @arg n netlink message
*
* Returns the actual netlink message casted to the type of the netlink
* message header.
*
* @return A pointer to the netlink message.
*/
static inline struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
{
return n->nm_nlh;
}
/**
* Acquire a reference on a netlink message
* @arg msg message to acquire reference from
*/
static inline void nlmsg_get(struct nl_msg *msg)
{
msg->nm_refcnt++;
}
/**
* Expand maximum payload size of a netlink message
* @arg n Netlink message.
* @arg newlen New maximum payload size.
*
* Reallocates the payload section of a netlink message and increases
* the maximum payload size of the message.
*
* @note Any pointers pointing to old payload block will be stale and
* need to be refetched. Therfore, do not expand while constructing
* nested attributes or while reserved data blocks are held.
*
* @return 0 on success or a negative error code.
*/
static inline int nlmsg_expand(struct nl_msg *n, size_t newlen)
{
void *tmp;
if (newlen <= n->nm_size)
return -NLE_INVAL;
tmp = realloc(n->nm_nlh, newlen);
if (tmp == NULL)
return -NLE_NOMEM;
n->nm_nlh = (struct nlmsghdr*)tmp;
n->nm_size = newlen;
return 0;
}
/**
* @name Iterators
* @{
*/
/**
* @ingroup msg
* Iterate over a stream of attributes in a message
* @arg pos loop counter, set to current attribute
* @arg nlh netlink message header
* @arg hdrlen length of family header
* @arg rem initialized to len, holds bytes currently remaining in stream
*/
#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
nlmsg_attrlen(nlh, hdrlen), rem)
/**
* Iterate over a stream of messages
* @arg pos loop counter, set to current message
* @arg head head of message stream
* @arg len length of message stream
* @arg rem initialized to len, holds bytes currently remaining in stream
*/
#define nlmsg_for_each_msg(pos, head, len, rem) \
for (pos = head, rem = len; \
nlmsg_ok(pos, rem); \
pos = nlmsg_next(pos, &(rem)))
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,50 @@
/*
* netlink/netlink-compat.h Netlink Compatability
*
* 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>
*/
#ifndef NETLINK_COMPAT_H_
#define NETLINK_COMPAT_H_
#if !defined _LINUX_SOCKET_H && !defined _BITS_SOCKADDR_H
typedef unsigned short sa_family_t;
#endif
#ifndef IFNAMSIZ
/** Maximum length of a interface name */
#define IFNAMSIZ 16
#endif
/* patch 2.4.x if_arp */
#ifndef ARPHRD_INFINIBAND
#define ARPHRD_INFINIBAND 32
#endif
/* patch 2.4.x eth header file */
#ifndef ETH_P_MPLS_UC
#define ETH_P_MPLS_UC 0x8847
#endif
#ifndef ETH_P_MPLS_MC
#define ETH_P_MPLS_MC 0x8848
#endif
#ifndef ETH_P_EDP2
#define ETH_P_EDP2 0x88A2
#endif
#ifndef ETH_P_HDLC
#define ETH_P_HDLC 0x0019
#endif
#ifndef AF_LLC
#define AF_LLC 26
#endif
#endif

View File

@ -0,0 +1,196 @@
#ifndef __LINUX_NETLINK_H
#define __LINUX_NETLINK_H
/**
* Netlink socket address
* @ingroup nl
*/
struct sockaddr_nl
{
/** socket family (AF_NETLINK) */
sa_family_t nl_family;
/** Padding (unused) */
unsigned short nl_pad;
/** Unique process ID */
uint32_t nl_pid;
/** Multicast group subscriptions */
uint32_t nl_groups;
};
/**
* Netlink message header
* @ingroup msg
*/
struct nlmsghdr
{
/**
* Length of message including header.
*/
uint32_t nlmsg_len;
/**
* Message type (content type)
*/
uint16_t nlmsg_type;
/**
* Message flags
*/
uint16_t nlmsg_flags;
/**
* Sequence number
*/
uint32_t nlmsg_seq;
/**
* Netlink PID of the proccess sending the message.
*/
uint32_t nlmsg_pid;
};
/**
* @name Standard message flags
* @{
*/
/**
* Must be set on all request messages (typically from user space to
* kernel space).
* @ingroup msg
*/
#define NLM_F_REQUEST 1
/**
* Indicates the message is part of a multipart message terminated
* by NLMSG_DONE.
*/
#define NLM_F_MULTI 2
/**
* Request for an acknowledgment on success.
*/
#define NLM_F_ACK 4
/**
* Echo this request
*/
#define NLM_F_ECHO 8
/** @} */
/**
* @name Additional message flags for GET requests
* @{
*/
/**
* Return the complete table instead of a single entry.
* @ingroup msg
*/
#define NLM_F_ROOT 0x100
/**
* Return all entries matching criteria passed in message content.
*/
#define NLM_F_MATCH 0x200
/**
* Return an atomic snapshot of the table being referenced. This
* may require special privileges because it has the potential to
* interrupt service in the FE for a longer time.
*/
#define NLM_F_ATOMIC 0x400
/**
* Dump all entries
*/
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
/** @} */
/**
* @name Additional messsage flags for NEW requests
* @{
*/
/**
* Replace existing matching config object with this request.
* @ingroup msg
*/
#define NLM_F_REPLACE 0x100
/**
* Don't replace the config object if it already exists.
*/
#define NLM_F_EXCL 0x200
/**
* Create config object if it doesn't already exist.
*/
#define NLM_F_CREATE 0x400
/**
* Add to the end of the object list.
*/
#define NLM_F_APPEND 0x800
/** @} */
/**
* @name Standard Message types
* @{
*/
/**
* No operation, message must be ignored
* @ingroup msg
*/
#define NLMSG_NOOP 0x1
/**
* The message signals an error and the payload contains a nlmsgerr
* structure. This can be looked at as a NACK and typically it is
* from FEC to CPC.
*/
#define NLMSG_ERROR 0x2
/**
* Message terminates a multipart message.
*/
#define NLMSG_DONE 0x3
/**
* The message signals that data got lost
*/
#define NLMSG_OVERRUN 0x4
/**
* Lower limit of reserved message types
*/
#define NLMSG_MIN_TYPE 0x10
/** @} */
/**
* Netlink error message
* @ingroup msg
*/
struct nlmsgerr
{
/** Error code (errno number) */
int error;
/** Original netlink message causing the error */
struct nlmsghdr msg;
};
struct nl_pktinfo
{
__u32 group;
};
#endif /* __LINUX_NETLINK_H */

View File

@ -0,0 +1,82 @@
/*
* netlink/netlink.h Netlink Interface
*
* 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>
*/
#ifndef NETLINK_NETLINK_H_
#define NETLINK_NETLINK_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netdb.h>
#include <netlink/netlink-compat.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>
#include <netlink/version.h>
#include <netlink/errno.h>
#include <netlink/types.h>
#include <netlink/handlers.h>
#include <netlink/socket.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int nl_debug;
extern struct nl_dump_params nl_debug_dp;
/* Connection Management */
extern int nl_connect(struct nl_sock *, int);
extern void nl_close(struct nl_sock *);
/* Send */
extern int nl_sendto(struct nl_sock *, void *, size_t);
extern int nl_sendmsg(struct nl_sock *, struct nl_msg *,
struct msghdr *);
extern int nl_send(struct nl_sock *, struct nl_msg *);
extern int nl_send_auto_complete(struct nl_sock *,
struct nl_msg *);
extern int nl_send_simple(struct nl_sock *, int, int,
void *, size_t);
/* Receive */
extern int nl_recv(struct nl_sock *,
struct sockaddr_nl *, unsigned char **,
struct ucred **);
extern int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb);
extern int nl_wait_for_ack(struct nl_sock *);
/* Netlink Family Translations */
extern char * nl_nlfamily2str(int, char *, size_t);
extern int nl_str2nlfamily(const char *);
/**
* Receive a set of message from a netlink socket using handlers in nl_sock.
* @arg sk Netlink socket.
*
* Calls nl_recvmsgs() with the handlers configured in the netlink socket.
*/
static inline int nl_recvmsgs_default(struct nl_sock *sk)
{
return nl_recvmsgs(sk, sk->s_cb);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,331 @@
/*
* netlink/object-api.c Object API
*
* 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-2007 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_OBJECT_API_H_
#define NETLINK_OBJECT_API_H_
#include <netlink/netlink.h>
#include <netlink/utils.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup object
* @defgroup object_api Object API
* @brief
*
* @par 1) Object Definition
* @code
* // Define your object starting with the common object header
* struct my_obj {
* NLHDR_COMMON
* int my_data;
* };
*
* // Fill out the object operations structure
* struct nl_object_ops my_ops = {
* .oo_name = "my_obj",
* .oo_size = sizeof(struct my_obj),
* };
*
* // At this point the object can be allocated, you may want to provide a
* // separate _alloc() function to ease allocting objects of this kind.
* struct nl_object *obj = nl_object_alloc(&my_ops);
*
* // And release it again...
* nl_object_put(obj);
* @endcode
*
* @par 2) Allocating additional data
* @code
* // You may require to allocate additional data and store it inside
* // object, f.e. assuming there is a field `ptr'.
* struct my_obj {
* NLHDR_COMMON
* void * ptr;
* };
*
* // And at some point you may assign allocated data to this field:
* my_obj->ptr = calloc(1, ...);
*
* // In order to not introduce any memory leaks you have to release
* // this data again when the last reference is given back.
* static void my_obj_free_data(struct nl_object *obj)
* {
* struct my_obj *my_obj = nl_object_priv(obj);
*
* free(my_obj->ptr);
* }
*
* // Also when the object is cloned, you must ensure for your pointer
* // stay valid even if one of the clones is freed by either making
* // a clone as well or increase the reference count.
* static int my_obj_clone(struct nl_object *src, struct nl_object *dst)
* {
* struct my_obj *my_src = nl_object_priv(src);
* struct my_obj *my_dst = nl_object_priv(dst);
*
* if (src->ptr) {
* dst->ptr = calloc(1, ...);
* memcpy(dst->ptr, src->ptr, ...);
* }
* }
*
* struct nl_object_ops my_ops = {
* ...
* .oo_free_data = my_obj_free_data,
* .oo_clone = my_obj_clone,
* };
* @endcode
*
* @par 3) Object Dumping
* @code
* static int my_obj_dump_detailed(struct nl_object *obj,
* struct nl_dump_params *params)
* {
* struct my_obj *my_obj = nl_object_priv(obj);
*
* // It is absolutely essential to use nl_dump() when printing
* // any text to make sure the dumping parameters are respected.
* nl_dump(params, "Obj Integer: %d\n", my_obj->my_int);
*
* // Before we can dump the next line, make sure to prefix
* // this line correctly.
* nl_new_line(params);
*
* // You may also split a line into multiple nl_dump() calls.
* nl_dump(params, "String: %s ", my_obj->my_string);
* nl_dump(params, "String-2: %s\n", my_obj->another_string);
* }
*
* struct nl_object_ops my_ops = {
* ...
* .oo_dump[NL_DUMP_FULL] = my_obj_dump_detailed,
* };
* @endcode
*
* @par 4) Object Attributes
* @code
* // The concept of object attributes is optional but can ease the typical
* // case of objects that have optional attributes, e.g. a route may have a
* // nexthop assigned but it is not required to.
*
* // The first step to define your object specific bitmask listing all
* // attributes
* #define MY_ATTR_FOO (1<<0)
* #define MY_ATTR_BAR (1<<1)
*
* // When assigning an optional attribute to the object, make sure
* // to mark its availability.
* my_obj->foo = 123123;
* my_obj->ce_mask |= MY_ATTR_FOO;
*
* // At any time you may use this mask to check for the availability
* // of the attribute, e.g. while dumping
* if (my_obj->ce_mask & MY_ATTR_FOO)
* nl_dump(params, "foo %d ", my_obj->foo);
*
* // One of the big advantages of this concept is that it allows for
* // standardized comparisons which make it trivial for caches to
* // identify unique objects by use of unified comparison functions.
* // In order for it to work, your object implementation must provide
* // a comparison function and define a list of attributes which
* // combined together make an object unique.
*
* static int my_obj_compare(struct nl_object *_a, struct nl_object *_b,
* uint32_t attrs, int flags)
* {
* struct my_obj *a = nl_object_priv(_a):
* struct my_obj *b = nl_object_priv(_b):
* int diff = 0;
*
* // We help ourselves in defining our own DIFF macro which will
* // call ATTR_DIFF() on both objects which will make sure to only
* // compare the attributes if required.
* #define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR)
*
* // Call our own diff macro for each attribute to build a bitmask
* // representing the attributes which mismatch.
* diff |= MY_DIFF(FOO, a->foo != b->foo)
* diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar))
*
* return diff;
* }
*
* // In order to identify identical objects with differing attributes
* // you must specify the attributes required to uniquely identify
* // your object. Make sure to not include too many attributes, this
* // list is used when caches look for an old version of an object.
* struct nl_object_ops my_ops = {
* ...
* .oo_id_attrs = MY_ATTR_FOO,
* .oo_compare = my_obj_compare,
* };
* @endcode
* @{
*/
/**
* Common Object Header
*
* This macro must be included as first member in every object
* definition to allow objects to be cached.
*/
#define NLHDR_COMMON \
int ce_refcnt; \
struct nl_object_ops * ce_ops; \
struct nl_cache * ce_cache; \
struct nl_list_head ce_list; \
int ce_msgtype; \
int ce_flags; \
uint32_t ce_mask;
/**
* Return true if attribute is available in both objects
* @arg A an object
* @arg B another object
* @arg ATTR attribute bit
*
* @return True if the attribute is available, otherwise false is returned.
*/
#define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR))
/**
* Return true if attributes mismatch
* @arg A an object
* @arg B another object
* @arg ATTR attribute bit
* @arg EXPR Comparison expression
*
* This function will check if the attribute in question is available
* in both objects, if not this will count as a mismatch.
*
* If available the function will execute the expression which must
* return true if the attributes mismatch.
*
* @return True if the attribute mismatch, or false if they match.
*/
#define ATTR_MISMATCH(A, B, ATTR, EXPR) (!AVAILABLE(A, B, ATTR) || (EXPR))
/**
* Return attribute bit if attribute does not match
* @arg LIST list of attributes to be compared
* @arg ATTR attribute bit
* @arg A an object
* @arg B another object
* @arg EXPR Comparison expression
*
* This function will check if the attribute in question is available
* in both objects, if not this will count as a mismatch.
*
* If available the function will execute the expression which must
* return true if the attributes mismatch.
*
* In case the attributes mismatch, the attribute is returned, otherwise
* 0 is returned.
*
* @code
* diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo);
* @endcode
*/
#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
({ int diff = 0; \
if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \
diff = ATTR; \
diff; })
/**
* Object Operations
*/
struct nl_object;
struct nl_object_ops
{
/**
* Unique name of object type
*
* Must be in the form family/name, e.g. "route/addr"
*/
char * oo_name;
/** Size of object including its header */
size_t oo_size;
/* List of attributes needed to uniquely identify the object */
uint32_t oo_id_attrs;
/**
* Constructor function
*
* Will be called when a new object of this type is allocated.
* Can be used to initialize members such as lists etc.
*/
void (*oo_constructor)(struct nl_object *);
/**
* Destructor function
*
* Will be called when an object is freed. Must free all
* resources which may have been allocated as part of this
* object.
*/
void (*oo_free_data)(struct nl_object *);
/**
* Cloning function
*
* Will be called when an object needs to be cloned. Please
* note that the generic object code will make an exact
* copy of the object first, therefore you only need to take
* care of members which require reference counting etc.
*
* May return a negative error code to abort cloning.
*/
int (*oo_clone)(struct nl_object *, struct nl_object *);
/**
* Dumping functions
*
* Will be called when an object is dumped. The implementations
* have to use nl_dump(), nl_dump_line(), and nl_new_line() to
* dump objects.
*
* The functions must return the number of lines printed.
*/
void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *,
struct nl_dump_params *);
/**
* Comparison function
*
* Will be called when two objects of the same type are
* compared. It takes the two objects in question, an object
* specific bitmask defining which attributes should be
* compared and flags to control the behaviour.
*
* The function must return a bitmask with the relevant bit
* set for each attribute that mismatches.
*/
int (*oo_compare)(struct nl_object *, struct nl_object *,
uint32_t, int);
char *(*oo_attrs2str)(int, char *, size_t);
};
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,164 @@
/*
* netlink/object.c Generic Cacheable Object
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_OBJECT_H_
#define NETLINK_OBJECT_H_
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/object-api.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NL_OBJ_MARK 1
struct nl_cache;
struct nl_object;
struct nl_object_ops;
struct nl_object
{
NLHDR_COMMON
};
#define OBJ_CAST(ptr) ((struct nl_object *) (ptr))
/* General */
extern struct nl_object * nl_object_alloc(struct nl_object_ops *);
extern void nl_object_free(struct nl_object *);
extern struct nl_object * nl_object_clone(struct nl_object *obj);
#ifdef disabled
extern int nl_object_alloc_name(const char *,
struct nl_object **);
extern void nl_object_dump(struct nl_object *,
struct nl_dump_params *);
extern uint32_t nl_object_diff(struct nl_object *,
struct nl_object *);
extern int nl_object_match_filter(struct nl_object *,
struct nl_object *);
extern int nl_object_identical(struct nl_object *,
struct nl_object *);
extern char * nl_object_attrs2str(struct nl_object *,
uint32_t attrs, char *buf,
size_t);
#endif
/**
* Check whether this object is used by multiple users
* @arg obj object to check
* @return true or false
*/
static inline int nl_object_shared(struct nl_object *obj)
{
return obj->ce_refcnt > 1;
}
static inline void nl_object_get(struct nl_object *obj)
{
obj->ce_refcnt++;
}
static inline void nl_object_put(struct nl_object *obj)
{
if (!obj)
return;
obj->ce_refcnt--;
if (obj->ce_refcnt <= 0)
nl_object_free(obj);
}
/**
* @name Marks
* @{
*/
/**
* Add mark to object
* @arg obj Object to mark
*/
static inline void nl_object_mark(struct nl_object *obj)
{
obj->ce_flags |= NL_OBJ_MARK;
}
/**
* Remove mark from object
* @arg obj Object to unmark
*/
static inline void nl_object_unmark(struct nl_object *obj)
{
obj->ce_flags &= ~NL_OBJ_MARK;
}
/**
* Return true if object is marked
* @arg obj Object to check
* @return true if object is marked, otherwise false
*/
static inline int nl_object_is_marked(struct nl_object *obj)
{
return (obj->ce_flags & NL_OBJ_MARK);
}
/** @} */
#ifdef disabled
/**
* Return list of attributes present in an object
* @arg obj an object
* @arg buf destination buffer
* @arg len length of destination buffer
*
* @return destination buffer.
*/
static inline char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
{
return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
}
#endif
/**
* @name Attributes
* @{
*/
static inline int nl_object_get_refcnt(struct nl_object *obj)
{
return obj->ce_refcnt;
}
static inline struct nl_cache *nl_object_get_cache(struct nl_object *obj)
{
return obj->ce_cache;
}
static inline void * nl_object_priv(struct nl_object *obj)
{
return obj;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,231 @@
/*
* netlink/socket.h Netlink Socket
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_SOCKET_H_
#define NETLINK_SOCKET_H_
#include <netlink/types.h>
#include <netlink/handlers.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NL_SOCK_BUFSIZE_SET (1<<0)
#define NL_SOCK_PASSCRED (1<<1)
#define NL_OWN_PORT (1<<2)
#define NL_MSG_PEEK (1<<3)
#define NL_NO_AUTO_ACK (1<<4)
struct nl_cb;
struct nl_sock
{
struct sockaddr_nl s_local;
struct sockaddr_nl s_peer;
int s_fd;
int s_proto;
unsigned int s_seq_next;
unsigned int s_seq_expect;
int s_flags;
struct nl_cb * s_cb;
};
extern struct nl_sock * nl_socket_alloc(void);
extern struct nl_sock * nl_socket_alloc_cb(struct nl_cb *);
extern void nl_socket_free(struct nl_sock *);
extern void nl_socket_set_local_port(struct nl_sock *, uint32_t);
extern int nl_socket_add_memberships(struct nl_sock *, int, ...);
extern int nl_socket_drop_memberships(struct nl_sock *, int, ...);
extern int nl_socket_set_buffer_size(struct nl_sock *, int, int);
extern int nl_socket_set_passcred(struct nl_sock *, int);
extern int nl_socket_recv_pktinfo(struct nl_sock *, int);
extern void nl_socket_disable_seq_check(struct nl_sock *);
extern int nl_socket_set_nonblocking(struct nl_sock *);
/**
* Use next sequence number
* @arg sk Netlink socket.
*
* Uses the next available sequence number and increases the counter
* by one for subsequent calls.
*
* @return Unique serial sequence number
*/
static inline unsigned int nl_socket_use_seq(struct nl_sock *sk)
{
return sk->s_seq_next++;
}
/**
* Disable automatic request for ACK
* @arg sk Netlink socket.
*
* The default behaviour of a socket is to request an ACK for
* each message sent to allow for the caller to synchronize to
* the completion of the netlink operation. This function
* disables this behaviour and will result in requests being
* sent which will not have the NLM_F_ACK flag set automatically.
* However, it is still possible for the caller to set the
* NLM_F_ACK flag explicitely.
*/
static inline void nl_socket_disable_auto_ack(struct nl_sock *sk)
{
sk->s_flags |= NL_NO_AUTO_ACK;
}
/**
* Enable automatic request for ACK (default)
* @arg sk Netlink socket.
* @see nl_socket_disable_auto_ack
*/
static inline void nl_socket_enable_auto_ack(struct nl_sock *sk)
{
sk->s_flags &= ~NL_NO_AUTO_ACK;
}
/**
* @name Source Idenficiation
* @{
*/
static inline uint32_t nl_socket_get_local_port(struct nl_sock *sk)
{
return sk->s_local.nl_pid;
}
/**
* Join multicast groups (deprecated)
* @arg sk Netlink socket.
* @arg groups Bitmask of groups to join.
*
* This function defines the old way of joining multicast group which
* has to be done prior to calling nl_connect(). It works on any kernel
* version but is very limited as only 32 groups can be joined.
*/
static inline void nl_join_groups(struct nl_sock *sk, int groups)
{
sk->s_local.nl_groups |= groups;
}
/**
* @name Peer Identfication
* @{
*/
static inline uint32_t nl_socket_get_peer_port(struct nl_sock *sk)
{
return sk->s_peer.nl_pid;
}
static inline void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port)
{
sk->s_peer.nl_pid = port;
}
/** @} */
/**
* @name File Descriptor
* @{
*/
static inline int nl_socket_get_fd(struct nl_sock *sk)
{
return sk->s_fd;
}
/**
* Enable use of MSG_PEEK when reading from socket
* @arg sk Netlink socket.
*/
static inline void nl_socket_enable_msg_peek(struct nl_sock *sk)
{
sk->s_flags |= NL_MSG_PEEK;
}
/**
* Disable use of MSG_PEEK when reading from socket
* @arg sk Netlink socket.
*/
static inline void nl_socket_disable_msg_peek(struct nl_sock *sk)
{
sk->s_flags &= ~NL_MSG_PEEK;
}
static inline uint32_t nl_socket_get_peer_groups(struct nl_sock *sk)
{
return sk->s_peer.nl_groups;
}
static inline void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups)
{
sk->s_peer.nl_groups = groups;
}
/**
* @name Callback Handler
* @{
*/
static inline struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
{
return nl_cb_get(sk->s_cb);
}
static inline void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
{
nl_cb_put(sk->s_cb);
sk->s_cb = nl_cb_get(cb);
}
/**
* Modify the callback handler associated to the socket
* @arg sk Netlink socket.
* @arg type which type callback to set
* @arg kind kind of callback
* @arg func callback function
* @arg arg argument to be passwd to callback function
*
* @see nl_cb_set
*/
static inline int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type,
enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
void *arg)
{
return nl_cb_set(sk->s_cb, type, kind, func, arg);
}
/** @} */
static inline int nl_socket_add_membership(struct nl_sock *sk, int group)
{
return nl_socket_add_memberships(sk, group, 0);
}
static inline int nl_socket_drop_membership(struct nl_sock *sk, int group)
{
return nl_socket_drop_memberships(sk, group, 0);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,121 @@
/*
* netlink/netlink-types.h Netlink Types
*
* 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>
*/
#ifndef __NETLINK_TYPES_H_
#define __NETLINK_TYPES_H_
#include <stdio.h>
/**
* Dumping types (dp_type)
* @ingroup utils
*/
enum nl_dump_type {
NL_DUMP_LINE, /**< Dump object briefly on one line */
NL_DUMP_DETAILS, /**< Dump all attributes but no statistics */
NL_DUMP_STATS, /**< Dump all attributes including statistics */
NL_DUMP_ENV, /**< Dump all attribtues as env variables */
__NL_DUMP_MAX,
};
#define NL_DUMP_MAX (__NL_DUMP_MAX - 1)
/**
* Dumping parameters
* @ingroup utils
*/
struct nl_dump_params
{
/**
* Specifies the type of dump that is requested.
*/
enum nl_dump_type dp_type;
/**
* Specifies the number of whitespaces to be put in front
* of every new line (indentation).
*/
int dp_prefix;
/**
* Causes the cache index to be printed for each element.
*/
int dp_print_index;
/**
* Causes each element to be prefixed with the message type.
*/
int dp_dump_msgtype;
/**
* A callback invoked for output
*
* Passed arguments are:
* - dumping parameters
* - string to append to the output
*/
void (*dp_cb)(struct nl_dump_params *, char *);
/**
* A callback invoked for every new line, can be used to
* customize the indentation.
*
* Passed arguments are:
* - dumping parameters
* - line number starting from 0
*/
void (*dp_nl_cb)(struct nl_dump_params *, int);
/**
* User data pointer, can be used to pass data to callbacks.
*/
void *dp_data;
/**
* File descriptor the dumping output should go to
*/
FILE * dp_fd;
/**
* Alternatively the output may be redirected into a buffer
*/
char * dp_buf;
/**
* Length of the buffer dp_buf
*/
size_t dp_buflen;
/**
* PRIVATE
* Set if a dump was performed prior to the actual dump handler.
*/
int dp_pre_dump;
/**
* PRIVATE
* Owned by the current caller
*/
int dp_ivar;
unsigned int dp_line;
};
#ifndef __GNUC__
#define __extension__
#endif
#define min_t(type,x,y) \
__extension__({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
#define max_t(type,x,y) \
__extension__({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
#endif

View File

@ -0,0 +1,78 @@
/*
* netlink/utils.h Utility Functions
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_UTILS_H_
#define NETLINK_UTILS_H_
#include <netlink/netlink.h>
#include <netlink/list.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Probability Constants
* @{
*/
/**
* Lower probability limit
* @ingroup utils
*/
#define NL_PROB_MIN 0x0
/**
* Upper probability limit
* @ingroup utils
*/
#define NL_PROB_MAX 0xffffffff
/** @} */
/* unit pretty-printing */
extern double nl_cancel_down_bytes(unsigned long long, char **);
extern double nl_cancel_down_bits(unsigned long long, char **);
extern double nl_cancel_down_us(uint32_t, char **);
/* generic unit translations */
extern long nl_size2int(const char *);
extern long nl_prob2int(const char *);
/* time translations */
extern int nl_get_hz(void);
extern uint32_t nl_us2ticks(uint32_t);
extern uint32_t nl_ticks2us(uint32_t);
extern int nl_str2msec(const char *, uint64_t *);
extern char * nl_msec2str(uint64_t, char *, size_t);
/* link layer protocol translations */
extern char * nl_llproto2str(int, char *, size_t);
extern int nl_str2llproto(const char *);
/* ethernet protocol translations */
extern char * nl_ether_proto2str(int, char *, size_t);
extern int nl_str2ether_proto(const char *);
/* IP protocol translations */
extern char * nl_ip_proto2str(int, char *, size_t);
extern int nl_str2ip_proto(const char *);
/* Dumping helpers */
extern void nl_new_line(struct nl_dump_params *);
extern void nl_dump(struct nl_dump_params *, const char *, ...);
extern void nl_dump_line(struct nl_dump_params *, const char *, ...);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,18 @@
/*
* netlink/version.h Compile Time Versioning Information
*
* 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) 2008 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_VERSION_H_
#define NETLINK_VERSION_H_
#define LIBNL_STRING "libnl"
#define LIBNL_VERSION "2.0"
#endif

View File

@ -0,0 +1,47 @@
#ifndef __UNL_H
#define __UNL_H
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <stdbool.h>
struct unl {
struct nl_sock *sock;
struct nl_cache *cache;
struct genl_family *family;
char *family_name;
int hdrlen;
bool loop_done;
};
int unl_genl_init(struct unl *unl, const char *family);
void unl_free(struct unl *unl);
typedef int (*unl_cb)(struct nl_msg *, void *);
struct nl_msg *unl_genl_msg(struct unl *unl, int cmd, bool dump);
int unl_genl_request(struct unl *unl, struct nl_msg *msg, unl_cb handler, void *arg);
int unl_genl_request_single(struct unl *unl, struct nl_msg *msg, struct nl_msg **dest);
void unl_genl_loop(struct unl *unl, unl_cb handler, void *arg);
int unl_genl_multicast_id(struct unl *unl, const char *name);
int unl_genl_subscribe(struct unl *unl, const char *name);
int unl_genl_unsubscribe(struct unl *unl, const char *name);
int unl_nl80211_phy_lookup(const char *name);
int unl_nl80211_wdev_to_phy(struct unl *unl, int wdev);
struct nl_msg *unl_nl80211_phy_msg(struct unl *unl, int phy, int cmd, bool dump);
struct nl_msg *unl_nl80211_vif_msg(struct unl *unl, int dev, int cmd, bool dump);
static inline void unl_loop_done(struct unl *unl)
{
unl->loop_done = true;
}
static inline struct nlattr *unl_find_attr(struct unl *unl, struct nl_msg *msg, int attr)
{
return nlmsg_find_attr(nlmsg_hdr(msg), unl->hdrlen, attr);
}
#endif

View File

@ -0,0 +1,561 @@
/*
* lib/msg.c Netlink Messages Interface
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup core
* @defgroup msg Messages
* Netlink Message Construction/Parsing Interface
*
* The following information is partly extracted from RFC3549
* (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt)
*
* @par Message Format
* Netlink messages consist of a byte stream with one or multiple
* Netlink headers and an associated payload. If the payload is too big
* to fit into a single message it, can be split over multiple Netlink
* messages, collectively called a multipart message. For multipart
* messages, the first and all following headers have the \c NLM_F_MULTI
* Netlink header flag set, except for the last header which has the
* Netlink header type \c NLMSG_DONE.
*
* @par
* The Netlink message header (\link nlmsghdr struct nlmsghdr\endlink) is shown below.
* @code
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Process ID (PID) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* @endcode
*
* @par
* The netlink message header and payload must be aligned properly:
* @code
* <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
* +----------------------------+- - -+- - - - - - - - - - -+- - -+
* | Header | Pad | Payload | Pad |
* | struct nlmsghdr | | | |
* +----------------------------+- - -+- - - - - - - - - - -+- - -+
* @endcode
* @par
* Message Format:
* @code
* <--- nlmsg_total_size(payload) --->
* <-- nlmsg_msg_size(payload) ->
* +----------+- - -+-------------+- - -+-------- - -
* | nlmsghdr | Pad | Payload | Pad | nlmsghdr
* +----------+- - -+-------------+- - -+-------- - -
* nlmsg_data(nlh)---^ ^
* nlmsg_next(nlh)-----------------------+
* @endcode
* @par
* The payload may consist of arbitary data but may have strict
* alignment and formatting rules depening on the specific netlink
* families.
* @par
* @code
* <---------------------- nlmsg_len(nlh) --------------------->
* <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) ->
* +----------------------+- - -+--------------------------------+
* | Family Header | Pad | Attributes |
* +----------------------+- - -+--------------------------------+
* nlmsg_attrdata(nlh, hdrlen)---^
* @endcode
* @par The ACK Netlink Message
* This message is actually used to denote both an ACK and a NACK.
* Typically, the direction is from FEC to CPC (in response to an ACK
* request message). However, the CPC should be able to send ACKs back
* to FEC when requested.
* @code
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Netlink message header |
* | type = NLMSG_ERROR |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Error code |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | OLD Netlink message header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* @endcode
*
* @par Example
* @code
* // Various methods exist to create/allocate a new netlink
* // message.
* //
* // nlmsg_alloc() will allocate an empty netlink message with
* // a maximum payload size which defaults to the page size of
* // the system. This default size can be modified using the
* // function nlmsg_set_default_size().
* struct nl_msg *msg = nlmsg_alloc();
*
* // Very often, the message type and message flags are known
* // at allocation time while the other fields are auto generated:
* struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS);
*
* // Alternatively an existing netlink message header can be used
* // to inherit the header values:
* struct nlmsghdr hdr = {
* .nlmsg_type = MY_TYPE,
* .nlmsg_flags = MY_FLAGS,
* };
* struct nl_msg *msg = nlmsg_inherit(&hdr);
*
* // Last but not least, netlink messages received from netlink sockets
* // can be converted into nl_msg objects using nlmsg_convert(). This
* // will create a message with a maximum payload size which equals the
* // length of the existing netlink message, therefore no more data can
* // be appened without calling nlmsg_expand() first.
* struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock);
*
* // Payload may be added to the message via nlmsg_append(). The fourth
* // parameter specifies the number of alignment bytes the data should
* // be padding with at the end. Common values are 0 to disable it or
* // NLMSG_ALIGNTO to ensure proper netlink message padding.
* nlmsg_append(msg, &mydata, sizeof(mydata), 0);
*
* // Sometimes it may be necessary to reserve room for data but defer
* // the actual copying to a later point, nlmsg_reserve() can be used
* // for this purpose:
* void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO);
*
* // Attributes may be added using the attributes interface.
*
* // After successful use of the message, the memory must be freed
* // using nlmsg_free()
* nlmsg_free(msg);
* @endcode
*
* @par 4) Parsing messages
* @code
* int n;
* unsigned char *buf;
* struct nlmsghdr *hdr;
*
* n = nl_recv(handle, NULL, &buf);
*
* hdr = (struct nlmsghdr *) buf;
* while (nlmsg_ok(hdr, n)) {
* // Process message here...
* hdr = nlmsg_next(hdr, &n);
* }
* @endcode
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/cache.h>
#include <netlink/attr.h>
#include <netlink/msg.h>
#include <linux/socket.h>
static size_t default_msg_size = 4096;
/**
* @name Attribute Access
* @{
*/
//** @} */
/**
* @name Message Parsing
* @{
*/
/**
* check if the netlink message fits into the remaining bytes
* @arg nlh netlink message header
* @arg remaining number of bytes remaining in message stream
*/
int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
{
return (remaining >= sizeof(struct nlmsghdr) &&
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
nlh->nlmsg_len <= remaining);
}
/**
* next netlink message in message stream
* @arg nlh netlink message header
* @arg remaining number of bytes remaining in message stream
*
* @returns the next netlink message in the message stream and
* decrements remaining by the size of the current message.
*/
struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
{
int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
*remaining -= totlen;
return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
}
/**
* parse attributes of a netlink message
* @arg nlh netlink message header
* @arg hdrlen length of family specific header
* @arg tb destination array with maxtype+1 elements
* @arg maxtype maximum attribute type to be expected
* @arg policy validation policy
*
* See nla_parse()
*/
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
int maxtype, struct nla_policy *policy)
{
if (!nlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
nlmsg_attrlen(nlh, hdrlen), policy);
}
/**
* nlmsg_validate - validate a netlink message including attributes
* @arg nlh netlinket message header
* @arg hdrlen length of familiy specific header
* @arg maxtype maximum attribute type to be expected
* @arg policy validation policy
*/
int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
struct nla_policy *policy)
{
if (!nlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
return nla_validate(nlmsg_attrdata(nlh, hdrlen),
nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
}
/** @} */
/**
* @name Message Building/Access
* @{
*/
static struct nl_msg *__nlmsg_alloc(size_t len)
{
struct nl_msg *nm;
nm = calloc(1, sizeof(*nm));
if (!nm)
goto errout;
nm->nm_refcnt = 1;
nm->nm_nlh = malloc(len);
if (!nm->nm_nlh)
goto errout;
memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
nm->nm_protocol = -1;
nm->nm_size = len;
nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
return nm;
errout:
free(nm);
return NULL;
}
/**
* Allocate a new netlink message with the default maximum payload size.
*
* Allocates a new netlink message without any further payload. The
* maximum payload size defaults to PAGESIZE or as otherwise specified
* with nlmsg_set_default_size().
*
* @return Newly allocated netlink message or NULL.
*/
struct nl_msg *nlmsg_alloc(void)
{
return __nlmsg_alloc(default_msg_size);
}
/**
* Allocate a new netlink message with maximum payload size specified.
*/
struct nl_msg *nlmsg_alloc_size(size_t max)
{
return __nlmsg_alloc(max);
}
/**
* Allocate a new netlink message and inherit netlink message header
* @arg hdr Netlink message header template
*
* Allocates a new netlink message and inherits the original message
* header. If \a hdr is not NULL it will be used as a template for
* the netlink message header, otherwise the header is left blank.
*
* @return Newly allocated netlink message or NULL
*/
struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
{
struct nl_msg *nm;
nm = nlmsg_alloc();
if (nm && hdr) {
struct nlmsghdr *new = nm->nm_nlh;
new->nlmsg_type = hdr->nlmsg_type;
new->nlmsg_flags = hdr->nlmsg_flags;
new->nlmsg_seq = hdr->nlmsg_seq;
new->nlmsg_pid = hdr->nlmsg_pid;
}
return nm;
}
/**
* Allocate a new netlink message
* @arg nlmsgtype Netlink message type
* @arg flags Message flags.
*
* @return Newly allocated netlink message or NULL.
*/
struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
{
struct nl_msg *msg;
struct nlmsghdr nlh = {
.nlmsg_type = nlmsgtype,
.nlmsg_flags = flags,
};
msg = nlmsg_inherit(&nlh);
if (msg)
NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
return msg;
}
/**
* Set the default maximum message payload size for allocated messages
* @arg max Size of payload in bytes.
*/
void nlmsg_set_default_size(size_t max)
{
if (max < nlmsg_total_size(0))
max = nlmsg_total_size(0);
default_msg_size = max;
}
/**
* Convert a netlink message received from a netlink socket to a nl_msg
* @arg hdr Netlink message received from netlink socket.
*
* Allocates a new netlink message and copies all of the data pointed to
* by \a hdr into the new message object.
*
* @return Newly allocated netlink message or NULL.
*/
struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
{
struct nl_msg *nm;
nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
if (!nm)
goto errout;
memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
return nm;
errout:
nlmsg_free(nm);
return NULL;
}
/**
* Reserve room for additional data in a netlink message
* @arg n netlink message
* @arg len length of additional data to reserve room for
* @arg pad number of bytes to align data to
*
* Reserves room for additional data at the tail of the an
* existing netlink message. Eventual padding required will
* be zeroed out.
*
* @return Pointer to start of additional data tailroom or NULL.
*/
void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
{
void *buf = n->nm_nlh;
size_t nlmsg_len = n->nm_nlh->nlmsg_len;
size_t tlen;
tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
if ((tlen + nlmsg_len) > n->nm_size)
return NULL;
buf += nlmsg_len;
n->nm_nlh->nlmsg_len += tlen;
if (tlen > len)
memset(buf + len, 0, tlen - len);
NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
n, len, pad, n->nm_nlh->nlmsg_len);
return buf;
}
/**
* Append data to tail of a netlink message
* @arg n netlink message
* @arg data data to add
* @arg len length of data
* @arg pad Number of bytes to align data to.
*
* Extends the netlink message as needed and appends the data of given
* length to the message.
*
* @return 0 on success or a negative error code
*/
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
{
void *tmp;
tmp = nlmsg_reserve(n, len, pad);
if (tmp == NULL)
return -NLE_NOMEM;
memcpy(tmp, data, len);
NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
return 0;
}
/**
* Add a netlink message header to a netlink message
* @arg n netlink message
* @arg pid netlink process id or NL_AUTO_PID
* @arg seq sequence number of message or NL_AUTO_SEQ
* @arg type message type
* @arg payload length of message payload
* @arg flags message flags
*
* Adds or overwrites the netlink message header in an existing message
* object. If \a payload is greater-than zero additional room will be
* reserved, f.e. for family specific headers. It can be accesed via
* nlmsg_data().
*
* @return A pointer to the netlink message header or NULL.
*/
struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
int type, int payload, int flags)
{
struct nlmsghdr *nlh;
if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
BUG();
nlh = (struct nlmsghdr *) n->nm_nlh;
nlh->nlmsg_type = type;
nlh->nlmsg_flags = flags;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
"seq=%d\n", n, type, flags, pid, seq);
if (payload > 0 &&
nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
return NULL;
return nlh;
}
/**
* Release a reference from an netlink message
* @arg msg message to release reference from
*
* Frees memory after the last reference has been released.
*/
void nlmsg_free(struct nl_msg *msg)
{
if (!msg)
return;
msg->nm_refcnt--;
NL_DBG(4, "Returned message reference %p, %d remaining\n",
msg, msg->nm_refcnt);
if (msg->nm_refcnt < 0)
BUG();
if (msg->nm_refcnt <= 0) {
free(msg->nm_nlh);
free(msg);
NL_DBG(2, "msg %p: Freed\n", msg);
}
}
/** @} */
/**
* @name Direct Parsing
* @{
*/
/** @cond SKIP */
struct dp_xdata {
void (*cb)(struct nl_object *, void *);
void *arg;
};
/** @endcond */
static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
{
struct dp_xdata *x = p->pp_arg;
x->cb(obj, x->arg);
return 0;
}
int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
void *arg)
{
struct nl_cache_ops *ops;
struct nl_parser_param p = {
.pp_cb = parse_cb
};
struct dp_xdata x = {
.cb = cb,
.arg = arg,
};
ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
nlmsg_hdr(msg)->nlmsg_type);
if (ops == NULL)
return -NLE_MSGTYPE_NOSUPPORT;
p.pp_arg = &x;
return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
}
/** @} */

View File

@ -0,0 +1,720 @@
/*
* lib/nl.c Core Netlink Interface
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @defgroup core Core
*
* @details
* @par 1) Connecting the socket
* @code
* // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
* nl_connect(sk, NETLINK_ROUTE);
* @endcode
*
* @par 2) Sending data
* @code
* // The most rudimentary method is to use nl_sendto() simply pushing
* // a piece of data to the other netlink peer. This method is not
* // recommended.
* const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
* nl_sendto(sk, buf, sizeof(buf));
*
* // A more comfortable interface is nl_send() taking a pointer to
* // a netlink message.
* struct nl_msg *msg = my_msg_builder();
* nl_send(sk, nlmsg_hdr(msg));
*
* // nl_sendmsg() provides additional control over the sendmsg() message
* // header in order to allow more specific addressing of multiple peers etc.
* struct msghdr hdr = { ... };
* nl_sendmsg(sk, nlmsg_hdr(msg), &hdr);
*
* // You're probably too lazy to fill out the netlink pid, sequence number
* // and message flags all the time. nl_send_auto_complete() automatically
* // extends your message header as needed with an appropriate sequence
* // number, the netlink pid stored in the netlink socket and the message
* // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket)
* nl_send_auto_complete(sk, nlmsg_hdr(msg));
*
* // Simple protocols don't require the complex message construction interface
* // and may favour nl_send_simple() to easly send a bunch of payload
* // encapsulated in a netlink message header.
* nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf));
* @endcode
*
* @par 3) Receiving data
* @code
* // nl_recv() receives a single message allocating a buffer for the message
* // content and gives back the pointer to you.
* struct sockaddr_nl peer;
* unsigned char *msg;
* nl_recv(sk, &peer, &msg);
*
* // nl_recvmsgs() receives a bunch of messages until the callback system
* // orders it to state, usually after receving a compolete multi part
* // message series.
* nl_recvmsgs(sk, my_callback_configuration);
*
* // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
* // configuration stored in the socket.
* nl_recvmsgs_default(sk);
*
* // In case you want to wait for the ACK to be recieved that you requested
* // with your latest message, you can call nl_wait_for_ack()
* nl_wait_for_ack(sk);
* @endcode
*
* @par 4) Closing
* @code
* // Close the socket first to release kernel memory
* nl_close(sk);
* @endcode
*
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/handlers.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
/**
* @name Connection Management
* @{
*/
/**
* Create and connect netlink socket.
* @arg sk Netlink socket.
* @arg protocol Netlink protocol to use.
*
* Creates a netlink socket using the specified protocol, binds the socket
* and issues a connection attempt.
*
* @return 0 on success or a negative error code.
*/
int nl_connect(struct nl_sock *sk, int protocol)
{
int err;
socklen_t addrlen;
sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
if (sk->s_fd < 0) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
err = nl_socket_set_buffer_size(sk, 0, 0);
if (err < 0)
goto errout;
}
err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
sizeof(sk->s_local));
if (err < 0) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
addrlen = sizeof(sk->s_local);
err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
&addrlen);
if (err < 0) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
if (addrlen != sizeof(sk->s_local)) {
err = -NLE_NOADDR;
goto errout;
}
if (sk->s_local.nl_family != AF_NETLINK) {
err = -NLE_AF_NOSUPPORT;
goto errout;
}
sk->s_proto = protocol;
return 0;
errout:
close(sk->s_fd);
sk->s_fd = -1;
return err;
}
/**
* Close/Disconnect netlink socket.
* @arg sk Netlink socket.
*/
void nl_close(struct nl_sock *sk)
{
if (sk->s_fd >= 0) {
close(sk->s_fd);
sk->s_fd = -1;
}
sk->s_proto = 0;
}
/** @} */
/**
* @name Send
* @{
*/
/**
* Send raw data over netlink socket.
* @arg sk Netlink socket.
* @arg buf Data buffer.
* @arg size Size of data buffer.
* @return Number of characters written on success or a negative error code.
*/
int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
{
int ret;
ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
&sk->s_peer, sizeof(sk->s_peer));
if (ret < 0)
return -nl_syserr2nlerr(errno);
return ret;
}
/**
* Send netlink message with control over sendmsg() message header.
* @arg sk Netlink socket.
* @arg msg Netlink message to be sent.
* @arg hdr Sendmsg() message header.
* @return Number of characters sent on sucess or a negative error code.
*/
int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
{
struct nl_cb *cb;
int ret;
struct iovec iov = {
.iov_base = (void *) nlmsg_hdr(msg),
.iov_len = nlmsg_hdr(msg)->nlmsg_len,
};
hdr->msg_iov = &iov;
hdr->msg_iovlen = 1;
nlmsg_set_src(msg, &sk->s_local);
cb = sk->s_cb;
if (cb->cb_set[NL_CB_MSG_OUT])
if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK)
return 0;
ret = sendmsg(sk->s_fd, hdr, 0);
if (ret < 0)
return -nl_syserr2nlerr(errno);
return ret;
}
/**
* Send netlink message.
* @arg sk Netlink socket.
* @arg msg Netlink message to be sent.
* @see nl_sendmsg()
* @return Number of characters sent on success or a negative error code.
*/
int nl_send(struct nl_sock *sk, struct nl_msg *msg)
{
struct sockaddr_nl *dst;
struct ucred *creds;
struct msghdr hdr = {
.msg_name = (void *) &sk->s_peer,
.msg_namelen = sizeof(struct sockaddr_nl),
};
/* Overwrite destination if specified in the message itself, defaults
* to the peer address of the socket.
*/
dst = nlmsg_get_dst(msg);
if (dst->nl_family == AF_NETLINK)
hdr.msg_name = dst;
/* Add credentials if present. */
creds = nlmsg_get_creds(msg);
if (creds != NULL) {
char buf[CMSG_SPACE(sizeof(struct ucred))];
struct cmsghdr *cmsg;
hdr.msg_control = buf;
hdr.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
}
return nl_sendmsg(sk, msg, &hdr);
}
/**
* Send netlink message and check & extend header values as needed.
* @arg sk Netlink socket.
* @arg msg Netlink message to be sent.
*
* Checks the netlink message \c nlh for completness and extends it
* as required before sending it out. Checked fields include pid,
* sequence nr, and flags.
*
* @see nl_send()
* @return Number of characters sent or a negative error code.
*/
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
{
struct nlmsghdr *nlh;
struct nl_cb *cb = sk->s_cb;
nlh = nlmsg_hdr(msg);
if (nlh->nlmsg_pid == 0)
nlh->nlmsg_pid = sk->s_local.nl_pid;
if (nlh->nlmsg_seq == 0)
nlh->nlmsg_seq = sk->s_seq_next++;
if (msg->nm_protocol == -1)
msg->nm_protocol = sk->s_proto;
nlh->nlmsg_flags |= NLM_F_REQUEST;
if (!(sk->s_flags & NL_NO_AUTO_ACK))
nlh->nlmsg_flags |= NLM_F_ACK;
if (cb->cb_send_ow)
return cb->cb_send_ow(sk, msg);
else
return nl_send(sk, msg);
}
/**
* Send simple netlink message using nl_send_auto_complete()
* @arg sk Netlink socket.
* @arg type Netlink message type.
* @arg flags Netlink message flags.
* @arg buf Data buffer.
* @arg size Size of data buffer.
*
* Builds a netlink message with the specified type and flags and
* appends the specified data as payload to the message.
*
* @see nl_send_auto_complete()
* @return Number of characters sent on success or a negative error code.
*/
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
size_t size)
{
int err;
struct nl_msg *msg;
msg = nlmsg_alloc_simple(type, flags);
if (!msg)
return -NLE_NOMEM;
if (buf && size) {
err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
if (err < 0)
goto errout;
}
err = nl_send_auto_complete(sk, msg);
errout:
nlmsg_free(msg);
return err;
}
/** @} */
/**
* @name Receive
* @{
*/
/**
* Receive data from netlink socket
* @arg sk Netlink socket.
* @arg nla Destination pointer for peer's netlink address.
* @arg buf Destination pointer for message content.
* @arg creds Destination pointer for credentials.
*
* Receives a netlink message, allocates a buffer in \c *buf and
* stores the message content. The peer's netlink address is stored
* in \c *nla. The caller is responsible for freeing the buffer allocated
* in \c *buf if a positive value is returned. Interrupted system calls
* are handled by repeating the read. The input buffer size is determined
* by peeking before the actual read is done.
*
* A non-blocking sockets causes the function to return immediately with
* a return value of 0 if no data is available.
*
* @return Number of octets read, 0 on EOF or a negative error code.
*/
int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
unsigned char **buf, struct ucred **creds)
{
int n;
int flags = 0;
static int page_size = 0;
struct iovec iov;
struct msghdr msg = {
.msg_name = (void *) nla,
.msg_namelen = sizeof(struct sockaddr_nl),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
struct cmsghdr *cmsg;
if (sk->s_flags & NL_MSG_PEEK)
flags |= MSG_PEEK;
if (page_size == 0)
page_size = getpagesize() * 4;
iov.iov_len = page_size;
iov.iov_base = *buf = malloc(iov.iov_len);
if (sk->s_flags & NL_SOCK_PASSCRED) {
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
msg.msg_control = calloc(1, msg.msg_controllen);
}
retry:
n = recvmsg(sk->s_fd, &msg, flags);
if (!n)
goto abort;
else if (n < 0) {
if (errno == EINTR) {
NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
goto retry;
} else if (errno == EAGAIN) {
NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
goto abort;
} else {
free(msg.msg_control);
free(*buf);
return -nl_syserr2nlerr(errno);
}
}
if (iov.iov_len < n ||
msg.msg_flags & MSG_TRUNC) {
/* Provided buffer is not long enough, enlarge it
* and try again. */
iov.iov_len *= 2;
iov.iov_base = *buf = realloc(*buf, iov.iov_len);
goto retry;
} else if (msg.msg_flags & MSG_CTRUNC) {
msg.msg_controllen *= 2;
msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
goto retry;
} else if (flags != 0) {
/* Buffer is big enough, do the actual reading */
flags = 0;
goto retry;
}
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
free(msg.msg_control);
free(*buf);
return -NLE_NOADDR;
}
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS) {
*creds = calloc(1, sizeof(struct ucred));
memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
break;
}
}
free(msg.msg_control);
return n;
abort:
free(msg.msg_control);
free(*buf);
return 0;
}
#define NL_CB_CALL(cb, type, msg) \
do { \
err = nl_cb_call(cb, type, msg); \
switch (err) { \
case NL_OK: \
err = 0; \
break; \
case NL_SKIP: \
goto skip; \
case NL_STOP: \
goto stop; \
default: \
goto out; \
} \
} while (0)
static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
{
int n, err = 0, multipart = 0;
unsigned char *buf = NULL;
struct nlmsghdr *hdr;
struct sockaddr_nl nla = {0};
struct nl_msg *msg = NULL;
struct ucred *creds = NULL;
continue_reading:
NL_DBG(3, "Attempting to read from %p\n", sk);
if (cb->cb_recv_ow)
n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
else
n = nl_recv(sk, &nla, &buf, &creds);
if (n <= 0)
return n;
NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);
hdr = (struct nlmsghdr *) buf;
while (nlmsg_ok(hdr, n)) {
NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk);
nlmsg_free(msg);
msg = nlmsg_convert(hdr);
if (!msg) {
err = -NLE_NOMEM;
goto out;
}
nlmsg_set_proto(msg, sk->s_proto);
nlmsg_set_src(msg, &nla);
if (creds)
nlmsg_set_creds(msg, creds);
/* Raw callback is the first, it gives the most control
* to the user and he can do his very own parsing. */
if (cb->cb_set[NL_CB_MSG_IN])
NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
/* Sequence number checking. The check may be done by
* the user, otherwise a very simple check is applied
* enforcing strict ordering */
if (cb->cb_set[NL_CB_SEQ_CHECK])
NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
else if (hdr->nlmsg_seq != sk->s_seq_expect) {
if (cb->cb_set[NL_CB_INVALID])
NL_CB_CALL(cb, NL_CB_INVALID, msg);
else {
err = -NLE_SEQ_MISMATCH;
goto out;
}
}
if (hdr->nlmsg_type == NLMSG_DONE ||
hdr->nlmsg_type == NLMSG_ERROR ||
hdr->nlmsg_type == NLMSG_NOOP ||
hdr->nlmsg_type == NLMSG_OVERRUN) {
/* We can't check for !NLM_F_MULTI since some netlink
* users in the kernel are broken. */
sk->s_seq_expect++;
NL_DBG(3, "recvmsgs(%p): Increased expected " \
"sequence number to %d\n",
sk, sk->s_seq_expect);
}
if (hdr->nlmsg_flags & NLM_F_MULTI)
multipart = 1;
/* Other side wishes to see an ack for this message */
if (hdr->nlmsg_flags & NLM_F_ACK) {
if (cb->cb_set[NL_CB_SEND_ACK])
NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
else {
/* FIXME: implement */
}
}
/* messages terminates a multpart message, this is
* usually the end of a message and therefore we slip
* out of the loop by default. the user may overrule
* this action by skipping this packet. */
if (hdr->nlmsg_type == NLMSG_DONE) {
multipart = 0;
if (cb->cb_set[NL_CB_FINISH])
NL_CB_CALL(cb, NL_CB_FINISH, msg);
}
/* Message to be ignored, the default action is to
* skip this message if no callback is specified. The
* user may overrule this action by returning
* NL_PROCEED. */
else if (hdr->nlmsg_type == NLMSG_NOOP) {
if (cb->cb_set[NL_CB_SKIPPED])
NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
else
goto skip;
}
/* Data got lost, report back to user. The default action is to
* quit parsing. The user may overrule this action by retuning
* NL_SKIP or NL_PROCEED (dangerous) */
else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
if (cb->cb_set[NL_CB_OVERRUN])
NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
else {
err = -NLE_MSG_OVERFLOW;
goto out;
}
}
/* Message carries a nlmsgerr */
else if (hdr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *e = nlmsg_data(hdr);
if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
/* Truncated error message, the default action
* is to stop parsing. The user may overrule
* this action by returning NL_SKIP or
* NL_PROCEED (dangerous) */
if (cb->cb_set[NL_CB_INVALID])
NL_CB_CALL(cb, NL_CB_INVALID, msg);
else {
err = -NLE_MSG_TRUNC;
goto out;
}
} else if (e->error) {
/* Error message reported back from kernel. */
if (cb->cb_err) {
err = cb->cb_err(&nla, e,
cb->cb_err_arg);
if (err < 0)
goto out;
else if (err == NL_SKIP)
goto skip;
else if (err == NL_STOP) {
err = -nl_syserr2nlerr(e->error);
goto out;
}
} else {
err = -nl_syserr2nlerr(e->error);
goto out;
}
} else if (cb->cb_set[NL_CB_ACK])
NL_CB_CALL(cb, NL_CB_ACK, msg);
} else {
/* Valid message (not checking for MULTIPART bit to
* get along with broken kernels. NL_SKIP has no
* effect on this. */
if (cb->cb_set[NL_CB_VALID])
NL_CB_CALL(cb, NL_CB_VALID, msg);
}
skip:
err = 0;
hdr = nlmsg_next(hdr, &n);
}
nlmsg_free(msg);
free(buf);
free(creds);
buf = NULL;
msg = NULL;
creds = NULL;
if (multipart) {
/* Multipart message not yet complete, continue reading */
goto continue_reading;
}
stop:
err = 0;
out:
nlmsg_free(msg);
free(buf);
free(creds);
return err;
}
/**
* Receive a set of messages from a netlink socket.
* @arg sk Netlink socket.
* @arg cb set of callbacks to control behaviour.
*
* Repeatedly calls nl_recv() or the respective replacement if provided
* by the application (see nl_cb_overwrite_recv()) and parses the
* received data as netlink messages. Stops reading if one of the
* callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
*
* A non-blocking sockets causes the function to return immediately if
* no data is available.
*
* @return 0 on success or a negative error code from nl_recv().
*/
int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
{
if (cb->cb_recvmsgs_ow)
return cb->cb_recvmsgs_ow(sk, cb);
else
return recvmsgs(sk, cb);
}
static int ack_wait_handler(struct nl_msg *msg, void *arg)
{
return NL_STOP;
}
/**
* Wait for ACK.
* @arg sk Netlink socket.
* @pre The netlink socket must be in blocking state.
*
* Waits until an ACK is received for the latest not yet acknowledged
* netlink message.
*/
int nl_wait_for_ack(struct nl_sock *sk)
{
int err;
struct nl_cb *cb;
cb = nl_cb_clone(sk->s_cb);
if (cb == NULL)
return -NLE_NOMEM;
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
err = nl_recvmsgs(sk, cb);
nl_cb_put(cb);
return err;
}
/** @} */
/** @} */

View File

@ -0,0 +1,147 @@
/*
* lib/object.c Generic Cacheable Object
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cache
* @defgroup object Object
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/object.h>
#include <netlink/utils.h>
static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
{
if (!obj->ce_ops)
BUG();
return obj->ce_ops;
}
/**
* @name Object Creation/Deletion
* @{
*/
/**
* Allocate a new object of kind specified by the operations handle
* @arg ops cache operations handle
* @return The new object or NULL
*/
struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
{
struct nl_object *new;
if (ops->oo_size < sizeof(*new))
BUG();
new = calloc(1, ops->oo_size);
if (!new)
return NULL;
new->ce_refcnt = 1;
nl_init_list_head(&new->ce_list);
new->ce_ops = ops;
if (ops->oo_constructor)
ops->oo_constructor(new);
NL_DBG(4, "Allocated new object %p\n", new);
return new;
}
struct nl_derived_object {
NLHDR_COMMON
char data;
};
/**
* Allocate a new object and copy all data from an existing object
* @arg obj object to inherite data from
* @return The new object or NULL.
*/
struct nl_object *nl_object_clone(struct nl_object *obj)
{
struct nl_object *new;
struct nl_object_ops *ops = obj_ops(obj);
int doff = offsetof(struct nl_derived_object, data);
int size;
new = nl_object_alloc(ops);
if (!new)
return NULL;
size = ops->oo_size - doff;
if (size < 0)
BUG();
new->ce_ops = obj->ce_ops;
new->ce_msgtype = obj->ce_msgtype;
if (size)
memcpy((void *)new + doff, (void *)obj + doff, size);
if (ops->oo_clone) {
if (ops->oo_clone(new, obj) < 0) {
nl_object_free(new);
return NULL;
}
} else if (size && ops->oo_free_data)
BUG();
return new;
}
/**
* Free a cacheable object
* @arg obj object to free
*
* @return 0 or a negative error code.
*/
void nl_object_free(struct nl_object *obj)
{
struct nl_object_ops *ops = obj_ops(obj);
if (obj->ce_refcnt > 0)
NL_DBG(1, "Warning: Freeing object in use...\n");
if (obj->ce_cache)
nl_cache_remove(obj);
if (ops->oo_free_data)
ops->oo_free_data(obj);
free(obj);
NL_DBG(4, "Freed object %p\n", obj);
}
/** @} */
/**
* @name Reference Management
* @{
*/
/** @} */
/**
* @name Utillities
* @{
*/
/** @} */
/** @} */

View File

@ -0,0 +1,406 @@
/*
* lib/socket.c Netlink Socket
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup core
* @defgroup socket Socket
* @{
*/
#include <netlink-local.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/handlers.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
static uint32_t used_ports_map[32];
static uint32_t generate_local_port(void)
{
int i, n;
uint32_t pid = getpid() & 0x3FFFFF;
for (i = 0; i < 32; i++) {
if (used_ports_map[i] == 0xFFFFFFFF)
continue;
for (n = 0; n < 32; n++) {
if (1UL & (used_ports_map[i] >> n))
continue;
used_ports_map[i] |= (1UL << n);
n += (i * 32);
/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
* to, i.e. 1024 unique ports per application. */
return pid + (n << 22);
}
}
/* Out of sockets in our own PID namespace, what to do? FIXME */
return UINT_MAX;
}
static void release_local_port(uint32_t port)
{
int nr;
if (port == UINT_MAX)
return;
nr = port >> 22;
used_ports_map[nr / 32] &= ~(1 << nr % 32);
}
/**
* @name Allocation
* @{
*/
static struct nl_sock *__alloc_socket(struct nl_cb *cb)
{
struct nl_sock *sk;
sk = calloc(1, sizeof(*sk));
if (!sk)
return NULL;
sk->s_fd = -1;
sk->s_cb = cb;
sk->s_local.nl_family = AF_NETLINK;
sk->s_peer.nl_family = AF_NETLINK;
sk->s_seq_expect = sk->s_seq_next = time(0);
sk->s_local.nl_pid = generate_local_port();
if (sk->s_local.nl_pid == UINT_MAX) {
nl_socket_free(sk);
return NULL;
}
return sk;
}
/**
* Allocate new netlink socket
*
* @return Newly allocated netlink socket or NULL.
*/
struct nl_sock *nl_socket_alloc(void)
{
struct nl_cb *cb;
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb)
return NULL;
return __alloc_socket(cb);
}
/**
* Allocate new socket with custom callbacks
* @arg cb Callback handler
*
* The reference to the callback handler is taken into account
* automatically, it is released again upon calling nl_socket_free().
*
*@return Newly allocted socket handle or NULL.
*/
struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
{
if (cb == NULL)
BUG();
return __alloc_socket(nl_cb_get(cb));
}
/**
* Free a netlink socket.
* @arg sk Netlink socket.
*/
void nl_socket_free(struct nl_sock *sk)
{
if (!sk)
return;
if (sk->s_fd >= 0)
close(sk->s_fd);
if (!(sk->s_flags & NL_OWN_PORT))
release_local_port(sk->s_local.nl_pid);
nl_cb_put(sk->s_cb);
free(sk);
}
/** @} */
/**
* @name Sequence Numbers
* @{
*/
static int noop_seq_check(struct nl_msg *msg, void *arg)
{
return NL_OK;
}
/**
* Disable sequence number checking.
* @arg sk Netlink socket.
*
* Disables checking of sequence numbers on the netlink socket This is
* required to allow messages to be processed which were not requested by
* a preceding request message, e.g. netlink events.
*
* @note This function modifies the NL_CB_SEQ_CHECK configuration in
* the callback handle associated with the socket.
*/
void nl_socket_disable_seq_check(struct nl_sock *sk)
{
nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK,
NL_CB_CUSTOM, noop_seq_check, NULL);
}
/** @} */
/**
* Set local port of socket
* @arg sk Netlink socket.
* @arg port Local port identifier
*
* Assigns a local port identifier to the socket. If port is 0
* a unique port identifier will be generated automatically.
*/
void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
{
if (port == 0) {
port = generate_local_port();
sk->s_flags &= ~NL_OWN_PORT;
} else {
if (!(sk->s_flags & NL_OWN_PORT))
release_local_port(sk->s_local.nl_pid);
sk->s_flags |= NL_OWN_PORT;
}
sk->s_local.nl_pid = port;
}
/** @} */
/**
* @name Group Subscriptions
* @{
*/
/**
* Join groups
* @arg sk Netlink socket
* @arg group Group identifier
*
* Joins the specified groups using the modern socket option which
* is available since kernel version 2.6.14. It allows joining an
* almost arbitary number of groups without limitation. The list
* of groups has to be terminated by 0 (%NFNLGRP_NONE).
*
* Make sure to use the correct group definitions as the older
* bitmask definitions for nl_join_groups() are likely to still
* be present for backward compatibility reasons.
*
* @return 0 on sucess or a negative error code.
*/
int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
{
int err;
va_list ap;
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
va_start(ap, group);
while (group != 0) {
if (group < 0)
return -NLE_INVAL;
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
&group, sizeof(group));
if (err < 0)
return -nl_syserr2nlerr(errno);
group = va_arg(ap, int);
}
va_end(ap);
return 0;
}
/**
* Leave groups
* @arg sk Netlink socket
* @arg group Group identifier
*
* Leaves the specified groups using the modern socket option
* which is available since kernel version 2.6.14. The list of groups
* has to terminated by 0 (%NFNLGRP_NONE).
*
* @see nl_socket_add_membership
* @return 0 on success or a negative error code.
*/
int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
{
int err;
va_list ap;
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
va_start(ap, group);
while (group != 0) {
if (group < 0)
return -NLE_INVAL;
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
&group, sizeof(group));
if (err < 0)
return -nl_syserr2nlerr(errno);
group = va_arg(ap, int);
}
va_end(ap);
return 0;
}
/** @} */
/**
* Set file descriptor of socket to non-blocking state
* @arg sk Netlink socket.
*
* @return 0 on success or a negative error code.
*/
int nl_socket_set_nonblocking(struct nl_sock *sk)
{
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
return -nl_syserr2nlerr(errno);
return 0;
}
/** @} */
/**
* @name Utilities
* @{
*/
/**
* Set socket buffer size of netlink socket.
* @arg sk Netlink socket.
* @arg rxbuf New receive socket buffer size in bytes.
* @arg txbuf New transmit socket buffer size in bytes.
*
* Sets the socket buffer size of a netlink socket to the specified
* values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
* good default value.
*
* @note It is not required to call this function prior to nl_connect().
* @return 0 on sucess or a negative error code.
*/
int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
{
int err;
if (rxbuf <= 0)
rxbuf = 32768;
if (txbuf <= 0)
txbuf = 32768;
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
&txbuf, sizeof(txbuf));
if (err < 0)
return -nl_syserr2nlerr(errno);
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
&rxbuf, sizeof(rxbuf));
if (err < 0)
return -nl_syserr2nlerr(errno);
sk->s_flags |= NL_SOCK_BUFSIZE_SET;
return 0;
}
/**
* Enable/disable credential passing on netlink socket.
* @arg sk Netlink socket.
* @arg state New state (0 - disabled, 1 - enabled)
*
* @return 0 on success or a negative error code
*/
int nl_socket_set_passcred(struct nl_sock *sk, int state)
{
int err;
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
&state, sizeof(state));
if (err < 0)
return -nl_syserr2nlerr(errno);
if (state)
sk->s_flags |= NL_SOCK_PASSCRED;
else
sk->s_flags &= ~NL_SOCK_PASSCRED;
return 0;
}
/**
* Enable/disable receival of additional packet information
* @arg sk Netlink socket.
* @arg state New state (0 - disabled, 1 - enabled)
*
* @return 0 on success or a negative error code
*/
int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
{
int err;
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
&state, sizeof(state));
if (err < 0)
return -nl_syserr2nlerr(errno);
return 0;
}
/** @} */
/** @} */

View File

@ -0,0 +1,287 @@
#define _GNU_SOURCE
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/family.h>
#include <sys/types.h>
#include <net/if.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/nl80211.h>
#include "unl.h"
static int unl_init(struct unl *unl)
{
unl->sock = nl_socket_alloc();
if (!unl->sock)
return -1;
return 0;
}
int unl_genl_init(struct unl *unl, const char *family)
{
memset(unl, 0, sizeof(*unl));
if (unl_init(unl))
goto error_out;
unl->hdrlen = NLMSG_ALIGN(sizeof(struct genlmsghdr));
unl->family_name = strdup(family);
if (!unl->family_name)
goto error;
if (genl_connect(unl->sock))
goto error;
if (genl_ctrl_alloc_cache(unl->sock, &unl->cache))
goto error;
unl->family = genl_ctrl_search_by_name(unl->cache, family);
if (!unl->family)
goto error;
return 0;
error:
unl_free(unl);
error_out:
return -1;
}
void unl_free(struct unl *unl)
{
if (unl->family_name)
free(unl->family_name);
if (unl->sock)
nl_socket_free(unl->sock);
if (unl->cache)
nl_cache_free(unl->cache);
memset(unl, 0, sizeof(*unl));
}
static int
ack_handler(struct nl_msg *msg, void *arg)
{
int *err = arg;
*err = 0;
return NL_STOP;
}
static int
finish_handler(struct nl_msg *msg, void *arg)
{
int *err = arg;
*err = 0;
return NL_SKIP;
}
static int
error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
{
int *ret = arg;
*ret = err->error;
return NL_SKIP;
}
struct nl_msg *unl_genl_msg(struct unl *unl, int cmd, bool dump)
{
struct nl_msg *msg;
int flags = 0;
msg = nlmsg_alloc();
if (!msg)
goto out;
if (dump)
flags |= NLM_F_DUMP;
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
genl_family_get_id(unl->family), 0, flags, cmd, 0);
out:
return msg;
}
int unl_genl_request(struct unl *unl, struct nl_msg *msg, unl_cb handler, void *arg)
{
struct nl_cb *cb;
int err;
cb = nl_cb_alloc(NL_CB_CUSTOM);
err = nl_send_auto_complete(unl->sock, msg);
if (err < 0)
goto out;
err = 1;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
if (handler)
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
while (err > 0)
nl_recvmsgs(unl->sock, cb);
out:
nlmsg_free(msg);
nl_cb_put(cb);
return err;
}
static int request_single_cb(struct nl_msg *msg, void *arg)
{
struct nl_msg **dest = arg;
if (!*dest) {
nlmsg_get(msg);
*dest = msg;
}
return NL_SKIP;
}
int unl_genl_request_single(struct unl *unl, struct nl_msg *msg, struct nl_msg **dest)
{
*dest = NULL;
return unl_genl_request(unl, msg, request_single_cb, dest);
}
static int no_seq_check(struct nl_msg *msg, void *arg)
{
return NL_OK;
}
void unl_genl_loop(struct unl *unl, unl_cb handler, void *arg)
{
struct nl_cb *cb;
cb = nl_cb_alloc(NL_CB_CUSTOM);
unl->loop_done = false;
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
while (!unl->loop_done)
nl_recvmsgs(unl->sock, cb);
nl_cb_put(cb);
}
int unl_genl_multicast_id(struct unl *unl, const char *name)
{
struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
struct nlattr *groups, *group;
struct nl_msg *msg;
int ctrlid;
int ret = -1;
int rem;
msg = nlmsg_alloc();
if (!msg)
return -1;
ctrlid = genl_ctrl_resolve(unl->sock, "nlctrl");
genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, unl->family_name);
unl_genl_request_single(unl, msg, &msg);
if (!msg)
return -1;
groups = unl_find_attr(unl, msg, CTRL_ATTR_MCAST_GROUPS);
if (!groups)
goto nla_put_failure;
nla_for_each_nested(group, groups, rem) {
const char *gn;
nla_parse(tb, CTRL_ATTR_MCAST_GRP_MAX, nla_data(group),
nla_len(group), NULL);
if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
!tb[CTRL_ATTR_MCAST_GRP_ID])
continue;
gn = nla_data(tb[CTRL_ATTR_MCAST_GRP_NAME]);
if (strcmp(gn, name) != 0)
continue;
ret = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
break;
}
nla_put_failure:
nlmsg_free(msg);
return ret;
}
int unl_genl_subscribe(struct unl *unl, const char *name)
{
int mcid;
mcid = unl_genl_multicast_id(unl, name);
if (mcid < 0)
return mcid;
return nl_socket_add_membership(unl->sock, mcid);
}
int unl_genl_unsubscribe(struct unl *unl, const char *name)
{
int mcid;
mcid = unl_genl_multicast_id(unl, name);
if (mcid < 0)
return mcid;
return nl_socket_drop_membership(unl->sock, mcid);
}
int unl_nl80211_phy_lookup(const char *name)
{
char buf[32];
int fd, pos;
snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
fd = open(buf, O_RDONLY);
if (fd < 0)
return -1;
pos = read(fd, buf, sizeof(buf) - 1);
if (pos < 0) {
close(fd);
return -1;
}
buf[pos] = '\0';
close(fd);
return atoi(buf);
}
int unl_nl80211_wdev_to_phy(struct unl *unl, int wdev)
{
struct nl_msg *msg;
struct nlattr *attr;
int ret = -1;
msg = unl_genl_msg(unl, NL80211_CMD_GET_INTERFACE, false);
if (!msg)
return -1;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
if (unl_genl_request_single(unl, msg, &msg) < 0)
return -1;
attr = unl_find_attr(unl, msg, NL80211_ATTR_WIPHY);
if (!attr)
goto out;
ret = nla_get_u32(attr);
out:
nla_put_failure:
nlmsg_free(msg);
return ret;
}

View File

@ -1,13 +1,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=netifd
PKG_RELEASE:=2
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
PKG_SOURCE_DATE:=2019-11-12
PKG_SOURCE_VERSION:=e15147c272201eb17320c10ec95919e641bd03c5
PKG_MIRROR_HASH:=af830967d3d9f20d8d3c01b1931e501e075984043e38c23ac649faced34e896a
PKG_SOURCE_DATE:=2019-08-05
PKG_SOURCE_VERSION:=5e02f94411b06f192fb2a7d9be9abde3549153a8
PKG_MIRROR_HASH:=96e158584c605e96aceb3ce7e8ad8faa8e774ffd67d59558b2d6c2ff49d0f1a5
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0

View File

@ -1,23 +0,0 @@
. /lib/functions.sh
migrate_release() {
local config="$1"
local proto
local release
config_get proto "$config" proto
config_get release "$config" release
[ "$proto" = "dhcp" ] && [ -n "$release" ] && {
norelease="$((!$release))"
uci_set network "$config" norelease "$norelease"
uci_remove network "$config" release
}
}
config_load network
config_foreach migrate_release interface
commit network
exit 0

View File

@ -14,7 +14,7 @@ proto_dhcp_init_config() {
proto_config_add_string clientid
proto_config_add_string vendorid
proto_config_add_boolean 'broadcast:bool'
proto_config_add_boolean 'norelease:bool'
proto_config_add_boolean 'release:bool'
proto_config_add_string 'reqopts:list(string)'
proto_config_add_boolean 'defaultreqopts:bool'
proto_config_add_string iface6rd
@ -35,8 +35,8 @@ proto_dhcp_setup() {
local config="$1"
local iface="$2"
local ipaddr hostname clientid vendorid broadcast norelease reqopts defaultreqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute
json_get_vars ipaddr hostname clientid vendorid broadcast norelease reqopts defaultreqopts iface6rd delegate zone6rd zone mtu6rd customroutes classlessroute
local ipaddr hostname clientid vendorid broadcast release reqopts defaultreqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute
json_get_vars ipaddr hostname clientid vendorid broadcast release reqopts defaultreqopts iface6rd delegate zone6rd zone mtu6rd customroutes classlessroute
local opt dhcpopts
for opt in $reqopts; do
@ -50,7 +50,7 @@ proto_dhcp_setup() {
[ "$defaultreqopts" = 0 ] && defaultreqopts="-o" || defaultreqopts=
[ "$broadcast" = 1 ] && broadcast="-B" || broadcast=
[ "$norelease" = 1 ] && norelease="" || norelease="-R"
[ "$release" = 1 ] && release="-R" || release=
[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}" || clientid="-C"
[ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd"
[ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212"
@ -70,7 +70,7 @@ proto_dhcp_setup() {
${ipaddr:+-r $ipaddr} \
${hostname:+-x "hostname:$hostname"} \
${vendorid:+-V "$vendorid"} \
$clientid $defaultreqopts $broadcast $norelease $dhcpopts
$clientid $defaultreqopts $broadcast $release $dhcpopts
}
proto_dhcp_renew() {

View File

@ -8,13 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=iw
PKG_VERSION:=5.3
PKG_RELEASE:=2
PKG_VERSION:=4.14
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@KERNEL/software/network/iw
PKG_HASH:=04afe857bc8dea67e461946de30ae1b012954b6965839c5c3fda7d0ed15505d5
PKG_HASH:=f01671c0074bfdec082a884057edba1b9efd35c89eda554638496f03b769ad89
PKG_BUILD_DIR:=$(BUILD_DIR)/iw-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0

View File

@ -1,27 +1,181 @@
diff --git a/nl80211.h b/nl80211.h
index c587a61..255a971 100644
--- a/nl80211.h
+++ b/nl80211.h
@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
@@ -11,6 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -203,7 +204,8 @@
* FILS shared key authentication offload should be able to construct the
* authentication and association frames for FILS shared key authentication and
* eventually do a key derivation as per IEEE 802.11ai. The below additional
- * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ * parameters should be given to driver in %NL80211_CMD_CONNECT and/or in
+ * %NL80211_CMD_UPDATE_CONNECT_PARAMS.
* %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
* %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
@@ -214,7 +216,8 @@
* as specified in IETF RFC 6696.
*
* When FILS shared key authentication is completed, driver needs to provide the
- * below additional parameters to userspace.
+ * below additional parameters to userspace, which can be either after setting
+ * up a connection or after roaming.
* %NL80211_ATTR_FILS_KEK - used for key renewal
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
* %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
@@ -542,7 +545,8 @@
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
* %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
- * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+ * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
* %NL80211_ATTR_WIPHY_FREQ_HINT.
* If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
* restrictions on BSS selection, i.e., they effectively prevent roaming
@@ -977,21 +981,58 @@
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
* @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
- * for the given authenticator address (specified with &NL80211_ATTR_MAC).
- * When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
+ * for the given authenticator address (specified with %NL80211_ATTR_MAC).
+ * When %NL80211_ATTR_PMKR0_NAME is set, %NL80211_ATTR_PMK specifies the
* PMK-R0, otherwise it specifies the PMK.
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
* configured PMK for the authenticator address identified by
- * &NL80211_ATTR_MAC.
+ * %NL80211_ATTR_MAC.
* @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
* handshake was completed successfully by the driver. The BSSID is
- * specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ * specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
* offload should send this event after indicating 802.11 association with
- * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
- * &NL80211_CMD_DISCONNECT should be indicated instead.
+ * %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
+ * %NL80211_CMD_DISCONNECT should be indicated instead.
+ *
+ * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
+ * and RX notification. This command is used both as a request to transmit
+ * a control port frame and as a notification that a control port frame
+ * has been received. %NL80211_ATTR_FRAME is used to specify the
+ * frame contents. The frame is the raw EAPoL data, without ethernet or
+ * 802.11 headers.
+ * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
+ * indicating the protocol type of the received frame; whether the frame
+ * was received unencrypted and the MAC address of the peer respectively.
*
* @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
*
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ * drivers that do not define separate commands for authentication and
+ * association, but rely on user space for the authentication to happen.
+ * This interface acts both as the event request (driver to user space)
+ * to trigger the authentication and command response (userspace to
+ * driver) to indicate the authentication status.
+ *
+ * User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ * trigger a connection. The host driver selects a BSS and further uses
+ * this interface to offload only the authentication part to the user
+ * space. Authentication frames are passed between the driver and user
+ * space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ * further with the association after getting successful authentication
+ * status. User space indicates the authentication status through
+ * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ * command interface.
+ *
+ * Host driver reports this status on an authentication failure to the
+ * user space through the connect result as the user space would have
+ * initiated the connection through the connect request.
+ *
+ * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's
+ * ht opmode or vht opmode changes using any of %NL80211_ATTR_SMPS_MODE,
+ * %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its
+ * address(specified in %NL80211_ATTR_MAC).
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1198,6 +1239,12 @@ enum nl80211_commands {
+#define NL80211_EDMG_BW_CONFIG_MIN 4
+#define NL80211_EDMG_BW_CONFIG_MAX 15
+#define NL80211_EDMG_CHANNELS_MIN 1
+#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
NL80211_CMD_RELOAD_REGDB,
+ NL80211_CMD_EXTERNAL_AUTH,
+
/**
* DOC: Station handling
+ NL80211_CMD_STA_OPMODE_CHANGED,
+
+ NL80211_CMD_CONTROL_PORT_FRAME,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1445,6 +1492,15 @@ enum nl80211_commands {
* @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
* ethertype frames used for key negotiation must not be encrypted.
+ * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
+ * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ * will be sent directly to the network interface or sent via the NL80211
+ * socket. If this attribute is missing, then legacy behavior of sending
+ * control port frames directly to the network interface is used. If the
+ * flag is included, then control port frames are sent over NL80211 instead
+ * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
+ * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
+ * flag.
*
@@ -2361,6 +2366,16 @@ enum nl80211_commands {
* @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
* functionality.
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -1932,6 +1988,12 @@ enum nl80211_commands {
* multicast group.
* If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
* station will deauthenticate when the socket is closed.
+ * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically
+ * torn down when the socket is closed.
+ * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be
+ * automatically torn down when the socket is closed.
+ * If set during %NL80211_CMD_START_AP the AP will be automatically
+ * disabled when the socket is closed.
*
+ * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
+ * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations. (u8 attribute)
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -2153,6 +2215,35 @@ enum nl80211_commands {
* @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
* @NL80211_ATTR_PORT_AUTHORIZED: (reserved)
*
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ * authentication operation (u32 attribute with an
+ * &enum nl80211_external_auth_action value). This is used with the
+ * %NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ * space supports external authentication. This attribute shall be used
+ * only with %NL80211_CMD_CONNECT request. The driver may offload
+ * authentication processing to user space if this capability is indicated
+ * in NL80211_CMD_CONNECT requests from the user space.
+ *
+ * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
+ * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
+ *
+ * @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum
+ * nl80211_txq_stats)
+ * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
+ * The smaller of this and the memory limit is enforced.
+ * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
+ * TXQ queues for this phy. The smaller of this and the packet limit is
+ * enforced.
+ * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
+ * a flow is assigned on each round of the DRR scheduler.
+ * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION). Can be set
+ * only if %NL80211_STA_FLAG_WME is set.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
@ -29,88 +183,447 @@
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2820,6 +2835,11 @@ enum nl80211_attrs {
@@ -2579,6 +2670,23 @@ enum nl80211_attrs {
NL80211_ATTR_PMKR0_NAME,
NL80211_ATTR_PORT_AUTHORIZED,
NL80211_ATTR_HE_OBSS_PD,
+ NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+ NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
+ NL80211_ATTR_NSS,
+ NL80211_ATTR_ACK_SIGNAL,
+
+ NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
+
+ NL80211_ATTR_TXQ_STATS,
+ NL80211_ATTR_TXQ_LIMIT,
+ NL80211_ATTR_TXQ_MEMORY_LIMIT,
+ NL80211_ATTR_TXQ_QUANTUM,
+
+ NL80211_ATTR_HE_CAPABILITY,
+
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3201,6 +3221,8 @@ enum nl80211_sta_bss_param {
* sent to the station (u64, usec)
* @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
+ * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
+ * of STA's association
@@ -2618,6 +2726,8 @@ enum nl80211_attrs {
#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+#define NL80211_WIPHY_NAME_MAXLEN 64
+
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 64
@@ -2626,7 +2736,8 @@ enum nl80211_attrs {
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
-
+#define NL80211_HE_MIN_CAPABILITY_LEN 16
+#define NL80211_HE_MAX_CAPABILITY_LEN 51
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -2754,6 +2865,38 @@ struct nl80211_sta_flag_update {
} __attribute__((packed));
/**
+ * enum nl80211_he_gi - HE guard interval
+ * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
+ */
+enum nl80211_he_gi {
+ NL80211_RATE_INFO_HE_GI_0_8,
+ NL80211_RATE_INFO_HE_GI_1_6,
+ NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+/**
+ * enum nl80211_he_ru_alloc - HE RU allocation values
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation
+ */
+enum nl80211_he_ru_alloc {
+ NL80211_RATE_INFO_HE_RU_ALLOC_26,
+ NL80211_RATE_INFO_HE_RU_ALLOC_52,
+ NL80211_RATE_INFO_HE_RU_ALLOC_106,
+ NL80211_RATE_INFO_HE_RU_ALLOC_242,
+ NL80211_RATE_INFO_HE_RU_ALLOC_484,
+ NL80211_RATE_INFO_HE_RU_ALLOC_996,
+ NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
+};
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -2785,6 +2928,13 @@ struct nl80211_sta_flag_update {
* @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
* a legacy rate and will be reported as the actual bitrate, i.e.
* a quarter of the base (20 MHz) rate
+ * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
+ * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
+ * (u8, see &enum nl80211_he_gi)
+ * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
+ * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
+ * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -2801,6 +2951,11 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_160_MHZ_WIDTH,
NL80211_RATE_INFO_10_MHZ_WIDTH,
NL80211_RATE_INFO_5_MHZ_WIDTH,
+ NL80211_RATE_INFO_HE_MCS,
+ NL80211_RATE_INFO_HE_NSS,
+ NL80211_RATE_INFO_HE_GI,
+ NL80211_RATE_INFO_HE_DCM,
+ NL80211_RATE_INFO_HE_RU_ALLOC,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2899,6 +3054,9 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
* received from the station (u64, usec)
* @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
+ * @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data)
+ * ACK frame (s8, dBm)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3247,6 +3269,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
+ NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
@@ -2937,6 +3095,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TID_STATS,
NL80211_STA_INFO_RX_DURATION,
NL80211_STA_INFO_PAD,
+ NL80211_STA_INFO_ACK_SIGNAL,
+ NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3428,6 +3451,12 @@ enum nl80211_band_iftype_attr {
@@ -2954,6 +3114,7 @@ enum nl80211_sta_info {
* @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
* MSDUs (u64)
* @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute)
* @NUM_NL80211_TID_STATS: number of attributes here
* @NL80211_TID_STATS_MAX: highest numbered attribute here
*/
@@ -2964,6 +3125,7 @@ enum nl80211_tid_stats {
NL80211_TID_STATS_TX_MSDU_RETRIES,
NL80211_TID_STATS_TX_MSDU_FAILED,
NL80211_TID_STATS_PAD,
+ NL80211_TID_STATS_TXQ_STATS,
/* keep last */
NUM_NL80211_TID_STATS,
@@ -2971,6 +3133,44 @@ enum nl80211_tid_stats {
};
/**
+ * enum nl80211_txq_stats - per TXQ statistics attributes
+ * @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved
+ * @NUM_NL80211_TXQ_STATS: number of attributes here
+ * @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged
+ * @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently
+ * backlogged
+ * @NL80211_TXQ_STATS_FLOWS: total number of new flows seen
+ * @NL80211_TXQ_STATS_DROPS: total number of packet drops
+ * @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks
+ * @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow
+ * @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow
+ * (only for per-phy stats)
+ * @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions
+ * @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ
+ * @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ
+ * @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY
+ * @NL80211_TXQ_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_txq_stats {
+ __NL80211_TXQ_STATS_INVALID,
+ NL80211_TXQ_STATS_BACKLOG_BYTES,
+ NL80211_TXQ_STATS_BACKLOG_PACKETS,
+ NL80211_TXQ_STATS_FLOWS,
+ NL80211_TXQ_STATS_DROPS,
+ NL80211_TXQ_STATS_ECN_MARKS,
+ NL80211_TXQ_STATS_OVERLIMIT,
+ NL80211_TXQ_STATS_OVERMEMORY,
+ NL80211_TXQ_STATS_COLLISIONS,
+ NL80211_TXQ_STATS_TX_BYTES,
+ NL80211_TXQ_STATS_TX_PACKETS,
+ NL80211_TXQ_STATS_MAX_FLOWS,
+
+ /* keep last */
+ NUM_NL80211_TXQ_STATS,
+ NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1
+};
+
+/**
* enum nl80211_mpath_flags - nl80211 mesh path flags
*
* @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -3022,6 +3222,38 @@ enum nl80211_mpath_info {
};
/**
+ * enum nl80211_band_iftype_attr - Interface type data attributes
+ *
+ * @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute
+ * for each interface type that supports the band data
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
+ * defined in HE capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
+ * defined
+ * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_iftype_attr {
+ __NL80211_BAND_IFTYPE_ATTR_INVALID,
+
+ NL80211_BAND_IFTYPE_ATTR_IFTYPES,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+
+ /* keep last */
+ __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
+ NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_band_attr - band attributes
* @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
@@ -3036,6 +3268,8 @@ enum nl80211_mpath_info {
* @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
* defined in 802.11ac
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
* attributes from &enum nl80211_band_iftype_attr
+ * @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
+ * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
+ * attributes from &enum nl80211_band_iftype_attr
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -3445,6 +3474,9 @@ enum nl80211_band_attr {
NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA,
@@ -3051,6 +3285,7 @@ enum nl80211_band_attr {
NL80211_BAND_ATTR_VHT_MCS_SET,
NL80211_BAND_ATTR_VHT_CAPA,
+ NL80211_BAND_ATTR_IFTYPE_DATA,
+ NL80211_BAND_ATTR_EDMG_CHANNELS,
+ NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -3843,6 +3875,8 @@ enum nl80211_user_reg_hint_type {
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent
+ * receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
@@ -3060,6 +3295,29 @@ enum nl80211_band_attr {
#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
/**
+ * enum nl80211_wmm_rule - regulatory wmm rule
+ *
+ * @__NL80211_WMMR_INVALID: attribute number 0 is reserved
+ * @NL80211_WMMR_CW_MIN: Minimum contention window slot.
+ * @NL80211_WMMR_CW_MAX: Maximum contention window slot.
+ * @NL80211_WMMR_AIFSN: Arbitration Inter Frame Space.
+ * @NL80211_WMMR_TXOP: Maximum allowed tx operation time.
+ * @nl80211_WMMR_MAX: highest possible wmm rule.
+ * @__NL80211_WMMR_LAST: Internal use.
+ */
+enum nl80211_wmm_rule {
+ __NL80211_WMMR_INVALID,
+ NL80211_WMMR_CW_MIN,
+ NL80211_WMMR_CW_MAX,
+ NL80211_WMMR_AIFSN,
+ NL80211_WMMR_TXOP,
+
+ /* keep last */
+ __NL80211_WMMR_LAST,
+ NL80211_WMMR_MAX = __NL80211_WMMR_LAST - 1
+};
+
+/**
* enum nl80211_frequency_attr - frequency attributes
* @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
@@ -3108,6 +3366,9 @@ enum nl80211_band_attr {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
+ * This is a nested attribute that contains the wmm limitation per AC.
+ * (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -3859,6 +3893,7 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
+ NL80211_SURVEY_INFO_TIME_BSS_RX,
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3136,6 +3397,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
+ NL80211_FREQUENCY_ATTR_WMM,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4543,6 +4578,7 @@ enum nl80211_txrate_gi {
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
+ * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4550,6 +4586,7 @@ enum nl80211_band {
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3319,7 +3581,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
* @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -4945,6 +5207,27 @@ enum nl80211_feature_flags {
* probe request tx deferral and suppression
* @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
* value in %NL80211_ATTR_USE_MFP.
+ * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
+ * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
+ * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
+ * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
+ * Device or driver will do all DFS-related actions by itself,
+ * informing user-space about CAC progress, radar detection event,
+ * channel change triggered by radar detection event.
+ * No need to start CAC from user-space, no need to react to
+ * "radar detected" event.
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
+ * receiving control port frames over nl80211 instead of the netdevice.
+ * @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack
+ * rssi if firmware support, this flag is to intimate about ack rssi
+ * support to nl80211.
+ * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
+ * TXQs.
+ * @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
+ * SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN.
+ * @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
+ * except for supported rates from the probe request content if requested
+ * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4972,6 +5255,15 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
NL80211_EXT_FEATURE_MFP_OPTIONAL,
+ NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
+ NL80211_EXT_FEATURE_LOW_POWER_SCAN,
+ NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
+ NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
+ NL80211_EXT_FEATURE_TXQS,
+ NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
+ NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
NUM_NL80211_BANDS,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -5032,6 +5324,10 @@ enum nl80211_timeout_reason {
* of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
* requests.
*
+ * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and
+ * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only
+ * one of them can be used in the request.
+ *
* @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
* @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
* @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
@@ -5059,7 +5355,26 @@ enum nl80211_timeout_reason {
* and suppression (if it has received a broadcast Probe Response frame,
* Beacon frame or FILS Discovery frame from an AP that the STA considers
* a suitable candidate for (re-)association - suitable in terms of
- * SSID and/or RSSI
+ * SSID and/or RSSI.
+ * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to
+ * accomplish the scan. Thus, this flag intends the driver to perform the
+ * scan request with lesser span/duration. It is specific to the driver
+ * implementations on how this is accomplished. Scan accuracy may get
+ * impacted with this flag.
+ * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume
+ * optimal possible power. Drivers can resort to their specific means to
+ * optimize the power. Scan accuracy may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan
+ * results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum
+ * possible scan results. This flag hints the driver to use the best
+ * possible scan configuration to improve the accuracy in scanning.
+ * Latency and power use may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_RANDOM_SN: randomize the sequence number in probe
+ * request frames from this scan to avoid correlation/tracking being
+ * possible.
+ * @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
+ * only have supported rates and no additional capabilities (unless
+ * added by userspace explicitly.)
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
@@ -5070,6 +5385,11 @@ enum nl80211_scan_flags {
NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = 1<<5,
NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = 1<<6,
NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 1<<7,
+ NL80211_SCAN_FLAG_LOW_SPAN = 1<<8,
+ NL80211_SCAN_FLAG_LOW_POWER = 1<<9,
+ NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
+ NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
+ NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
};
/**
@@ -5127,6 +5447,8 @@ enum nl80211_smps_mode {
* non-operating channel is expired and no longer valid. New CAC must
* be done on this channel before starting the operation. This is not
* applicable for ETSI dfs domain where pre-CAC is valid for ever.
+ * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
+ * should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
*/
enum nl80211_radar_event {
NL80211_RADAR_DETECTED,
@@ -5134,6 +5456,7 @@ enum nl80211_radar_event {
NL80211_RADAR_CAC_ABORTED,
NL80211_RADAR_NOP_FINISHED,
NL80211_RADAR_PRE_CAC_EXPIRED,
+ NL80211_RADAR_CAC_STARTED,
};
/**
@@ -5425,11 +5748,11 @@ enum nl80211_nan_func_attributes {
* @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
* This is a flag.
* @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
- * &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
+ * %NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
* @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
- * &NL80211_NAN_SRF_BF is present. This is a u8.
+ * %NL80211_NAN_SRF_BF is present. This is a u8.
* @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
- * and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
+ * and only if %NL80211_NAN_SRF_BF isn't present. This is a nested
* attribute. Each nested attribute is a MAC address.
* @NUM_NL80211_NAN_SRF_ATTR: internal
* @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
@@ -5469,4 +5792,15 @@ enum nl80211_nan_match_attributes {
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
};
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ * authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+ NL80211_EXTERNAL_AUTH_START,
+ NL80211_EXTERNAL_AUTH_ABORT,
+};
+
#endif /* __LINUX_NL80211_H */

View File

@ -1,9 +1,9 @@
--- a/phy.c
+++ b/phy.c
@@ -855,3 +855,30 @@ static int handle_get_txq(struct nl80211
COMMAND(get, txq, "",
NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
"Get TXQ parameters.");
@@ -727,3 +727,30 @@ COMMAND(set, antenna, "<bitmap> | all |
NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
"Set a bitmap of allowed antennas to use for TX and RX.\n"
"The driver may reject antenna configurations it cannot support.");
+
+static int handle_antenna_gain(struct nl80211_state *state,
+ struct nl_msg *msg,

View File

@ -1,12 +0,0 @@
--- a/survey.c
+++ b/survey.c
@@ -60,6 +60,9 @@ static int print_survey_handler(struct n
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX])
printf("\tchannel receive time:\t\t%llu ms\n",
(unsigned long long)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]));
+ if (sinfo[NL80211_SURVEY_INFO_TIME_BSS_RX])
+ printf("\tchannel BSS receive time:\t%llu ms\n",
+ (unsigned long long)nla_get_u64(sinfo[NL80211_SURVEY_INFO_TIME_BSS_RX]));
if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX])
printf("\tchannel transmit time:\t\t%llu ms\n",
(unsigned long long)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]));

View File

@ -1,6 +1,6 @@
--- a/event.c
+++ b/event.c
@@ -699,6 +699,7 @@ static int print_event(struct nl_msg *ms
@@ -342,6 +342,7 @@ static int print_event(struct nl_msg *ms
}
switch (gnlh->cmd) {
@ -8,7 +8,7 @@
case NL80211_CMD_NEW_WIPHY:
printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
break;
@@ -734,6 +735,7 @@ static int print_event(struct nl_msg *ms
@@ -376,6 +377,7 @@ static int print_event(struct nl_msg *ms
case NL80211_CMD_SCHED_SCAN_RESULTS:
printf("got scheduled scan results\n");
break;
@ -16,7 +16,7 @@
case NL80211_CMD_REG_CHANGE:
printf("regulatory domain change: ");
@@ -812,6 +814,7 @@ static int print_event(struct nl_msg *ms
@@ -454,6 +456,7 @@ static int print_event(struct nl_msg *ms
mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
printf("del station %s\n", macbuf);
break;
@ -24,10 +24,10 @@
case NL80211_CMD_JOIN_IBSS:
mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
printf("IBSS %s joined\n", macbuf);
@@ -989,9 +992,9 @@ static int print_event(struct nl_msg *ms
parse_nan_match(tb);
@@ -618,9 +621,9 @@ static int print_event(struct nl_msg *ms
case NL80211_CMD_DEL_WIPHY:
printf("delete wiphy\n");
break;
}
+#endif
default:
- printf("unknown event %d (%s)\n",
@ -38,23 +38,7 @@
--- a/info.c
+++ b/info.c
@@ -164,6 +164,7 @@ static int print_phy_handler(struct nl_m
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])
print_vht_info(nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]),
nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]));
+#ifdef IW_FULL
if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) {
struct nlattr *nl_iftype;
int rem_band;
@@ -171,6 +172,7 @@ static int print_phy_handler(struct nl_m
nla_for_each_nested(nl_iftype, tb_band[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band)
print_he_info(nl_iftype);
}
+#endif
if (tb_band[NL80211_BAND_ATTR_FREQS]) {
if (!band_had_freq) {
printf("\t\tFrequencies:\n");
@@ -213,6 +215,7 @@ next:
@@ -197,6 +197,7 @@ next:
}
}
@ -62,7 +46,7 @@
if (tb_band[NL80211_BAND_ATTR_RATES]) {
printf("\t\tBitrates (non-HT):\n");
nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
@@ -229,6 +232,7 @@ next:
@@ -213,6 +214,7 @@ next:
printf("\n");
}
}
@ -70,7 +54,7 @@
}
}
@@ -294,6 +298,7 @@ next:
@@ -278,6 +280,7 @@ next:
printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
}
@ -78,7 +62,7 @@
if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) {
int num = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
int i;
@@ -305,6 +310,7 @@ next:
@@ -289,6 +292,7 @@ next:
cipher_name(ciphers[i]));
}
}
@ -86,7 +70,7 @@
if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX] &&
tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])
@@ -324,11 +330,13 @@ next:
@@ -308,11 +312,13 @@ next:
printf("\t\t * %s\n", iftype_name(nla_type(nl_mode)));
}
@ -100,7 +84,7 @@
if (tb_msg[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
struct nlattr *nl_combi;
@@ -425,6 +433,7 @@ broken_combination:
@@ -409,6 +415,7 @@ broken_combination:
printf("\tinterface combinations are not supported\n");
}
@ -108,7 +92,7 @@
if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
printf("\tSupported commands:\n");
nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], rem_cmd)
@@ -522,6 +531,7 @@ broken_combination:
@@ -506,6 +513,7 @@ broken_combination:
printf("\t\t * wake up on TCP connection\n");
}
}
@ -116,7 +100,7 @@
if (tb_msg[NL80211_ATTR_ROAM_SUPPORT])
printf("\tDevice supports roaming.\n");
@@ -560,6 +570,7 @@ broken_combination:
@@ -544,6 +552,7 @@ broken_combination:
}
}
@ -124,15 +108,15 @@
if (tb_msg[NL80211_ATTR_FEATURE_FLAGS]) {
unsigned int features = nla_get_u32(tb_msg[NL80211_ATTR_FEATURE_FLAGS]);
@@ -624,6 +635,7 @@ broken_combination:
if (features & NL80211_FEATURE_ND_RANDOM_MAC_ADDR)
printf("\tDevice supports randomizing MAC-addr in net-detect scans.\n");
@@ -602,6 +611,7 @@ broken_combination:
if (features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)
printf("\tDevice supports TDLS channel switching\n");
}
+#endif
if (tb_msg[NL80211_ATTR_TDLS_SUPPORT])
printf("\tDevice supports T-DLS.\n");
@@ -732,6 +744,7 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIP
if (tb_msg[NL80211_ATTR_EXT_FEATURES]) {
struct nlattr *tb = tb_msg[NL80211_ATTR_EXT_FEATURES];
@@ -658,6 +668,7 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIP
"List all wireless devices and their capabilities.");
TOPLEVEL(phy, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, NULL);
@ -140,7 +124,7 @@
static int handle_commands(struct nl80211_state *state, struct nl_msg *msg,
int argc, char **argv, enum id_input id)
{
@@ -743,6 +756,7 @@ static int handle_commands(struct nl8021
@@ -669,6 +680,7 @@ static int handle_commands(struct nl8021
}
TOPLEVEL(commands, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_NONE, handle_commands,
"list all known commands and their decimal & hex value");
@ -150,17 +134,15 @@
{
--- a/scan.c
+++ b/scan.c
@@ -1197,6 +1197,9 @@ static void print_ht_op(const uint8_t ty
@@ -1170,6 +1170,7 @@ static void print_ht_op(const uint8_t ty
printf("\t\t * secondary channel offset: %s\n",
ht_secondary_offset[data[1] & 0x3]);
printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
+#ifndef IW_FULL
+ return;
+#endif
printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
@@ -1524,6 +1527,14 @@ static void print_ie(const struct ie_pri
@@ -1497,6 +1498,14 @@ static void print_ie(const struct ie_pri
static const struct ie_print ieprinters[] = {
[0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
@ -175,7 +157,7 @@
[1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
[3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
[5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
@@ -1533,21 +1544,15 @@ static const struct ie_print ieprinters[
@@ -1506,21 +1515,15 @@ static const struct ie_print ieprinters[
[32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
[35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
[42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
@ -198,7 +180,7 @@
};
static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
@@ -2026,6 +2031,7 @@ void print_ies(unsigned char *ie, int ie
@@ -1968,6 +1971,7 @@ void print_ies(unsigned char *ie, int ie
ieprinters[ie[0]].flags & BIT(ptype)) {
print_ie(&ieprinters[ie[0]],
ie[0], ie[1], ie + 2, &ie_buffer);
@ -206,7 +188,7 @@
} else if (ie[0] == 221 /* vendor */) {
print_vendor(ie[1], ie + 2, unknown, ptype);
} else if (unknown) {
@@ -2035,6 +2041,7 @@ void print_ies(unsigned char *ie, int ie
@@ -1977,6 +1981,7 @@ void print_ies(unsigned char *ie, int ie
for (i=0; i<ie[1]; i++)
printf(" %.2x", ie[2+i]);
printf("\n");
@ -214,7 +196,7 @@
}
ielen -= ie[1] + 2;
ie += ie[1] + 2;
@@ -2075,6 +2082,7 @@ static void print_capa_non_dmg(__u16 cap
@@ -2017,6 +2022,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" ESS");
if (capa & WLAN_CAPABILITY_IBSS)
printf(" IBSS");
@ -222,7 +204,7 @@
if (capa & WLAN_CAPABILITY_CF_POLLABLE)
printf(" CfPollable");
if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
@@ -2103,6 +2111,7 @@ static void print_capa_non_dmg(__u16 cap
@@ -2045,6 +2051,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" DelayedBACK");
if (capa & WLAN_CAPABILITY_IMM_BACK)
printf(" ImmediateBACK");
@ -230,7 +212,7 @@
}
static int print_bss_handler(struct nl_msg *msg, void *arg)
@@ -2187,8 +2196,10 @@ static int print_bss_handler(struct nl_m
@@ -2129,8 +2136,10 @@ static int print_bss_handler(struct nl_m
if (bss[NL80211_BSS_FREQUENCY]) {
int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
printf("\tfreq: %d\n", freq);
@ -241,7 +223,7 @@
}
if (bss[NL80211_BSS_BEACON_INTERVAL])
printf("\tbeacon interval: %d TUs\n",
@@ -2382,6 +2393,7 @@ static int handle_stop_sched_scan(struct
@@ -2319,6 +2328,7 @@ static int handle_stop_sched_scan(struct
return 0;
}
@ -249,14 +231,14 @@
COMMAND(scan, sched_start,
SCHED_SCAN_OPTIONS,
NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
@@ -2392,3 +2404,4 @@ COMMAND(scan, sched_start,
@@ -2329,3 +2339,4 @@ COMMAND(scan, sched_start,
COMMAND(scan, sched_stop, "",
NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
"Stop an ongoing scheduled scan.");
+#endif
--- a/util.c
+++ b/util.c
@@ -291,6 +291,7 @@ static const char *commands[NL80211_CMD_
@@ -281,6 +281,7 @@ static const char *commands[NL80211_CMD_
static char cmdbuf[100];
@ -264,7 +246,7 @@
const char *command_name(enum nl80211_commands cmd)
{
if (cmd <= NL80211_CMD_MAX && commands[cmd])
@@ -298,6 +299,7 @@ const char *command_name(enum nl80211_co
@@ -288,6 +289,7 @@ const char *command_name(enum nl80211_co
sprintf(cmdbuf, "Unknown command (%d)", cmd);
return cmdbuf;
}
@ -272,23 +254,23 @@
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
{
@@ -436,6 +438,9 @@ int parse_keys(struct nl_msg *msg, char
@@ -426,6 +428,9 @@ int parse_keys(struct nl_msg *msg, char
char keybuf[13];
int pos = 0;
+#ifndef IW_FULL
+ return 1;
+#endif
if (!*argc)
if (!argc)
return 1;
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,12 @@ _OBJS := $(sort $(patsubst %.c,%.o,$(wil
VERSION_OBJS := $(filter-out version.o, $(_OBJS))
OBJS := $(VERSION_OBJS) version.o
@@ -25,6 +25,12 @@ OBJS-$(HWSIM) += hwsim.o
+OBJS_FULL = ocb offch cqm wowlan coalesce roc p2p vendor mgmt ap sha256 nan bloom measurements ftm
OBJS += $(OBJS-y) $(OBJS-Y)
+OBJS_FULL = ocb offch cqm wowlan coalesce roc p2p ap mgmt vendor
+ifdef IW_FULL
+ CFLAGS += -DIW_FULL
+else
@ -299,7 +281,7 @@
ifeq ($(NO_PKG_CONFIG),)
--- a/station.c
+++ b/station.c
@@ -736,10 +736,12 @@ static int handle_station_set_plink(stru
@@ -629,10 +629,12 @@ static int handle_station_set_plink(stru
nla_put_failure:
return -ENOBUFS;
}
@ -312,7 +294,7 @@
static int handle_station_set_vlan(struct nl80211_state *state,
struct nl_msg *msg,
@@ -834,11 +836,13 @@ static int handle_station_set_mesh_power
@@ -727,11 +729,13 @@ static int handle_station_set_mesh_power
nla_put_failure:
return -ENOBUFS;
}
@ -324,11 +306,11 @@
select_station_cmd, station_set_mesh_power_mode);
+#endif
static int handle_station_set_airtime_weight(struct nl80211_state *state,
struct nl_msg *msg,
static int handle_station_dump(struct nl80211_state *state,
struct nl_msg *msg,
--- a/interface.c
+++ b/interface.c
@@ -627,9 +627,11 @@ static int handle_interface_wds_peer(str
@@ -615,9 +615,11 @@ static int handle_interface_wds_peer(str
nla_put_failure:
return -ENOBUFS;
}
@ -340,7 +322,7 @@
static int set_mcast_rate(struct nl80211_state *state,
struct nl_msg *msg,
@@ -719,6 +721,7 @@ static int handle_chan(struct nl80211_st
@@ -707,6 +709,7 @@ static int handle_chan(struct nl80211_st
return handle_chanfreq(state, msg, true, argc, argv, id);
}
@ -348,22 +330,22 @@
SECTION(switch);
COMMAND(switch, freq,
"<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]\n"
@@ -727,3 +730,4 @@ COMMAND(switch, freq,
@@ -715,3 +718,4 @@ COMMAND(switch, freq,
"Switch the operating channel by sending a channel switch announcement (CSA).");
COMMAND(switch, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]",
NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_chan, NULL);
+#endif
--- a/phy.c
+++ b/phy.c
@@ -369,6 +369,7 @@ err_out:
free(cac_trigger_argv);
return err;
@@ -359,6 +359,7 @@ static int handle_cac(struct nl80211_sta
return 0;
}
+#ifdef IW_FULL
TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
"freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
"freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
@@ -380,6 +381,7 @@ COMMAND(cac, trigger,
@@ -370,6 +371,7 @@ COMMAND(cac, trigger,
NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
"Start or trigger a channel availability check (CAC) looking to look for\n"
"radars on the given channel.");