attr.c
/*
* (C) 2008-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program 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; either version 2.1 of the License, or
* (at your option) any later version.
*/
#include <limits.h> /* for INT_MAX */
#include <libmnl/libmnl.h>
#include <string.h>
#include <errno.h>
#include "internal.h"
EXPORT_SYMBOL uint16_t mnl_attr_get_type(const struct nlattr *attr)
{
return attr->nla_type & NLA_TYPE_MASK;
}
EXPORT_SYMBOL uint16_t mnl_attr_get_len(const struct nlattr *attr)
{
return attr->nla_len;
}
EXPORT_SYMBOL uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
{
return attr->nla_len - MNL_ATTR_HDRLEN;
}
EXPORT_SYMBOL void *mnl_attr_get_payload(const struct nlattr *attr)
{
return (void *)attr + MNL_ATTR_HDRLEN;
}
EXPORT_SYMBOL bool mnl_attr_ok(const struct nlattr *attr, int len)
{
return len >= (int)sizeof(struct nlattr) &&
attr->nla_len >= sizeof(struct nlattr) &&
(int)attr->nla_len <= len;
}
EXPORT_SYMBOL struct nlattr *mnl_attr_next(const struct nlattr *attr)
{
return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
}
EXPORT_SYMBOL int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
{
if (mnl_attr_get_type(attr) > max) {
errno = EOPNOTSUPP;
return -1;
}
return 1;
}
static int __mnl_attr_validate(const struct nlattr *attr,
enum mnl_attr_data_type type, size_t exp_len)
{
uint16_t attr_len = mnl_attr_get_payload_len(attr);
const char *attr_data = mnl_attr_get_payload(attr);
if (attr_len < exp_len) {
errno = ERANGE;
return -1;
}
switch(type) {
case MNL_TYPE_FLAG:
if (attr_len > 0) {
errno = ERANGE;
return -1;
}
break;
case MNL_TYPE_NUL_STRING:
if (attr_len == 0) {
errno = ERANGE;
return -1;
}
if (attr_data[attr_len-1] != '\0') {
errno = EINVAL;
return -1;
}
break;
case MNL_TYPE_STRING:
if (attr_len == 0) {
errno = ERANGE;
return -1;
}
break;
case MNL_TYPE_NESTED:
/* empty nested attributes are OK. */
if (attr_len == 0)
break;
/* if not empty, they must contain one header, eg. flag */
if (attr_len < MNL_ATTR_HDRLEN) {
errno = ERANGE;
return -1;
}
break;
default:
/* make gcc happy. */
break;
}
if (exp_len && attr_len > exp_len) {
errno = ERANGE;
return -1;
}
return 0;
}
static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
[MNL_TYPE_U8] = sizeof(uint8_t),
[MNL_TYPE_U16] = sizeof(uint16_t),
[MNL_TYPE_U32] = sizeof(uint32_t),
[MNL_TYPE_U64] = sizeof(uint64_t),
[MNL_TYPE_MSECS] = sizeof(uint64_t),
};
EXPORT_SYMBOL int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
{
int exp_len;
if (type >= MNL_TYPE_MAX) {
errno = EINVAL;
return -1;
}
exp_len = mnl_attr_data_type_len[type];
return __mnl_attr_validate(attr, type, exp_len);
}
EXPORT_SYMBOL int mnl_attr_validate2(const struct nlattr *attr,
enum mnl_attr_data_type type,
size_t exp_len)
{
if (type >= MNL_TYPE_MAX) {
errno = EINVAL;
return -1;
}
return __mnl_attr_validate(attr, type, exp_len);
}
EXPORT_SYMBOL int mnl_attr_parse(const struct nlmsghdr *nlh,
unsigned int offset, mnl_attr_cb_t cb,
void *data)
{
int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each(attr, nlh, offset)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
EXPORT_SYMBOL int mnl_attr_parse_nested(const struct nlattr *nested,
mnl_attr_cb_t cb, void *data)
{
int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each_nested(attr, nested)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
EXPORT_SYMBOL int mnl_attr_parse_payload(const void *payload,
size_t payload_len,
mnl_attr_cb_t cb, void *data)
{
int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each_payload(payload, payload_len)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
EXPORT_SYMBOL uint8_t mnl_attr_get_u8(const struct nlattr *attr)
{
return *((uint8_t *)mnl_attr_get_payload(attr));
}
EXPORT_SYMBOL uint16_t mnl_attr_get_u16(const struct nlattr *attr)
{
return *((uint16_t *)mnl_attr_get_payload(attr));
}
EXPORT_SYMBOL uint32_t mnl_attr_get_u32(const struct nlattr *attr)
{
return *((uint32_t *)mnl_attr_get_payload(attr));
}
EXPORT_SYMBOL uint64_t mnl_attr_get_u64(const struct nlattr *attr)
{
uint64_t tmp;
memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
return tmp;
}
EXPORT_SYMBOL const char *mnl_attr_get_str(const struct nlattr *attr)
{
return mnl_attr_get_payload(attr);
}
EXPORT_SYMBOL void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type,
size_t len, const void *data)
{
struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
int pad;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy(mnl_attr_get_payload(attr), data, len);
pad = MNL_ALIGN(len) - len;
if (pad > 0)
memset(mnl_attr_get_payload(attr) + len, 0, pad);
nlh->nlmsg_len += MNL_ALIGN(payload_len);
}
EXPORT_SYMBOL void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type,
uint8_t data)
{
mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
}
EXPORT_SYMBOL void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type,
uint16_t data)
{
mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
}
EXPORT_SYMBOL void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type,
uint32_t data)
{
mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
}
EXPORT_SYMBOL void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type,
uint64_t data)
{
mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
}
EXPORT_SYMBOL void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type,
const char *data)
{
mnl_attr_put(nlh, type, strlen(data), data);
}
EXPORT_SYMBOL void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type,
const char *data)
{
mnl_attr_put(nlh, type, strlen(data)+1, data);
}
EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh,
uint16_t type)
{
struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
/* set start->nla_len in mnl_attr_nest_end() */
start->nla_type = NLA_F_NESTED | type;
nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
return start;
}
EXPORT_SYMBOL bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, size_t len,
const void *data)
{
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
return false;
mnl_attr_put(nlh, type, len, data);
return true;
}
EXPORT_SYMBOL bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint8_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
}
EXPORT_SYMBOL bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint16_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
}
EXPORT_SYMBOL bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint32_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
}
EXPORT_SYMBOL bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint64_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
}
EXPORT_SYMBOL bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, const char *data)
{
return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
}
EXPORT_SYMBOL bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, const char *data)
{
return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
}
EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh,
size_t buflen,
uint16_t type)
{
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
return NULL;
return mnl_attr_nest_start(nlh, type);
}
EXPORT_SYMBOL void mnl_attr_nest_end(struct nlmsghdr *nlh,
struct nlattr *start)
{
start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
}
EXPORT_SYMBOL void mnl_attr_nest_cancel(struct nlmsghdr *nlh,
struct nlattr *start)
{
nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
}
mnl_attr_put_u8
void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data)
Definition attr.c:421
mnl_attr_ok
bool mnl_attr_ok(const struct nlattr *attr, int len)
Definition attr.c:93
mnl_attr_put_strz
void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data)
Definition attr.c:499
mnl_attr_put_check
bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data)
Definition attr.c:540
mnl_attr_get_u8
uint8_t mnl_attr_get_u8(const struct nlattr *attr)
Definition attr.c:332
mnl_attr_put_u16
void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
Definition attr.c:436
mnl_attr_parse_nested
int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb, void *data)
Definition attr.c:282
mnl_attr_put_u8_check
bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data)
Definition attr.c:563
mnl_attr_get_u64
uint64_t mnl_attr_get_u64(const struct nlattr *attr)
Definition attr.c:367
mnl_attr_get_payload
void * mnl_attr_get_payload(const struct nlattr *attr)
Definition attr.c:72
mnl_attr_put_str
void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data)
Definition attr.c:481
mnl_attr_put_strz_check
bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data)
Definition attr.c:669
mnl_attr_put_u16_check
bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data)
Definition attr.c:584
mnl_attr_get_payload_len
uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
Definition attr.c:61
mnl_attr_validate
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
Definition attr.c:207
mnl_attr_put_u64
void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
Definition attr.c:466
mnl_attr_parse
int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data)
Definition attr.c:255
mnl_attr_get_len
uint16_t mnl_attr_get_len(const struct nlattr *attr)
Definition attr.c:50
mnl_attr_type_valid
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
Definition attr.c:127
mnl_attr_get_type
uint16_t mnl_attr_get_type(const struct nlattr *attr)
Definition attr.c:38
mnl_attr_put_u64_check
bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data)
Definition attr.c:626
mnl_attr_nest_start
struct nlattr * mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
Definition attr.c:514
mnl_attr_put_str_check
bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data)
Definition attr.c:647
mnl_attr_validate2
int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t exp_len)
Definition attr.c:229
mnl_attr_get_u32
uint32_t mnl_attr_get_u32(const struct nlattr *attr)
Definition attr.c:354
mnl_attr_get_str
const char * mnl_attr_get_str(const struct nlattr *attr)
Definition attr.c:380
mnl_attr_put_u32
void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
Definition attr.c:451
mnl_attr_next
struct nlattr * mnl_attr_next(const struct nlattr *attr)
Definition attr.c:108
mnl_attr_put
void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
Definition attr.c:395
mnl_attr_nest_end
void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
Definition attr.c:701
mnl_attr_get_u16
uint16_t mnl_attr_get_u16(const struct nlattr *attr)
Definition attr.c:343
mnl_attr_nest_cancel
void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start)
Definition attr.c:714
mnl_attr_parse_payload
int mnl_attr_parse_payload(const void *payload, size_t payload_len, mnl_attr_cb_t cb, void *data)
Definition attr.c:313
mnl_attr_nest_start_check
struct nlattr * mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type)
Definition attr.c:685
mnl_attr_put_u32_check
bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data)
Definition attr.c:605
mnl_nlmsg_get_payload_tail
void * mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
Definition nlmsg.c:187