mirror of
https://github.com/apache/nuttx.git
synced 2026-05-16 13:56:00 +08:00
netlink: add RTM_NEWADDR, RTM_DELADDR and RTM_GETADDR
We have projects that need to sense ip address changes in time, and set ip address or clear ip address through netlink so the relevant implementation is added. The usage and command structure are consistent with linux Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
@@ -85,6 +85,8 @@ struct ifaddrmsg
|
||||
*
|
||||
* IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
|
||||
* If present, the value from struct ifaddrmsg will be ignored.
|
||||
*
|
||||
* IFA_RT_PRIORITY is a u32 attribute, priority/metric for prefix route
|
||||
*/
|
||||
|
||||
enum
|
||||
@@ -98,6 +100,7 @@ enum
|
||||
IFA_CACHEINFO,
|
||||
IFA_MULTICAST,
|
||||
IFA_FLAGS,
|
||||
IFA_RT_PRIORITY,
|
||||
__IFA_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -389,6 +389,25 @@
|
||||
#define RTNLGRP_NSID 28
|
||||
#define RTNLGRP_MAX 29
|
||||
|
||||
/**
|
||||
* nla_type (16 bits)
|
||||
* +---+---+-------------------------------+
|
||||
* | N | O | Attribute Type |
|
||||
* +---+---+-------------------------------+
|
||||
* N := Carries nested attributes
|
||||
* O := Payload stored in network byte order
|
||||
*
|
||||
* Note: The N and O flag are mutually exclusive.
|
||||
*/
|
||||
|
||||
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||
#define NLA_F_NESTED (1 << 15)
|
||||
#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
|
||||
|
||||
#define NLA_ALIGNTO 4
|
||||
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
|
||||
#define NLA_HDRLEN (NLA_ALIGN(sizeof(struct nlattr)))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
@@ -503,6 +522,41 @@ struct rtmsg
|
||||
uint32_t rtm_flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
|
||||
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
||||
* | Header | Pad | Payload | Pad |
|
||||
* | (struct nlattr) | ing | | ing |
|
||||
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
||||
* <-------------- nlattr->nla_len -------------->
|
||||
*/
|
||||
|
||||
struct nlattr
|
||||
{
|
||||
uint16_t nla_len;
|
||||
uint16_t nla_type;
|
||||
};
|
||||
|
||||
/* Generic 32 bitflags attribute content sent to the kernel.
|
||||
*
|
||||
* The value is a bitmap that defines the values being set
|
||||
* The selector is a bitmask that defines which value is legit
|
||||
*
|
||||
* Examples:
|
||||
* value = 0x0, and selector = 0x1
|
||||
* implies we are selecting bit 1 and we want to set its value to 0.
|
||||
*
|
||||
* value = 0x2, and selector = 0x2
|
||||
* implies we are selecting bit 2 and we want to set its value to 1.
|
||||
*
|
||||
*/
|
||||
|
||||
struct nla_bitfield32
|
||||
{
|
||||
uint32_t value;
|
||||
uint32_t selector;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
@@ -839,6 +839,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
|
||||
|
||||
case SIOCSIFADDR: /* Set IP address */
|
||||
ioctl_set_ipv4addr(&dev->d_ipaddr, &req->ifr_addr);
|
||||
netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET);
|
||||
break;
|
||||
|
||||
case SIOCGIFDSTADDR: /* Get P-to-P address */
|
||||
@@ -879,6 +880,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
|
||||
{
|
||||
FAR struct lifreq *lreq = (FAR struct lifreq *)req;
|
||||
ioctl_set_ipv6addr(dev->d_ipv6addr, &lreq->lifr_addr);
|
||||
netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1040,9 +1042,11 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
|
||||
case SIOCDIFADDR: /* Delete IP address */
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
dev->d_ipaddr = 0;
|
||||
netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET);
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t));
|
||||
netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
@@ -91,6 +91,31 @@ config NETLINK_DISABLE_GETROUTE
|
||||
---help---
|
||||
RTM_GETROUTE is used to retrieve routing tables.
|
||||
|
||||
config NETLINK_DISABLE_NEWADDR
|
||||
bool "Disable RTM_NEWADDR support"
|
||||
default n
|
||||
---help---
|
||||
RTM_NEWADDR is used to set netdev address.
|
||||
|
||||
config NETLINK_DISABLE_DELADDR
|
||||
bool "Disable RTM_DELADDR support"
|
||||
default n
|
||||
---help---
|
||||
RTM_DELADDR is used to delete netdev address.
|
||||
|
||||
config NETLINK_DISABLE_GETADDR
|
||||
bool "Disable RTM_GETADDR support"
|
||||
default n
|
||||
---help---
|
||||
RTM_GETADDR is used to get netdev address.
|
||||
|
||||
config NETLINK_VALIDATE_POLICY
|
||||
bool "Enable netlink message policy verification"
|
||||
default n
|
||||
---help---
|
||||
VALIDATE_POLICY is used to make sure the parameters
|
||||
you pass in are valid.
|
||||
|
||||
endif # NETLINK_ROUTE
|
||||
endmenu # Netlink Protocols
|
||||
endif # NET_NETLINK
|
||||
|
||||
@@ -26,7 +26,7 @@ SOCK_CSRCS += netlink_sockif.c
|
||||
NET_CSRCS += netlink_conn.c netlink_notifier.c
|
||||
|
||||
ifeq ($(CONFIG_NETLINK_ROUTE),y)
|
||||
NET_CSRCS += netlink_route.c
|
||||
NET_CSRCS += netlink_route.c netlink_attr.c
|
||||
endif
|
||||
|
||||
# Include netlink build support
|
||||
|
||||
+261
-1
@@ -44,11 +44,142 @@
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_NETLINK_ROUTE
|
||||
#define netlink_device_notify(dev)
|
||||
# define netlink_device_notify(dev)
|
||||
# define netlink_device_notify_ipaddr(dev, type, domain)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_NETLINK
|
||||
|
||||
/**
|
||||
* nla_for_each_attr - iterate over a stream of attributes
|
||||
* @pos: loop counter, set to current attribute
|
||||
* @head: head of attribute stream
|
||||
* @len: length of attribute stream
|
||||
* @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)))
|
||||
|
||||
/* Always use this macro, this allows later putting the
|
||||
* message into a separate section or such for things
|
||||
* like translation or listing all possible messages.
|
||||
* Currently string formatting is not supported (due
|
||||
* to the lack of an output buffer.)
|
||||
*/
|
||||
|
||||
#define nl_set_err_msg_attr(extack, attr, msg) \
|
||||
do \
|
||||
{ \
|
||||
static const char __msg[] = (msg); \
|
||||
FAR struct netlink_ext_ack *__extack = (extack); \
|
||||
if (__extack) \
|
||||
{ \
|
||||
__extack->_msg = __msg; \
|
||||
__extack->bad_attr = (attr); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
* nla_data - head of payload
|
||||
* @nla: netlink attribute
|
||||
*/
|
||||
|
||||
#define nla_data(nla) ((FAR void *)((FAR char *)(nla) + NLA_HDRLEN))
|
||||
|
||||
/**
|
||||
* nla_len - length of payload
|
||||
* @nla: netlink attribute
|
||||
*/
|
||||
|
||||
#define nla_len(nla) ((nla)->nla_len - NLA_HDRLEN)
|
||||
|
||||
/**
|
||||
* nla_type - attribute type
|
||||
* @nla: netlink attribute
|
||||
*/
|
||||
|
||||
#define nla_type(nla) ((nla)->nla_type & NLA_TYPE_MASK)
|
||||
|
||||
/**
|
||||
* nla_ok - check if the netlink attribute fits into the remaining bytes
|
||||
* @nla: netlink attribute
|
||||
* @remaining: number of bytes remaining in attribute stream
|
||||
*/
|
||||
|
||||
#define nla_ok(nla, remaining) \
|
||||
((remaining) >= sizeof(*(nla)) && \
|
||||
(nla)->nla_len >= sizeof(*(nla)) && \
|
||||
(nla)->nla_len <= (remaining))
|
||||
|
||||
/**
|
||||
* nlmsg_msg_size - length of netlink message not including padding
|
||||
* @payload: length of message payload
|
||||
*/
|
||||
|
||||
#define nlmsg_msg_size(payload) (NLMSG_HDRLEN + (payload))
|
||||
|
||||
/**
|
||||
* nlmsg_len - length of message payload
|
||||
* @nlh: netlink message header
|
||||
*/
|
||||
|
||||
#define nlmsg_len(nlh) ((nlh)->nlmsg_len - NLMSG_HDRLEN)
|
||||
|
||||
/**
|
||||
* nlmsg_attrlen - length of attributes data
|
||||
* @nlh: netlink message header
|
||||
* @hdrlen: length of family specific header
|
||||
*/
|
||||
|
||||
#define nlmsg_attrlen(nlh, hdrlen) (nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen))
|
||||
|
||||
/**
|
||||
* nlmsg_data - head of message payload
|
||||
* @nlh: netlink message header
|
||||
*/
|
||||
|
||||
#define nlmsg_data(nlh) ((FAR void *)((FAR char *)(nlh) + NLMSG_HDRLEN))
|
||||
|
||||
/**
|
||||
* nla_get_in_addr - return payload of IPv4 address attribute
|
||||
* @nla: IPv4 address netlink attribute
|
||||
*/
|
||||
|
||||
#define nla_get_in_addr(nla) (*(FAR uint32_t *)nla_data(nla))
|
||||
|
||||
/**
|
||||
* nlmsg_attrdata - head of attributes data
|
||||
* @nlh: netlink message header
|
||||
* @hdrlen: length of family specific header
|
||||
*/
|
||||
|
||||
#define nlmsg_attrdata(nlh, hdrlen) \
|
||||
((FAR struct nlattr *)((FAR char *)nlmsg_data(nlh) + NLMSG_ALIGN(hdrlen)))
|
||||
|
||||
/**
|
||||
* nlmsg_parse - parse attributes of a netlink message
|
||||
* @nlh: netlink message header
|
||||
* @hdrlen: length of family specific header
|
||||
* @tb: destination array with maxtype+1 elements
|
||||
* @maxtype: maximum attribute type to be expected
|
||||
* @policy: validation policy
|
||||
* @extack: extended ACK report struct
|
||||
*
|
||||
* See nla_parse()
|
||||
*/
|
||||
|
||||
#define nlmsg_parse(nlh, hdrlen, tb, maxtype, policy, extack) \
|
||||
((nlh)->nlmsg_len < nlmsg_msg_size(hdrlen) ? -EINVAL : \
|
||||
nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), \
|
||||
nlmsg_attrlen(nlh, hdrlen), policy, extack))
|
||||
|
||||
/* this can be increased when necessary - don't expose to userland */
|
||||
|
||||
#define NETLINK_MAX_COOKIE_LEN 20
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
@@ -79,6 +210,92 @@ struct netlink_conn_s
|
||||
sq_queue_t resplist; /* Singly linked list of responses */
|
||||
};
|
||||
|
||||
/**
|
||||
* Standard attribute types to specify validation policy
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
NLA_UNSPEC,
|
||||
NLA_U8,
|
||||
NLA_U16,
|
||||
NLA_U32,
|
||||
NLA_U64,
|
||||
NLA_STRING,
|
||||
NLA_FLAG,
|
||||
NLA_MSECS,
|
||||
NLA_NESTED,
|
||||
NLA_NESTED_COMPAT,
|
||||
NLA_NUL_STRING,
|
||||
NLA_BINARY,
|
||||
NLA_S8,
|
||||
NLA_S16,
|
||||
NLA_S32,
|
||||
NLA_S64,
|
||||
NLA_BITFIELD32,
|
||||
NLA_TYPE_MAX = NLA_BITFIELD32,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct netlink_ext_ack - netlink extended ACK report struct
|
||||
* @_msg: message string to report - don't access directly, use
|
||||
* %nl_set_err_msg_attr
|
||||
* @bad_attr: attribute with error
|
||||
* @cookie: cookie data to return to userspace (for success)
|
||||
* @cookie_len: actual cookie data length
|
||||
*/
|
||||
|
||||
struct netlink_ext_ack
|
||||
{
|
||||
FAR const char *_msg;
|
||||
FAR const struct nlattr *bad_attr;
|
||||
uint8_t cookie[NETLINK_MAX_COOKIE_LEN];
|
||||
uint8_t cookie_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nla_policy - attribute validation policy
|
||||
* @type: Type of attribute or NLA_UNSPEC
|
||||
* @len: Type specific length of payload
|
||||
*
|
||||
* Policies are defined as arrays of this struct, the array must be
|
||||
* accessible by attribute type up to the highest identifier to be expected.
|
||||
*
|
||||
* Meaning of `len' field:
|
||||
* NLA_STRING Maximum length of string
|
||||
* NLA_NUL_STRING Maximum length of string (excluding NUL)
|
||||
* NLA_FLAG Unused
|
||||
* NLA_BINARY Maximum length of attribute payload
|
||||
* NLA_NESTED Don't use `len' field -- length verification is
|
||||
* done by checking len of nested header (or empty)
|
||||
* NLA_NESTED_COMPAT Minimum length of structure payload
|
||||
* NLA_U8, NLA_U16,
|
||||
* NLA_U32, NLA_U64,
|
||||
* NLA_S8, NLA_S16,
|
||||
* NLA_S32, NLA_S64,
|
||||
* NLA_MSECS Leaving the length field zero will verify the
|
||||
* given type fits, using it verifies minimum length
|
||||
* just like "All other"
|
||||
* NLA_BITFIELD32 A 32-bit bitmap/bitselector attribute
|
||||
* All other Minimum length of attribute payload
|
||||
*
|
||||
* Example:
|
||||
* static const struct nla_policy my_policy[ATTR_MAX + 1] = {
|
||||
* [ATTR_FOO] = { .type = NLA_U16 },
|
||||
* [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
|
||||
* [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
|
||||
* [ATTR_GOO] = { .type = NLA_BITFIELD32, .validation_data =
|
||||
* &myvalidflags },
|
||||
* };
|
||||
*/
|
||||
|
||||
struct nla_policy
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
FAR void *validation_data;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
@@ -275,6 +492,49 @@ ssize_t netlink_route_sendto(NETLINK_HANDLE handle,
|
||||
****************************************************************************/
|
||||
|
||||
void netlink_device_notify(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netlink_device_notify_ipaddr()
|
||||
*
|
||||
* Description:
|
||||
* Perform the route broadcast for the NETLINK_ROUTE protocol.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void netlink_device_notify_ipaddr(FAR struct net_driver_s *dev,
|
||||
int type, int domain);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nla_next
|
||||
*
|
||||
* Description:
|
||||
* Next netlink attribute in attribute stream.
|
||||
*
|
||||
* Input Parameters:
|
||||
* nla - netlink attribute.
|
||||
* remaining - number of bytes remaining in attribute stream.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns the next netlink attribute in the attribute stream and
|
||||
* decrements remaining by the size of the current attribute.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct nlattr *nla_next(FAR const struct nlattr *nla,
|
||||
FAR int *remaining);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nla_parse
|
||||
*
|
||||
* Description:
|
||||
* Parse the nested netlink attribute.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nla_parse(FAR struct nlattr **tb, int maxtype,
|
||||
FAR const struct nlattr *head,
|
||||
int len, FAR const struct nla_policy *policy,
|
||||
FAR struct netlink_ext_ack *extack);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
/****************************************************************************
|
||||
* net/netlink/netlink_attr.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nuttx/net/netlink.h>
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NETLINK_VALIDATE_POLICY
|
||||
static const uint8_t g_nla_attr_len[NLA_TYPE_MAX + 1] =
|
||||
{
|
||||
0,
|
||||
sizeof(uint8_t),
|
||||
sizeof(uint16_t),
|
||||
sizeof(uint32_t),
|
||||
sizeof(uint64_t),
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
sizeof(int8_t),
|
||||
sizeof(int16_t),
|
||||
sizeof(int32_t),
|
||||
sizeof(int64_t),
|
||||
};
|
||||
|
||||
static const uint8_t g_nla_attr_minlen[NLA_TYPE_MAX + 1] =
|
||||
{
|
||||
0,
|
||||
sizeof(uint8_t),
|
||||
sizeof(uint16_t),
|
||||
sizeof(uint32_t),
|
||||
sizeof(uint64_t),
|
||||
0, 0,
|
||||
sizeof(uint64_t),
|
||||
NLA_HDRLEN,
|
||||
0, 0, 0,
|
||||
sizeof(int8_t),
|
||||
sizeof(int16_t),
|
||||
sizeof(int32_t),
|
||||
sizeof(int64_t),
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int validate_nla_bitfield32(FAR const struct nlattr *nla,
|
||||
FAR uint32_t *valid_flags_mask)
|
||||
{
|
||||
FAR const struct nla_bitfield32 *bf = nla_data(nla);
|
||||
|
||||
if (!valid_flags_mask)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* disallow invalid bit selector */
|
||||
|
||||
if (bf->selector & ~*valid_flags_mask)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* disallow invalid bit values */
|
||||
|
||||
if (bf->value & ~*valid_flags_mask)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* disallow valid bit values that are not selected */
|
||||
|
||||
if (bf->value & ~bf->selector)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_nla(FAR const struct nlattr *nla, int maxtype,
|
||||
FAR const struct nla_policy *policy)
|
||||
{
|
||||
FAR const struct nla_policy *pt;
|
||||
int minlen = 0;
|
||||
int attrlen = nla_len(nla);
|
||||
int type = nla_type(nla);
|
||||
|
||||
if (type <= 0 || type > maxtype)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pt = &policy[type];
|
||||
|
||||
DEBUGASSERT(pt->type <= NLA_TYPE_MAX);
|
||||
|
||||
if (g_nla_attr_len[pt->type] && attrlen != g_nla_attr_len[pt->type])
|
||||
{
|
||||
nwarn("netlink: '%d': attribute type %d has an invalid length.\n",
|
||||
getpid(), type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (pt->type)
|
||||
{
|
||||
case NLA_FLAG:
|
||||
if (attrlen > 0)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case NLA_BITFIELD32:
|
||||
if (attrlen != sizeof(struct nla_bitfield32))
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (validate_nla_bitfield32(nla, pt->validation_data) != 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case NLA_NUL_STRING:
|
||||
if (pt->len)
|
||||
{
|
||||
minlen = MIN(attrlen, pt->len + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
minlen = attrlen;
|
||||
}
|
||||
|
||||
if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
case NLA_STRING:
|
||||
if (attrlen < 1)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (pt->len)
|
||||
{
|
||||
FAR char *buf = nla_data(nla);
|
||||
|
||||
if (buf[attrlen - 1] == '\0')
|
||||
{
|
||||
attrlen--;
|
||||
}
|
||||
|
||||
if (attrlen > pt->len)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NLA_BINARY:
|
||||
if (pt->len && attrlen > pt->len)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case NLA_NESTED_COMPAT:
|
||||
if (attrlen < pt->len)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (attrlen < NLA_ALIGN(pt->len))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
nla = nla_data(nla) + NLA_ALIGN(pt->len);
|
||||
if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case NLA_NESTED:
|
||||
/* a nested attributes is allowed to be empty; if its not,
|
||||
* it must have a size of at least NLA_HDRLEN.
|
||||
*/
|
||||
|
||||
if (attrlen == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (pt->len)
|
||||
{
|
||||
minlen = pt->len;
|
||||
}
|
||||
else if (pt->type != NLA_UNSPEC)
|
||||
{
|
||||
minlen = g_nla_attr_minlen[pt->type];
|
||||
}
|
||||
|
||||
if (attrlen < minlen)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# define validate_nla(nla, maxtype, policy) 0
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nla_next
|
||||
*
|
||||
* Description:
|
||||
* Next netlink attribute in attribute stream.
|
||||
*
|
||||
* Input Parameters:
|
||||
* nla - netlink attribute.
|
||||
* remaining - number of bytes remaining in attribute stream.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns the next netlink attribute in the attribute stream and
|
||||
* decrements remaining by the size of the current attribute.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct nlattr *nla_next(FAR const struct nlattr *nla,
|
||||
FAR int *remaining)
|
||||
{
|
||||
unsigned int totlen = NLA_ALIGN(nla->nla_len);
|
||||
|
||||
*remaining -= totlen;
|
||||
return (FAR struct nlattr *)((FAR char *)nla + totlen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nla_parse
|
||||
*
|
||||
* Description:
|
||||
* Parse the nested netlink attribute.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nla_parse(FAR struct nlattr **tb, int maxtype,
|
||||
FAR const struct nlattr *head,
|
||||
int len, FAR const struct nla_policy *policy,
|
||||
FAR struct netlink_ext_ack *extack)
|
||||
{
|
||||
FAR const struct nlattr *nla;
|
||||
int rem;
|
||||
int err = 0;
|
||||
|
||||
memset(tb, 0, sizeof(FAR struct nlattr *) * (maxtype + 1));
|
||||
|
||||
nla_for_each_attr(nla, head, len, rem)
|
||||
{
|
||||
uint16_t type = nla_type(nla);
|
||||
|
||||
if (type > 0 && type <= maxtype)
|
||||
{
|
||||
err = validate_nla(nla, maxtype, policy);
|
||||
if (err < 0)
|
||||
{
|
||||
nl_set_err_msg_attr(extack, nla,
|
||||
"Attribute failed policy validation");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tb[type] = (FAR struct nlattr *)nla;
|
||||
}
|
||||
}
|
||||
|
||||
if (rem > 0)
|
||||
{
|
||||
nwarn("netlink: %d bytes leftover after parsing attributes in "
|
||||
"pid `%d'.\n", rem, getpid());
|
||||
}
|
||||
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user