summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/attr.c188
1 files changed, 141 insertions, 47 deletions
diff --git a/src/attr.c b/src/attr.c
index 0c09aef..cc4a774 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -9,6 +9,8 @@
#include <libmnl/libmnl.h>
#include <string.h>
+#include <values.h> /* for INT_MAX */
+#include <errno.h>
/*
* Netlink Type-Length-Value (TLV) attribute:
@@ -94,80 +96,172 @@ struct nlattr *mnl_attr_next(const struct nlattr *attr, int *len)
}
/**
- * mnl_attr_parse_at_offset - returns an array of attributes from offset
- * @nlh: pointer to netlink message
- * @offset: offset to start parse from
- * @tb: array of pointers to the attribute found
- * @max: size of the attribute array
- *
- * This functions zeroes the array of pointers. Thus, you don't need to
- * initialize this array.
+ * mnl_attr_type_invalid - check if the attribute type is valid
+ * @attr: pointer to attribute to be checked
+ * @max: maximum attribute type
*
- * This function returns an array of pointers to the attributes that has been
- * found in a netlink payload. This function return 0 on sucess, and >0 to
- * indicate the number of bytes the remaining bytes.
+ * This function allows to check if the attribute type is higher than the
+ * maximum supported type. If the attribute type is invalid, this function
+ * returns -1 and errno is explicitly set.
*/
-int mnl_attr_parse_at_offset(const struct nlmsghdr *nlh, int offset,
- struct nlattr *tb[], int max)
+int mnl_attr_type_invalid(const struct nlattr *attr, int max)
{
- struct nlattr *attr = mnl_nlmsg_get_data_offset(nlh, offset);
- int len = mnl_nlmsg_get_len(nlh);
+ if (mnl_attr_get_type(attr) > max) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
- memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
+static int __mnl_attr_validate(const struct nlattr *attr,
+ enum mnl_attr_data_type type, int exp_len)
+{
+ uint16_t attr_len = mnl_attr_get_payload_len(attr);
+ char *attr_data = mnl_attr_get_data(attr);
- while (mnl_attr_ok(attr, len)) {
- if (mnl_attr_get_type(attr) <= max)
- tb[mnl_attr_get_type(attr)] = attr;
- attr = mnl_attr_next(attr, &len);
+ if (attr_len < exp_len) {
+ errno = ERANGE;
+ return -1;
}
- return len;
+ 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;
}
/**
- * mnl_attr_parse - returns an array with the attributes in the netlink message
- * @nlh: pointer to netlink message header
- * @tb: array of pointers to the attribute found
- * @max: size of the attribute array
+ * mnl_attr_validate - validate netlink attribute (simplified version)
+ * @attr: pointer to netlink attribute that we want to validate
+ * @type: data type (see enum mnl_attr_data_type)
*
- * This functions zeroes the array of pointers. Thus, you don't need to
- * initialize this array.
+ * The validation is based on the data type. This functions returns -1 in
+ * case of error and errno is explicitly set.
+ */
+static 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),
+};
+
+int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
+{
+ int exp_len;
+
+ if (type < 0 || type >= MNL_TYPE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ exp_len = mnl_attr_data_type_len[type];
+ return __mnl_attr_validate(attr, type, exp_len);
+}
+
+/**
+ * mnl_attr_validate2 - validate netlink attribute (extended version)
+ * @attr: pointer to netlink attribute that we want to validate
+ * @type: attribute type (see enum mnl_attr_data_type)
+ * @exp_len: expected attribute data size
*
- * This function returns an array of pointers to the attributes that has been
- * found in a netlink payload. This function return 0 on sucess, and >0 to
- * indicate the number of bytes the remaining bytes.
+ * This function allows to perform a more accurate validation for attributes
+ * whose size is variable. If the size of the attribute is not what we expect,
+ * this functions returns -1 and errno is explicitly set.
*/
-int mnl_attr_parse(const struct nlmsghdr *nlh, struct nlattr *tb[], int max)
+int mnl_attr_validate2(const struct nlattr *attr,
+ enum mnl_attr_data_type type, int exp_len)
{
- return mnl_attr_parse_at_offset(nlh, 0, tb, max);
+ if (type < 0 || type >= MNL_TYPE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ return __mnl_attr_validate(attr, type, exp_len);
}
/**
- * mnl_attr_parse_nested - returns an array with the attributes from nested
- * @nested: pointer to netlink attribute that contains a nest
- * @tb: array of pointers to the attribute found
- * @max: size of the attribute array
+ * mnl_attr_parse - parse attributes
+ * @nlh: pointer to netlink message
+ * @offset: offset to start parsing from
+ * @cb: callback function
+ * @data: pointer to data passed to the callback function
*
- * This functions zeroes the array of pointers. Thus, you don't need to
- * initialize this array.
+ * This function propagates the return value of the callback that can be
+ * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
+ */
+int mnl_attr_parse(const struct nlmsghdr *nlh, int offset,
+ mnl_attr_cb_t cb, void *data)
+{
+ int ret = MNL_CB_OK;
+ struct nlattr *attr = mnl_nlmsg_get_data_offset(nlh, offset);
+ int len = mnl_nlmsg_get_len(nlh);
+
+ while (mnl_attr_ok(attr, len)) {
+ if (cb && (ret = cb(attr, data)) <= MNL_CB_STOP)
+ return ret;
+ attr = mnl_attr_next(attr, &len);
+ }
+ return ret;
+}
+
+/**
+ * mnl_attr_parse_nested - parse attributes inside a nest
+ * @nested: pointer to netlink attribute that contains a nest
+ * @offset: offset to start parsing from
+ * @cb: callback function
+ * @data: pointer to data passed to the callback function
*
- * This function returns an array of pointers to the attributes that has been
- * found in a netlink payload. This function return 0 on sucess, and >0 to
- * indicate the number of bytes the remaining bytes.
+ * This function propagates the return value of the callback that can be
+ * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
*/
int mnl_attr_parse_nested(const struct nlattr *nested,
- struct nlattr *tb[], int max)
+ mnl_attr_cb_t cb, void *data)
{
+ int ret = MNL_CB_OK;
struct nlattr *attr = mnl_attr_get_data(nested);
int len = mnl_attr_get_payload_len(nested);
- memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
-
while (mnl_attr_ok(attr, len)) {
- if (mnl_attr_get_type(attr) <= max)
- tb[mnl_attr_get_type(attr)] = attr;
+ if (cb && (ret = cb(attr, data)) <= MNL_CB_STOP)
+ return ret;
attr = mnl_attr_next(attr, &len);
}
- return len;
+ return ret;
}
/**